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