1 /* $NetBSD: chfs_vnode.c,v 1.7 2012/08/13 13:12:51 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 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 dbg("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 ip->ch_type = IFTOCHT(ip->mode); 105 vp->v_type = CHTTOVT(ip->ch_type); 106 ip->version = chfvn->version; 107 //ip->chvc->highest_version = ip->version; 108 ip->uid = chfvn->uid; 109 ip->gid = chfvn->gid; 110 ip->atime = chfvn->atime; 111 ip->mtime = chfvn->mtime; 112 ip->ctime = chfvn->ctime; 113 kmem_free(buf, len); 114 } 115 116 117 *vpp = vp; 118 return 0; 119 } 120 121 int 122 chfs_readdirent(struct mount *mp, struct chfs_node_ref *chnr, struct chfs_inode *pdir) 123 { 124 struct ufsmount *ump = VFSTOUFS(mp); 125 struct chfs_mount *chmp = ump->um_chfs; 126 struct chfs_flash_dirent_node chfdn; 127 struct chfs_dirent *fd;//, *pdents; 128 size_t len = sizeof(struct chfs_flash_dirent_node); 129 // struct chfs_vnode_cache* parent; 130 size_t retlen; 131 int err = 0; 132 133 // parent = chfs_get_vnode_cache(chmp, pdir->ino); 134 135 //read flash_dirent_node 136 err = chfs_read_leb(chmp, chnr->nref_lnr, (char *)&chfdn, 137 CHFS_GET_OFS(chnr->nref_offset), len, &retlen); 138 if (err) { 139 return err; 140 } 141 if (retlen != len) { 142 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 143 retlen, len); 144 return EIO; 145 } 146 147 //set fields of dirent 148 fd = chfs_alloc_dirent(chfdn.nsize + 1); 149 fd->version = chfdn.version; 150 fd->vno = chfdn.vno; 151 fd->type = chfdn.dtype; 152 fd->nsize = chfdn.nsize; 153 // fd->next = NULL; 154 155 err = chfs_read_leb(chmp, chnr->nref_lnr, fd->name, 156 CHFS_GET_OFS(chnr->nref_offset) + len, chfdn.nsize, &retlen); 157 if (err) { 158 return err; 159 } 160 161 if (retlen != chfdn.nsize) { 162 chfs_err("Error reading vnode: read: %zu insted of: %zu\n", 163 len, retlen); 164 return EIO; 165 } 166 167 fd->name[fd->nsize] = 0; 168 fd->nref = chnr; 169 170 chfs_add_fd_to_inode(chmp, pdir, fd); 171 /* 172 pdents = pdir->i_chfs_ext.dents; 173 if (!pdents) 174 pdir->i_chfs_ext.dents = fd; 175 else { 176 while (pdents->next != NULL) { 177 pdents = pdents->next; 178 } 179 pdents->next = fd; 180 } 181 */ 182 return 0; 183 } 184 185 /* 186 * Allocate a new inode. 187 */ 188 int 189 chfs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, 190 struct componentname *cnp, enum vtype type) 191 { 192 struct chfs_inode *ip, *pdir; 193 struct vnode *vp; 194 struct ufsmount* ump = VFSTOUFS(dvp->v_mount); 195 struct chfs_mount* chmp = ump->um_chfs; 196 struct chfs_vnode_cache* chvc; 197 int error; 198 ino_t vno; 199 struct chfs_dirent *nfd;//, *fd; 200 201 dbg("makeinode\n"); 202 pdir = VTOI(dvp); 203 204 *vpp = NULL; 205 206 vno = ++(chmp->chm_max_vno); 207 208 error = VFS_VGET(dvp->v_mount, vno, &vp); 209 if (error) 210 return (error); 211 212 mutex_enter(&chmp->chm_lock_vnocache); 213 chvc = chfs_vnode_cache_get(chmp, vno); 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 chvc->state = VNO_STATE_CHECKEDABSENT; 223 mutex_exit(&chmp->chm_lock_vnocache); 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 ip->ch_type = VTTOCHT(vp->v_type); 245 246 /* Authorize setting SGID if needed. */ 247 if (ip->mode & ISGID) { 248 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, 249 vp, NULL, genfs_can_chmod(vp->v_type, cnp->cn_cred, ip->uid, 250 ip->gid, mode)); 251 if (error) 252 ip->mode &= ~ISGID; 253 } 254 255 chfs_update(vp, NULL, NULL, UPDATE_WAIT); 256 257 mutex_enter(&chmp->chm_lock_mountfields); 258 259 //write inode to flash 260 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL); 261 if (error) { 262 mutex_exit(&chmp->chm_lock_mountfields); 263 vput(vp); 264 vput(dvp); 265 return error; 266 } 267 //update parent directory and write it to the flash 268 pdir->iflag |= (IN_ACCESS | IN_CHANGE | IN_MODIFY | IN_UPDATE); 269 chfs_update(dvp, NULL, NULL, UPDATE_WAIT); 270 271 error = chfs_write_flash_vnode(chmp, pdir, ALLOC_NORMAL); 272 if (error) { 273 mutex_exit(&chmp->chm_lock_mountfields); 274 vput(vp); 275 vput(dvp); 276 return error; 277 } 278 vput(dvp); 279 280 //set up node's full dirent 281 nfd = chfs_alloc_dirent(cnp->cn_namelen + 1); 282 nfd->vno = ip->ino; 283 nfd->version = (++pdir->chvc->highest_version); 284 nfd->type = ip->ch_type; 285 // nfd->next = NULL; 286 nfd->nsize = cnp->cn_namelen; 287 memcpy(&(nfd->name), cnp->cn_nameptr, cnp->cn_namelen); 288 nfd->name[nfd->nsize] = 0; 289 nfd->nhash = hash32_buf(nfd->name, cnp->cn_namelen, HASH32_BUF_INIT); 290 291 // write out direntry 292 error = chfs_write_flash_dirent(chmp, pdir, ip, nfd, ip->ino, ALLOC_NORMAL); 293 if (error) { 294 mutex_exit(&chmp->chm_lock_mountfields); 295 vput(vp); 296 return error; 297 } 298 299 //TODO set parent's dir times 300 301 chfs_add_fd_to_inode(chmp, pdir, nfd); 302 /* 303 fd = pdir->i_chfs_ext.dents; 304 if (!fd) 305 pdir->i_chfs_ext.dents = nfd; 306 else { 307 while (fd->next != NULL) { 308 fd = fd->next; 309 } 310 fd->next = nfd; 311 } 312 */ 313 //pdir->i_nlink++; 314 pdir->chvc->nlink++; 315 316 mutex_exit(&chmp->chm_lock_mountfields); 317 318 *vpp = vp; 319 return (0); 320 } 321 322 void 323 chfs_set_vnode_size(struct vnode *vp, size_t size) 324 { 325 struct chfs_inode *ip; 326 327 KASSERT(vp != NULL); 328 329 ip = VTOI(vp); 330 KASSERT(ip != NULL); 331 332 ip->size = size; 333 vp->v_size = vp->v_writesize = size; 334 return; 335 } 336 337 void 338 chfs_change_size_free(struct chfs_mount *chmp, 339 struct chfs_eraseblock *cheb, int change) 340 { 341 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 342 KASSERT((int)(chmp->chm_free_size + change) >= 0); 343 KASSERT((int)(cheb->free_size + change) >= 0); 344 KASSERT((int)(cheb->free_size + change) <= chmp->chm_ebh->eb_size); 345 chmp->chm_free_size += change; 346 cheb->free_size += change; 347 return; 348 } 349 350 void 351 chfs_change_size_dirty(struct chfs_mount *chmp, 352 struct chfs_eraseblock *cheb, int change) 353 { 354 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 355 KASSERT((int)(chmp->chm_dirty_size + change) >= 0); 356 KASSERT((int)(cheb->dirty_size + change) >= 0); 357 KASSERT((int)(cheb->dirty_size + change) <= chmp->chm_ebh->eb_size); 358 chmp->chm_dirty_size += change; 359 cheb->dirty_size += change; 360 return; 361 } 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 void 377 chfs_change_size_used(struct chfs_mount *chmp, 378 struct chfs_eraseblock *cheb, int change) 379 { 380 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 381 KASSERT((int)(chmp->chm_used_size + change) >= 0); 382 KASSERT((int)(cheb->used_size + change) >= 0); 383 KASSERT((int)(cheb->used_size + change) <= chmp->chm_ebh->eb_size); 384 chmp->chm_used_size += change; 385 cheb->used_size += change; 386 return; 387 } 388 389 void 390 chfs_change_size_wasted(struct chfs_mount *chmp, 391 struct chfs_eraseblock *cheb, int change) 392 { 393 KASSERT(mutex_owned(&chmp->chm_lock_sizes)); 394 KASSERT((int)(chmp->chm_wasted_size + change) >= 0); 395 KASSERT((int)(cheb->wasted_size + change) >= 0); 396 KASSERT((int)(cheb->wasted_size + change) <= chmp->chm_ebh->eb_size); 397 chmp->chm_wasted_size += change; 398 cheb->wasted_size += change; 399 return; 400 } 401 402