1 /* $NetBSD: chfs_vnode.c,v 1.14 2015/01/11 17:29:57 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu> 7 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org> 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by the Department of Software Engineering, University of Szeged, Hungary 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "chfs.h" 36 #include "chfs_inode.h" 37 #include <sys/kauth.h> 38 #include <sys/namei.h> 39 #include <sys/uio.h> 40 #include <sys/buf.h> 41 42 #include <miscfs/genfs/genfs.h> 43 44 /* chfs_vnode_lookup - lookup for a vnode */ 45 static bool 46 chfs_vnode_lookup_selector(void *ctx, struct vnode *vp) 47 { 48 ino_t *ino = ctx; 49 50 return (VTOI(vp) != NULL && VTOI(vp)->ino == *ino); 51 } 52 struct vnode * 53 chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno) 54 { 55 struct vnode_iterator *marker; 56 struct vnode *vp; 57 58 vfs_vnode_iterator_init(chmp->chm_fsmp, &marker); 59 vp = vfs_vnode_iterator_next(marker, chfs_vnode_lookup_selector, &vno); 60 vfs_vnode_iterator_destroy(marker); 61 62 return vp; 63 } 64 65 /* chfs_readvnode - reads a vnode from the flash and setups its inode */ 66 int 67 chfs_readvnode(struct mount *mp, ino_t ino, struct vnode **vpp) 68 { 69 struct ufsmount* ump = VFSTOUFS(mp); 70 struct chfs_mount *chmp = ump->um_chfs; 71 struct chfs_vnode_cache *chvc; 72 struct chfs_flash_vnode *chfvn; 73 struct chfs_inode *ip; 74 int err; 75 char* buf; 76 size_t retlen, len; 77 struct vnode* vp = NULL; 78 dbg("readvnode | ino: %llu\n", (unsigned long long)ino); 79 80 len = sizeof(struct chfs_flash_vnode); 81 82 KASSERT(vpp != NULL); 83 84 if (vpp != NULL) { 85 vp = *vpp; 86 } 87 88 ip = VTOI(vp); 89 chvc = ip->chvc; 90 91 /* root node is in-memory only */ 92 if (chvc && ino != CHFS_ROOTINO) { 93 dbg("offset: %" PRIu32 ", lnr: %d\n", 94 CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr); 95 96 KASSERT((void *)chvc != (void *)chvc->v); 97 98 /* reading */ 99 buf = kmem_alloc(len, KM_SLEEP); 100 err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf, 101 CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen); 102 if (err) { 103 kmem_free(buf, len); 104 return err; 105 } 106 if (retlen != len) { 107 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 108 len, retlen); 109 kmem_free(buf, len); 110 return EIO; 111 } 112 chfvn = (struct chfs_flash_vnode*)buf; 113 114 /* setup inode fields */ 115 chfs_set_vnode_size(vp, chfvn->dn_size); 116 ip->mode = chfvn->mode; 117 ip->ch_type = IFTOCHT(ip->mode); 118 vp->v_type = CHTTOVT(ip->ch_type); 119 ip->version = chfvn->version; 120 ip->uid = chfvn->uid; 121 ip->gid = chfvn->gid; 122 ip->atime = chfvn->atime; 123 ip->mtime = chfvn->mtime; 124 ip->ctime = chfvn->ctime; 125 126 kmem_free(buf, len); 127 } 128 129 130 *vpp = vp; 131 return 0; 132 } 133 134 /* 135 * chfs_readddirent - 136 * reads a directory entry from flash and adds it to its inode 137 */ 138 int 139 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir) 140 { 141 struct ufsmount *ump = VFSTOUFS(mp); 142 struct chfs_mount *chmp = ump->um_chfs; 143 struct chfs_flash_dirent_node chfdn; 144 struct chfs_dirent *fd; 145 size_t len = sizeof(struct chfs_flash_dirent_node); 146 size_t retlen; 147 int err = 0; 148 149 /* read flash_dirent_node */ 150 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn, 151 CHFS_GET_OFS(chnr->nref_offset), len, &retlen); 152 if (err) { 153 return err; 154 } 155 if (retlen != len) { 156 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 157 retlen, len); 158 return EIO; 159 } 160 161 /* set fields of dirent */ 162 fd = chfs_alloc_dirent(chfdn.nsize + 1); 163 fd->version = chfdn.version; 164 fd->vno = chfdn.vno; 165 fd->type = chfdn.dtype; 166 fd->nsize = chfdn.nsize; 167 168 /* read the name of the dirent */ 169 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name, 170 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen); 171 if (err) { 172 return err; 173 } 174 175 if (retlen != chfdn.nsize) { 176 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 177 len, retlen); 178 return EIO; 179 } 180 181 fd->name[fd->nsize] = 0; 182 fd->nref = chnr; 183 184 /* add to inode */ 185 chfs_add_fd_to_inode(chmp, pdir, fd); 186 return 0; 187 } 188 189 /* chfs_makeinode - makes a new file and initializes its structures */ 190 int 191 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, 192 struct componentname *cnp, enum vtype type) 193 { 194 struct chfs_inode *ip, *pdir; 195 struct vnode *vp; 196 struct ufsmount* ump = VFSTOUFS(dvp->v_mount); 197 struct chfs_mount* chmp = ump->um_chfs; 198 struct chfs_vnode_cache* chvc; 199 int error; 200 ino_t vno; 201 struct chfs_dirent *nfd; 202 203 dbg("makeinode\n"); 204 pdir = VTOI(dvp); 205 206 *vpp = NULL; 207 208 /* number of vnode will be the new maximum */ 209 vno = ++(chmp->chm_max_vno); 210 211 error = VFS_VGET(dvp->v_mount, vno, &vp); 212 if (error) 213 return (error); 214 215 /* setup vnode cache */ 216 mutex_enter(&chmp->chm_lock_vnocache); 217 chvc = chfs_vnode_cache_get(chmp, vno); 218 219 chvc->pvno = pdir->ino; 220 chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP); 221 *(chvc->vno_version) = 1; 222 if (type != VDIR) 223 chvc->nlink = 1; 224 else 225 chvc->nlink = 2; 226 chvc->state = VNO_STATE_CHECKEDABSENT; 227 mutex_exit(&chmp->chm_lock_vnocache); 228 229 /* setup inode */ 230 ip = VTOI(vp); 231 ip->ino = vno; 232 233 if (type == VDIR) 234 chfs_set_vnode_size(vp, 512); 235 else 236 chfs_set_vnode_size(vp, 0); 237 238 ip->uid = kauth_cred_geteuid(cnp->cn_cred); 239 ip->gid = kauth_cred_getegid(cnp->cn_cred); 240 ip->version = 1; 241 ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE); 242 243 ip->chvc = chvc; 244 ip->target = NULL; 245 246 ip->mode = mode; 247 vp->v_type = type; /* Rest init'd in chfs_loadvnode(). */ 248 ip->ch_type = VTTOCHT(vp->v_type); 249 250 /* authorize setting SGID if needed */ 251 if (ip->mode & ISGID) { 252 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, 253 vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid, 254 ip->gid, mode)); 255 if (error) 256 ip->mode &= ~ISGID; 257 } 258 259 /* write vnode information to the flash */ 260 chfs_update(vp, NULL, NULL, UPDATE_WAIT); 261 262 mutex_enter(&chmp->chm_lock_mountfields); 263 264 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL); 265 if (error) { 266 mutex_exit(&chmp->chm_lock_mountfields); 267 vput(vp); 268 return error; 269 } 270 271 /* update parent's vnode information and write it to the flash */ 272 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE); 273 chfs_update(dvp, NULL, NULL, UPDATE_WAIT); 274 275 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL); 276 if (error) { 277 mutex_exit(&chmp->chm_lock_mountfields); 278 vput(vp); 279 return error; 280 } 281 282 /* setup directory entry */ 283 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1); 284 nfd->vno = ip->ino; 285 nfd->version = (++pdir->chvc->highest_version); 286 nfd->type = ip->ch_type; 287 nfd->nsize = cnp->cn_namelen; 288 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen); 289 nfd->name[nfd->nsize] = 0; 290 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT); 291 292 /* write out */ 293 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL); 294 if (error) { 295 mutex_exit(&chmp->chm_lock_mountfields); 296 vput(vp); 297 return error; 298 } 299 300 //TODO set parent's dir times 301 302 /* add dirent to parent */ 303 chfs_add_fd_to_inode(chmp, pdir, nfd); 304 305 pdir->chvc->nlink++; 306 307 mutex_exit(&chmp->chm_lock_mountfields); 308 309 VOP_UNLOCK(vp); 310 *vpp = vp; 311 return (0); 312 } 313 314 /* chfs_set_vnode_size - updates size of vnode and also inode */ 315 void 316 chfs_set_vnode_size(struct vnode *vp, size_t size) 317 { 318 struct chfs_inode *ip; 319 320 KASSERT(vp != NULL); 321 322 ip = VTOI(vp); 323 KASSERT(ip != NULL); 324 325 ip->size = size; 326 vp->v_size = vp->v_writesize = size; 327 return; 328 } 329 330 /* 331 * chfs_change_size_free - updates free size 332 * "change" parameter is positive if we have to increase the size 333 * and negative if we have to decrease it 334 */ 335 void 336 chfs_change_size_free(struct chfs_mount *chmp, 337 struct chfs_eraseblock *cheb, int change) 338 { 339 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 340 KASSERT((int)(chmp->chm_free_size + change) >= 0); 341 KASSERT((int)(cheb->free_size + change) >= 0); 342 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size); 343 chmp->chm_free_size += change; 344 cheb->free_size += change; 345 return; 346 } 347 348 /* 349 * chfs_change_size_dirty - updates dirty size 350 * "change" parameter is positive if we have to increase the size 351 * and negative if we have to decrease it 352 */ 353 void 354 chfs_change_size_dirty(struct chfs_mount *chmp, 355 struct chfs_eraseblock *cheb, int change) 356 { 357 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 358 KASSERT((int)(chmp->chm_dirty_size + change) >= 0); 359 KASSERT((int)(cheb->dirty_size + change) >= 0); 360 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size); 361 chmp->chm_dirty_size += change; 362 cheb->dirty_size += change; 363 return; 364 } 365 366 /* 367 * chfs_change_size_unchecked - updates unchecked size 368 * "change" parameter is positive if we have to increase the size 369 * and negative if we have to decrease it 370 */ 371 void 372 chfs_change_size_unchecked(struct chfs_mount *chmp, 373 struct chfs_eraseblock *cheb, int change) 374 { 375 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 376 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0); 377 KASSERT((int)(cheb->unchecked_size + change) >= 0); 378 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size); 379 chmp->chm_unchecked_size += change; 380 cheb->unchecked_size += change; 381 return; 382 } 383 384 /* 385 * chfs_change_size_used - updates used size 386 * "change" parameter is positive if we have to increase the size 387 * and negative if we have to decrease it 388 */ 389 void 390 chfs_change_size_used(struct chfs_mount *chmp, 391 struct chfs_eraseblock *cheb, int change) 392 { 393 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 394 KASSERT((int)(chmp->chm_used_size + change) >= 0); 395 KASSERT((int)(cheb->used_size + change) >= 0); 396 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size); 397 chmp->chm_used_size += change; 398 cheb->used_size += change; 399 return; 400 } 401 402 /* 403 * chfs_change_size_wasted - updates wasted size 404 * "change" parameter is positive if we have to increase the size 405 * and negative if we have to decrease it 406 */ 407 void 408 chfs_change_size_wasted(struct chfs_mount *chmp, 409 struct chfs_eraseblock *cheb, int change) 410 { 411 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 412 KASSERT((int)(chmp->chm_wasted_size + change) >= 0); 413 KASSERT((int)(cheb->wasted_size + change) >= 0); 414 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size); 415 chmp->chm_wasted_size += change; 416 cheb->wasted_size += change; 417 return; 418 } 419 420