1 /* $NetBSD: chfs_vnode.c,v 1.11 2014/09/01 16:33:20 he 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/malloc.h> 38 #include <sys/kauth.h> 39 #include <sys/namei.h> 40 #include <sys/uio.h> 41 #include <sys/buf.h> 42 43 #include <miscfs/genfs/genfs.h> 44 45 /* chfs_vnode_lookup - lookup for a vnode */ 46 struct vnode * 47 chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno) 48 { 49 struct vnode *vp; 50 struct chfs_inode *ip; 51 52 TAILQ_FOREACH(vp, &chmp->chm_fsmp->mnt_vnodelist, v_mntvnodes) { 53 ip = VTOI(vp); 54 if (ip && ip->ino == vno) 55 return vp; 56 } 57 return NULL; 58 } 59 60 /* chfs_readvnode - reads a vnode from the flash and setups its inode */ 61 int 62 chfs_readvnode(struct mount *mp, ino_t ino, struct vnode **vpp) 63 { 64 struct ufsmount* ump = VFSTOUFS(mp); 65 struct chfs_mount *chmp = ump->um_chfs; 66 struct chfs_vnode_cache *chvc; 67 struct chfs_flash_vnode *chfvn; 68 struct chfs_inode *ip; 69 int err; 70 char* buf; 71 size_t retlen, len; 72 struct vnode* vp = NULL; 73 dbg("readvnode | ino: %llu\n", (unsigned long long)ino); 74 75 len = sizeof(struct chfs_flash_vnode); 76 77 KASSERT(vpp != NULL); 78 79 if (vpp != NULL) { 80 vp = *vpp; 81 } 82 83 ip = VTOI(vp); 84 chvc = ip->chvc; 85 86 /* root node is in-memory only */ 87 if (chvc && ino != CHFS_ROOTINO) { 88 dbg("offset: %" PRIu32 ", lnr: %d\n", 89 CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr); 90 91 KASSERT((void *)chvc != (void *)chvc->v); 92 93 /* reading */ 94 buf = kmem_alloc(len, KM_SLEEP); 95 err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf, 96 CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen); 97 if (err) { 98 kmem_free(buf, len); 99 return err; 100 } 101 if (retlen != len) { 102 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 103 len, retlen); 104 kmem_free(buf, len); 105 return EIO; 106 } 107 chfvn = (struct chfs_flash_vnode*)buf; 108 109 /* setup inode fields */ 110 chfs_set_vnode_size(vp, chfvn->dn_size); 111 ip->mode = chfvn->mode; 112 ip->ch_type = IFTOCHT(ip->mode); 113 vp->v_type = CHTTOVT(ip->ch_type); 114 ip->version = chfvn->version; 115 ip->uid = chfvn->uid; 116 ip->gid = chfvn->gid; 117 ip->atime = chfvn->atime; 118 ip->mtime = chfvn->mtime; 119 ip->ctime = chfvn->ctime; 120 121 kmem_free(buf, len); 122 } 123 124 125 *vpp = vp; 126 return 0; 127 } 128 129 /* 130 * chfs_readddirent - 131 * reads a directory entry from flash and adds it to its inode 132 */ 133 int 134 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir) 135 { 136 struct ufsmount *ump = VFSTOUFS(mp); 137 struct chfs_mount *chmp = ump->um_chfs; 138 struct chfs_flash_dirent_node chfdn; 139 struct chfs_dirent *fd; 140 size_t len = sizeof(struct chfs_flash_dirent_node); 141 size_t retlen; 142 int err = 0; 143 144 /* read flash_dirent_node */ 145 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn, 146 CHFS_GET_OFS(chnr->nref_offset), len, &retlen); 147 if (err) { 148 return err; 149 } 150 if (retlen != len) { 151 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 152 retlen, len); 153 return EIO; 154 } 155 156 /* set fields of dirent */ 157 fd = chfs_alloc_dirent(chfdn.nsize + 1); 158 fd->version = chfdn.version; 159 fd->vno = chfdn.vno; 160 fd->type = chfdn.dtype; 161 fd->nsize = chfdn.nsize; 162 163 /* read the name of the dirent */ 164 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name, 165 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen); 166 if (err) { 167 return err; 168 } 169 170 if (retlen != chfdn.nsize) { 171 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 172 len, retlen); 173 return EIO; 174 } 175 176 fd->name[fd->nsize] = 0; 177 fd->nref = chnr; 178 179 /* add to inode */ 180 chfs_add_fd_to_inode(chmp, pdir, fd); 181 return 0; 182 } 183 184 /* chfs_makeinode - makes a new file and initializes its structures */ 185 int 186 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, 187 struct componentname *cnp, enum vtype type) 188 { 189 struct chfs_inode *ip, *pdir; 190 struct vnode *vp; 191 struct ufsmount* ump = VFSTOUFS(dvp->v_mount); 192 struct chfs_mount* chmp = ump->um_chfs; 193 struct chfs_vnode_cache* chvc; 194 int error; 195 ino_t vno; 196 struct chfs_dirent *nfd; 197 198 dbg("makeinode\n"); 199 pdir = VTOI(dvp); 200 201 *vpp = NULL; 202 203 /* number of vnode will be the new maximum */ 204 vno = ++(chmp->chm_max_vno); 205 206 error = VFS_VGET(dvp->v_mount, vno, &vp); 207 if (error) 208 return (error); 209 210 /* setup vnode cache */ 211 mutex_enter(&chmp->chm_lock_vnocache); 212 chvc = chfs_vnode_cache_get(chmp, vno); 213 214 chvc->pvno = pdir->ino; 215 chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP); 216 *(chvc->vno_version) = 1; 217 if (type != VDIR) 218 chvc->nlink = 1; 219 else 220 chvc->nlink = 2; 221 chvc->state = VNO_STATE_CHECKEDABSENT; 222 mutex_exit(&chmp->chm_lock_vnocache); 223 224 /* setup inode */ 225 ip = VTOI(vp); 226 ip->ino = vno; 227 228 if (type == VDIR) 229 chfs_set_vnode_size(vp, 512); 230 else 231 chfs_set_vnode_size(vp, 0); 232 233 ip->uid = kauth_cred_geteuid(cnp->cn_cred); 234 ip->gid = kauth_cred_getegid(cnp->cn_cred); 235 ip->version = 1; 236 ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE); 237 238 ip->chvc = chvc; 239 ip->target = NULL; 240 241 ip->mode = mode; 242 vp->v_type = type; /* Rest init'd in getnewvnode(). */ 243 ip->ch_type = VTTOCHT(vp->v_type); 244 245 /* authorize setting SGID if needed */ 246 if (ip->mode & ISGID) { 247 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, 248 vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid, 249 ip->gid, mode)); 250 if (error) 251 ip->mode &= ~ISGID; 252 } 253 254 /* write vnode information to the flash */ 255 chfs_update(vp, NULL, NULL, UPDATE_WAIT); 256 257 mutex_enter(&chmp->chm_lock_mountfields); 258 259 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL); 260 if (error) { 261 mutex_exit(&chmp->chm_lock_mountfields); 262 vput(vp); 263 return error; 264 } 265 266 /* update parent's vnode information and write it to the flash */ 267 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE); 268 chfs_update(dvp, NULL, NULL, UPDATE_WAIT); 269 270 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL); 271 if (error) { 272 mutex_exit(&chmp->chm_lock_mountfields); 273 vput(vp); 274 return error; 275 } 276 277 /* setup directory entry */ 278 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1); 279 nfd->vno = ip->ino; 280 nfd->version = (++pdir->chvc->highest_version); 281 nfd->type = ip->ch_type; 282 nfd->nsize = cnp->cn_namelen; 283 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen); 284 nfd->name[nfd->nsize] = 0; 285 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT); 286 287 /* write out */ 288 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL); 289 if (error) { 290 mutex_exit(&chmp->chm_lock_mountfields); 291 vput(vp); 292 return error; 293 } 294 295 //TODO set parent's dir times 296 297 /* add dirent to parent */ 298 chfs_add_fd_to_inode(chmp, pdir, nfd); 299 300 pdir->chvc->nlink++; 301 302 mutex_exit(&chmp->chm_lock_mountfields); 303 304 VOP_UNLOCK(vp); 305 *vpp = vp; 306 return (0); 307 } 308 309 /* chfs_set_vnode_size - updates size of vnode and also inode */ 310 void 311 chfs_set_vnode_size(struct vnode *vp, size_t size) 312 { 313 struct chfs_inode *ip; 314 315 KASSERT(vp != NULL); 316 317 ip = VTOI(vp); 318 KASSERT(ip != NULL); 319 320 ip->size = size; 321 vp->v_size = vp->v_writesize = size; 322 return; 323 } 324 325 /* 326 * chfs_change_size_free - updates free size 327 * "change" parameter is positive if we have to increase the size 328 * and negative if we have to decrease it 329 */ 330 void 331 chfs_change_size_free(struct chfs_mount *chmp, 332 struct chfs_eraseblock *cheb, int change) 333 { 334 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 335 KASSERT((int)(chmp->chm_free_size + change) >= 0); 336 KASSERT((int)(cheb->free_size + change) >= 0); 337 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size); 338 chmp->chm_free_size += change; 339 cheb->free_size += change; 340 return; 341 } 342 343 /* 344 * chfs_change_size_dirty - updates dirty size 345 * "change" parameter is positive if we have to increase the size 346 * and negative if we have to decrease it 347 */ 348 void 349 chfs_change_size_dirty(struct chfs_mount *chmp, 350 struct chfs_eraseblock *cheb, int change) 351 { 352 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 353 KASSERT((int)(chmp->chm_dirty_size + change) >= 0); 354 KASSERT((int)(cheb->dirty_size + change) >= 0); 355 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size); 356 chmp->chm_dirty_size += change; 357 cheb->dirty_size += change; 358 return; 359 } 360 361 /* 362 * chfs_change_size_unchecked - updates unchecked size 363 * "change" parameter is positive if we have to increase the size 364 * and negative if we have to decrease it 365 */ 366 void 367 chfs_change_size_unchecked(struct chfs_mount *chmp, 368 struct chfs_eraseblock *cheb, int change) 369 { 370 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 371 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0); 372 KASSERT((int)(cheb->unchecked_size + change) >= 0); 373 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size); 374 chmp->chm_unchecked_size += change; 375 cheb->unchecked_size += change; 376 return; 377 } 378 379 /* 380 * chfs_change_size_used - updates used size 381 * "change" parameter is positive if we have to increase the size 382 * and negative if we have to decrease it 383 */ 384 void 385 chfs_change_size_used(struct chfs_mount *chmp, 386 struct chfs_eraseblock *cheb, int change) 387 { 388 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 389 KASSERT((int)(chmp->chm_used_size + change) >= 0); 390 KASSERT((int)(cheb->used_size + change) >= 0); 391 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size); 392 chmp->chm_used_size += change; 393 cheb->used_size += change; 394 return; 395 } 396 397 /* 398 * chfs_change_size_wasted - updates wasted size 399 * "change" parameter is positive if we have to increase the size 400 * and negative if we have to decrease it 401 */ 402 void 403 chfs_change_size_wasted(struct chfs_mount *chmp, 404 struct chfs_eraseblock *cheb, int change) 405 { 406 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 407 KASSERT((int)(chmp->chm_wasted_size + change) >= 0); 408 KASSERT((int)(cheb->wasted_size + change) >= 0); 409 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size); 410 chmp->chm_wasted_size += change; 411 cheb->wasted_size += change; 412 return; 413 } 414 415