1 /* $NetBSD: chfs_vnode.c,v 1.3 2012/03/13 18:41:03 elad 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 struct vnode * 46 chfs_vnode_lookup(struct chfs_mount *chmp, ino_t vno) 47 { 48 struct vnode *vp; 49 struct chfs_inode *ip; 50 51 TAILQ_FOREACH(vp, &chmp->chm_fsmp->mnt_vnodelist, v_mntvnodes) { 52 ip = VTOI(vp); 53 if (ip && ip->ino == vno) 54 return vp; 55 } 56 return NULL; 57 } 58 59 int 60 chfs_readvnode(struct mount* mp, ino_t ino, struct vnode** vpp) 61 { 62 struct ufsmount* ump = VFSTOUFS(mp); 63 struct chfs_mount *chmp = ump->um_chfs; 64 struct chfs_vnode_cache *chvc; 65 struct chfs_flash_vnode *chfvn; 66 struct chfs_inode *ip; 67 int err; 68 char* buf; 69 size_t retlen, len; 70 struct vnode* vp = NULL; 71 dbg("readvnode | ino: %llu\n", (unsigned long long)ino); 72 73 len = sizeof(struct chfs_flash_vnode); 74 75 KASSERT(vpp != NULL); 76 77 if (vpp != NULL) { 78 vp = *vpp; 79 } 80 81 ip = VTOI(vp); 82 chvc = ip->chvc; 83 84 if (chvc && ino != CHFS_ROOTINO) { 85 /* debug... */ 86 printf("readvnode; offset: %" PRIu32 ", lnr: %d\n", 87 CHFS_GET_OFS(chvc->v->nref_offset), chvc->v->nref_lnr); 88 89 KASSERT((void *)chvc != (void *)chvc->v); 90 91 buf = kmem_alloc(len, KM_SLEEP); 92 err = chfs_read_leb(chmp, chvc->v->nref_lnr, buf, 93 CHFS_GET_OFS(chvc->v->nref_offset), len, &retlen); 94 if (err) 95 return err; 96 if (retlen != len) { 97 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 98 len, retlen); 99 return EIO; 100 } 101 chfvn = (struct chfs_flash_vnode*)buf; 102 chfs_set_vnode_size(vp, chfvn->dn_size); 103 ip->mode = chfvn->mode; 104 vp->v_type = IFTOVT(ip->mode); 105 ip->version = chfvn->version; 106 //ip->chvc->highest_version = ip->version; 107 ip->uid = chfvn->uid; 108 ip->gid = chfvn->gid; 109 ip->atime = chfvn->atime; 110 ip->mtime = chfvn->mtime; 111 ip->ctime = chfvn->ctime; 112 kmem_free(buf, len); 113 } 114 115 116 *vpp = vp; 117 return 0; 118 } 119 120 int 121 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir) 122 { 123 struct ufsmount *ump = VFSTOUFS(mp); 124 struct chfs_mount *chmp = ump->um_chfs; 125 struct chfs_flash_dirent_node chfdn; 126 struct chfs_dirent *fd;//, *pdents; 127 size_t len = sizeof(struct chfs_flash_dirent_node); 128 // struct chfs_vnode_cache* parent; 129 size_t retlen; 130 int err = 0; 131 132 // parent = chfs_get_vnode_cache(chmp, pdir->ino); 133 134 //read flash_dirent_node 135 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn, 136 CHFS_GET_OFS(chnr->nref_offset), len, &retlen); 137 if (err) { 138 return err; 139 } 140 if (retlen != len) { 141 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 142 retlen, len); 143 return EIO; 144 } 145 146 //set fields of dirent 147 fd = chfs_alloc_dirent(chfdn.nsize + 1); 148 fd->version = chfdn.version; 149 fd->vno = chfdn.vno; 150 fd->type = chfdn.dtype; 151 fd->nsize = chfdn.nsize; 152 // fd->next = NULL; 153 154 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name, 155 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen); 156 if (err) { 157 return err; 158 } 159 160 if (retlen != chfdn.nsize) { 161 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 162 len, retlen); 163 return EIO; 164 } 165 166 fd->name[fd->nsize] = 0; 167 fd->nref = chnr; 168 169 chfs_add_fd_to_inode(chmp, pdir, fd); 170 /* 171 pdents = pdir->i_chfs_ext.dents; 172 if (!pdents) 173 pdir->i_chfs_ext.dents = fd; 174 else { 175 while (pdents->next != NULL) { 176 pdents = pdents->next; 177 } 178 pdents->next = fd; 179 } 180 */ 181 return 0; 182 } 183 184 /* 185 * Allocate a new inode. 186 */ 187 int 188 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, 189 struct componentname *cnp, int type) 190 { 191 struct chfs_inode *ip, *pdir; 192 struct vnode *vp; 193 struct ufsmount* ump = VFSTOUFS(dvp->v_mount); 194 struct chfs_mount* chmp = ump->um_chfs; 195 struct chfs_vnode_cache* chvc; 196 int error; 197 ino_t vno; 198 struct chfs_dirent *nfd;//, *fd; 199 200 dbg("makeinode\n"); 201 pdir = VTOI(dvp); 202 203 *vpp = NULL; 204 205 vno = ++(chmp->chm_max_vno); 206 207 error = VFS_VGET(dvp->v_mount, vno, &vp); 208 if (error) 209 return (error); 210 211 mutex_enter(&chmp->chm_lock_vnocache); 212 chvc = chfs_vnode_cache_get(chmp, vno); 213 mutex_exit(&chmp->chm_lock_vnocache); 214 215 chvc->pvno = pdir->ino; 216 chvc->vno_version = kmem_alloc(sizeof(uint64_t), KM_SLEEP); 217 *(chvc->vno_version) = 1; 218 if (type != VDIR) 219 chvc->nlink = 1; 220 else 221 chvc->nlink = 2; 222 // chfs_vnode_cache_set_state(chmp, chvc, VNO_STATE_CHECKEDABSENT); 223 chvc->state = VNO_STATE_CHECKEDABSENT; 224 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->chvc->highest_version = 1; 240 ip->target = NULL; 241 242 ip->mode = mode; 243 vp->v_type = type; /* Rest init'd in getnewvnode(). */ 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 chfs_update(vp, NULL, NULL, UPDATE_WAIT); 255 256 mutex_enter(&chmp->chm_lock_mountfields); 257 258 //write inode to flash 259 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL); 260 if (error) { 261 mutex_exit(&chmp->chm_lock_mountfields); 262 vput(vp); 263 vput(dvp); 264 return error; 265 } 266 //update parent directory 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 vput(dvp); 275 return error; 276 } 277 vput(dvp); 278 279 //set up node's full dirent 280 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1); 281 nfd->vno = ip->ino; 282 nfd->version = (++pdir->chvc->highest_version); 283 nfd->type = type; 284 // nfd->next = NULL; 285 nfd->nsize = cnp->cn_namelen; 286 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen); 287 nfd->name[nfd->nsize] = 0; 288 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT); 289 290 // write out direntry 291 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL); 292 if (error) { 293 mutex_exit(&chmp->chm_lock_mountfields); 294 vput(vp); 295 return error; 296 } 297 298 //TODO set parent's dir times 299 300 chfs_add_fd_to_inode(chmp, pdir, nfd); 301 /* 302 fd = pdir->i_chfs_ext.dents; 303 if (!fd) 304 pdir->i_chfs_ext.dents = nfd; 305 else { 306 while (fd->next != NULL) { 307 fd = fd->next; 308 } 309 fd->next = nfd; 310 } 311 */ 312 //pdir->i_nlink++; 313 pdir->chvc->nlink++; 314 315 mutex_exit(&chmp->chm_lock_mountfields); 316 317 *vpp = vp; 318 return (0); 319 } 320 321 void 322 chfs_set_vnode_size(struct vnode *vp, size_t size) 323 { 324 struct chfs_inode *ip; 325 326 KASSERT(vp != NULL); 327 328 ip = VTOI(vp); 329 KASSERT(ip != NULL); 330 331 ip->size = size; 332 vp->v_size = vp->v_writesize = size; 333 return; 334 } 335 336 void 337 chfs_change_size_free(struct chfs_mount *chmp, 338 struct chfs_eraseblock *cheb, int change) 339 { 340 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 341 KASSERT((int)(chmp->chm_free_size + change) >= 0); 342 KASSERT((int)(cheb->free_size + change) >= 0); 343 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size); 344 chmp->chm_free_size += change; 345 cheb->free_size += change; 346 return; 347 } 348 349 void 350 chfs_change_size_dirty(struct chfs_mount *chmp, 351 struct chfs_eraseblock *cheb, int change) 352 { 353 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 354 KASSERT((int)(chmp->chm_dirty_size + change) >= 0); 355 KASSERT((int)(cheb->dirty_size + change) >= 0); 356 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size); 357 chmp->chm_dirty_size += change; 358 cheb->dirty_size += change; 359 return; 360 } 361 362 void 363 chfs_change_size_unchecked(struct chfs_mount *chmp, 364 struct chfs_eraseblock *cheb, int change) 365 { 366 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 367 KASSERT((int)(chmp->chm_unchecked_size + change) >= 0); 368 KASSERT((int)(cheb->unchecked_size + change) >= 0); 369 KASSERT((int)(cheb->unchecked_size + change) <= chmp->chm_ebh->eb_size); 370 chmp->chm_unchecked_size += change; 371 cheb->unchecked_size += change; 372 return; 373 } 374 375 void 376 chfs_change_size_used(struct chfs_mount *chmp, 377 struct chfs_eraseblock *cheb, int change) 378 { 379 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 380 KASSERT((int)(chmp->chm_used_size + change) >= 0); 381 KASSERT((int)(cheb->used_size + change) >= 0); 382 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size); 383 chmp->chm_used_size += change; 384 cheb->used_size += change; 385 return; 386 } 387 388 void 389 chfs_change_size_wasted(struct chfs_mount *chmp, 390 struct chfs_eraseblock *cheb, int change) 391 { 392 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 393 KASSERT((int)(chmp->chm_wasted_size + change) >= 0); 394 KASSERT((int)(cheb->wasted_size + change) >= 0); 395 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size); 396 chmp->chm_wasted_size += change; 397 cheb->wasted_size += change; 398 return; 399 } 400 401