1 /* $NetBSD: chfs_vnode.c,v 1.8 2012/10/19 12:44:39 ttoth 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 vput(dvp); 261 return error; 262 } 263 264 /* update parent's vnode information and write it to the flash */ 265 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE); 266 chfs_update(dvp, NULL, NULL, UPDATE_WAIT); 267 268 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL); 269 if (error) { 270 mutex_exit(&chmp->chm_lock_mountfields); 271 vput(vp); 272 vput(dvp); 273 return error; 274 } 275 vput(dvp); 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 *vpp = vp; 305 return (0); 306 } 307 308 /* chfs_set_vnode_size - updates size of vnode and also inode */ 309 void 310 chfs_set_vnode_size(struct vnode *vp, size_t size) 311 { 312 struct chfs_inode *ip; 313 314 KASSERT(vp != NULL); 315 316 ip = VTOI(vp); 317 KASSERT(ip != NULL); 318 319 ip->size = size; 320 vp->v_size = vp->v_writesize = size; 321 return; 322 } 323 324 /* 325 * chfs_change_size_free - updates free size 326 * "change" parameter is positive if we have to increase the size 327 * and negative if we have to decrease it 328 */ 329 void 330 chfs_change_size_free(struct chfs_mount *chmp, 331 struct chfs_eraseblock *cheb, int change) 332 { 333 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 334 KASSERT((int)(chmp->chm_free_size + change) >= 0); 335 KASSERT((int)(cheb->free_size + change) >= 0); 336 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size); 337 chmp->chm_free_size += change; 338 cheb->free_size += change; 339 return; 340 } 341 342 /* 343 * chfs_change_size_dirty - updates dirty size 344 * "change" parameter is positive if we have to increase the size 345 * and negative if we have to decrease it 346 */ 347 void 348 chfs_change_size_dirty(struct chfs_mount *chmp, 349 struct chfs_eraseblock *cheb, int change) 350 { 351 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 352 KASSERT((int)(chmp->chm_dirty_size + change) >= 0); 353 KASSERT((int)(cheb->dirty_size + change) >= 0); 354 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size); 355 chmp->chm_dirty_size += change; 356 cheb->dirty_size += change; 357 return; 358 } 359 360 /* 361 * chfs_change_size_unchecked - updates unchecked size 362 * "change" parameter is positive if we have to increase the size 363 * and negative if we have to decrease it 364 */ 365 void 366 chfs_change_size_unchecked(struct chfs_mount *chmp, 367 struct chfs_eraseblock *cheb, int change) 368 { 369 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 370 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0); 371 KASSERT((int)(cheb->unchecked_size + change) >= 0); 372 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size); 373 chmp->chm_unchecked_size += change; 374 cheb->unchecked_size += change; 375 return; 376 } 377 378 /* 379 * chfs_change_size_used - updates used size 380 * "change" parameter is positive if we have to increase the size 381 * and negative if we have to decrease it 382 */ 383 void 384 chfs_change_size_used(struct chfs_mount *chmp, 385 struct chfs_eraseblock *cheb, int change) 386 { 387 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 388 KASSERT((int)(chmp->chm_used_size + change) >= 0); 389 KASSERT((int)(cheb->used_size + change) >= 0); 390 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size); 391 chmp->chm_used_size += change; 392 cheb->used_size += change; 393 return; 394 } 395 396 /* 397 * chfs_change_size_wasted - updates wasted size 398 * "change" parameter is positive if we have to increase the size 399 * and negative if we have to decrease it 400 */ 401 void 402 chfs_change_size_wasted(struct chfs_mount *chmp, 403 struct chfs_eraseblock *cheb, int change) 404 { 405 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 406 KASSERT((int)(chmp->chm_wasted_size + change) >= 0); 407 KASSERT((int)(cheb->wasted_size + change) >= 0); 408 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size); 409 chmp->chm_wasted_size += change; 410 cheb->wasted_size += change; 411 return; 412 } 413 414