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