1 /* $NetBSD: msdosfs_denode.c,v 1.50 2014/07/08 09:21:52 hannken Exp $ */ 2 3 /*- 4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 6 * All rights reserved. 7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 /* 35 * Written by Paul Popelka (paulp@uts.amdahl.com) 36 * 37 * You can do anything you want with this software, just don't say you wrote 38 * it, and don't remove this notice. 39 * 40 * This software is provided "as is". 41 * 42 * The author supplies this software to be publicly redistributed on the 43 * understanding that the author is not responsible for the correct 44 * functioning of this software in any circumstances and is not liable for 45 * any damages caused by this software. 46 * 47 * October 1992 48 */ 49 50 #include <sys/cdefs.h> 51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.50 2014/07/08 09:21:52 hannken Exp $"); 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/mount.h> 56 #include <sys/fstrans.h> 57 #include <sys/malloc.h> 58 #include <sys/pool.h> 59 #include <sys/proc.h> 60 #include <sys/buf.h> 61 #include <sys/vnode.h> 62 #include <sys/kernel.h> /* defines "time" */ 63 #include <sys/dirent.h> 64 #include <sys/namei.h> 65 #include <sys/kauth.h> 66 67 #include <uvm/uvm_extern.h> 68 69 #include <fs/msdosfs/bpb.h> 70 #include <fs/msdosfs/msdosfsmount.h> 71 #include <fs/msdosfs/direntry.h> 72 #include <fs/msdosfs/denode.h> 73 #include <fs/msdosfs/fat.h> 74 75 struct pool msdosfs_denode_pool; 76 77 extern int prtactive; 78 79 struct fh_key { 80 struct msdosfsmount *fhk_mount; 81 uint32_t fhk_dircluster; 82 uint32_t fhk_diroffset; 83 }; 84 struct fh_node { 85 struct rb_node fh_rbnode; 86 struct fh_key fh_key; 87 #define fh_mount fh_key.fhk_mount 88 #define fh_dircluster fh_key.fhk_dircluster 89 #define fh_diroffset fh_key.fhk_diroffset 90 uint32_t fh_gen; 91 }; 92 93 static int 94 fh_compare_node_fh(void *ctx, const void *b, const void *key) 95 { 96 const struct fh_node * const pnp = b; 97 const struct fh_key * const fhp = key; 98 99 /* msdosfs_fh_destroy() below depends on first sorting on fh_mount. */ 100 if (pnp->fh_mount != fhp->fhk_mount) 101 return (intptr_t)pnp->fh_mount - (intptr_t)fhp->fhk_mount; 102 if (pnp->fh_dircluster != fhp->fhk_dircluster) 103 return pnp->fh_dircluster - fhp->fhk_dircluster; 104 return pnp->fh_diroffset - fhp->fhk_diroffset; 105 } 106 107 static int 108 fh_compare_nodes(void *ctx, const void *parent, const void *node) 109 { 110 const struct fh_node * const np = node; 111 112 return fh_compare_node_fh(ctx, parent, &np->fh_key); 113 } 114 115 static uint32_t fh_generation; 116 static kmutex_t fh_lock; 117 static struct pool fh_pool; 118 static rb_tree_t fh_rbtree; 119 static const rb_tree_ops_t fh_rbtree_ops = { 120 .rbto_compare_nodes = fh_compare_nodes, 121 .rbto_compare_key = fh_compare_node_fh, 122 .rbto_node_offset = offsetof(struct fh_node, fh_rbnode), 123 .rbto_context = NULL 124 }; 125 126 static const struct genfs_ops msdosfs_genfsops = { 127 .gop_size = genfs_size, 128 .gop_alloc = msdosfs_gop_alloc, 129 .gop_write = genfs_gop_write, 130 .gop_markupdate = msdosfs_gop_markupdate, 131 }; 132 133 MALLOC_DECLARE(M_MSDOSFSFAT); 134 135 void 136 msdosfs_init(void) 137 { 138 139 malloc_type_attach(M_MSDOSFSMNT); 140 malloc_type_attach(M_MSDOSFSFAT); 141 malloc_type_attach(M_MSDOSFSTMP); 142 pool_init(&msdosfs_denode_pool, sizeof(struct denode), 0, 0, 0, 143 "msdosnopl", &pool_allocator_nointr, IPL_NONE); 144 pool_init(&fh_pool, sizeof(struct fh_node), 0, 0, 0, 145 "msdosfhpl", &pool_allocator_nointr, IPL_NONE); 146 rb_tree_init(&fh_rbtree, &fh_rbtree_ops); 147 mutex_init(&fh_lock, MUTEX_DEFAULT, IPL_NONE); 148 } 149 150 /* 151 * Reinitialize. 152 */ 153 154 void 155 msdosfs_reinit(void) 156 { 157 158 } 159 160 void 161 msdosfs_done(void) 162 { 163 pool_destroy(&msdosfs_denode_pool); 164 pool_destroy(&fh_pool); 165 mutex_destroy(&fh_lock); 166 malloc_type_detach(M_MSDOSFSTMP); 167 malloc_type_detach(M_MSDOSFSFAT); 168 malloc_type_detach(M_MSDOSFSMNT); 169 } 170 171 /* 172 * If deget() succeeds it returns with the gotten denode unlocked. 173 * 174 * pmp - address of msdosfsmount structure of the filesystem containing 175 * the denode of interest. The pm_dev field and the address of 176 * the msdosfsmount structure are used. 177 * dirclust - which cluster bp contains, if dirclust is 0 (root directory) 178 * diroffset is relative to the beginning of the root directory, 179 * otherwise it is cluster relative. 180 * diroffset - offset past begin of cluster of denode we want 181 * vpp - returns the address of the gotten vnode. 182 */ 183 int 184 deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, 185 struct vnode **vpp) 186 /* pmp: so we know the maj/min number */ 187 /* dirclust: cluster this dir entry came from */ 188 /* diroffset: index of entry within the cluster */ 189 /* vpp: returns the addr of the gotten vnode */ 190 { 191 int error; 192 struct denode_key key; 193 194 /* 195 * On FAT32 filesystems, root is a (more or less) normal 196 * directory 197 */ 198 if (FAT32(pmp) && dirclust == MSDOSFSROOT) 199 dirclust = pmp->pm_rootdirblk; 200 201 memset(&key, 0, sizeof(key)); 202 key.dk_dirclust = dirclust; 203 key.dk_diroffset = diroffset; 204 /* key.dk_dirgen = NULL; */ 205 206 error = vcache_get(pmp->pm_mountp, &key, sizeof(key), vpp); 207 return error; 208 } 209 210 int 211 msdosfs_loadvnode(struct mount *mp, struct vnode *vp, 212 const void *key, size_t key_len, const void **new_key) 213 { 214 bool is_root; 215 int error; 216 extern int (**msdosfs_vnodeop_p)(void *); 217 struct msdosfsmount *pmp; 218 struct direntry *direntptr; 219 struct denode *ldep; 220 struct buf *bp; 221 struct denode_key dkey; 222 223 KASSERT(key_len == sizeof(dkey)); 224 memcpy(&dkey, key, key_len); 225 KASSERT(dkey.dk_dirgen == NULL); 226 227 pmp = VFSTOMSDOSFS(mp); 228 is_root = ((dkey.dk_dirclust == MSDOSFSROOT || 229 (FAT32(pmp) && dkey.dk_dirclust == pmp->pm_rootdirblk)) && 230 dkey.dk_diroffset == MSDOSFSROOT_OFS); 231 232 #ifdef MSDOSFS_DEBUG 233 printf("loadvnode(pmp %p, dirclust %lu, diroffset %lx, vp %p)\n", 234 pmp, dkey.dk_dirclust, dkey.dk_diroffset, vp); 235 #endif 236 237 ldep = pool_get(&msdosfs_denode_pool, PR_WAITOK); 238 memset(ldep, 0, sizeof *ldep); 239 /* ldep->de_flag = 0; */ 240 /* ldep->de_devvp = 0; */ 241 /* ldep->de_lockf = 0; */ 242 ldep->de_dev = pmp->pm_dev; 243 ldep->de_dirclust = dkey.dk_dirclust; 244 ldep->de_diroffset = dkey.dk_diroffset; 245 ldep->de_pmp = pmp; 246 ldep->de_devvp = pmp->pm_devvp; 247 ldep->de_refcnt = 1; 248 fc_purge(ldep, 0); /* init the FAT cache for this denode */ 249 250 /* 251 * Copy the directory entry into the denode area of the vnode. 252 */ 253 if (is_root) { 254 /* 255 * Directory entry for the root directory. There isn't one, 256 * so we manufacture one. We should probably rummage 257 * through the root directory and find a label entry (if it 258 * exists), and then use the time and date from that entry 259 * as the time and date for the root denode. 260 */ 261 ldep->de_Attributes = ATTR_DIRECTORY; 262 if (FAT32(pmp)) 263 ldep->de_StartCluster = pmp->pm_rootdirblk; 264 /* de_FileSize will be filled in further down */ 265 else { 266 ldep->de_StartCluster = MSDOSFSROOT; 267 ldep->de_FileSize = pmp->pm_rootdirsize * 268 pmp->pm_BytesPerSec; 269 } 270 /* 271 * fill in time and date so that dos2unixtime() doesn't 272 * spit up when called from msdosfs_getattr() with root 273 * denode 274 */ 275 ldep->de_CHun = 0; 276 ldep->de_CTime = 0x0000; /* 00:00:00 */ 277 ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT) 278 | (1 << DD_DAY_SHIFT); 279 /* Jan 1, 1980 */ 280 ldep->de_ADate = ldep->de_CDate; 281 ldep->de_MTime = ldep->de_CTime; 282 ldep->de_MDate = ldep->de_CDate; 283 /* leave the other fields as garbage */ 284 } else { 285 error = readep(pmp, ldep->de_dirclust, ldep->de_diroffset, 286 &bp, &direntptr); 287 if (error) { 288 pool_put(&msdosfs_denode_pool, ldep); 289 return error; 290 } 291 DE_INTERNALIZE(ldep, direntptr); 292 brelse(bp, 0); 293 } 294 295 /* 296 * Fill in a few fields of the vnode and finish filling in the 297 * denode. 298 */ 299 if (ldep->de_Attributes & ATTR_DIRECTORY) { 300 /* 301 * Since DOS directory entries that describe directories 302 * have 0 in the filesize field, we take this opportunity 303 * to find out the length of the directory and plug it into 304 * the denode structure. 305 */ 306 u_long size; 307 308 vp->v_type = VDIR; 309 if (ldep->de_StartCluster != MSDOSFSROOT) { 310 error = pcbmap(ldep, CLUST_END, 0, &size, 0); 311 if (error == E2BIG) { 312 ldep->de_FileSize = de_cn2off(pmp, size); 313 error = 0; 314 } else 315 printf("loadvnode(): pcbmap returned %d\n", 316 error); 317 } 318 } else 319 vp->v_type = VREG; 320 vref(ldep->de_devvp); 321 if (is_root) 322 vp->v_vflag |= VV_ROOT; 323 vp->v_tag = VT_MSDOSFS; 324 vp->v_op = msdosfs_vnodeop_p; 325 vp->v_data = ldep; 326 ldep->de_vnode = vp; 327 genfs_node_init(vp, &msdosfs_genfsops); 328 uvm_vnp_setsize(vp, ldep->de_FileSize); 329 *new_key = &ldep->de_key; 330 331 return 0; 332 } 333 334 int 335 deupdat(struct denode *dep, int waitfor) 336 { 337 338 return (msdosfs_update(DETOV(dep), NULL, NULL, 339 waitfor ? UPDATE_WAIT : 0)); 340 } 341 342 /* 343 * Truncate the file described by dep to the length specified by length. 344 */ 345 int 346 detrunc(struct denode *dep, u_long length, int flags, kauth_cred_t cred) 347 { 348 int error; 349 int allerror; 350 u_long eofentry; 351 u_long chaintofree = 0; 352 daddr_t bn, lastblock; 353 int boff; 354 int isadir = dep->de_Attributes & ATTR_DIRECTORY; 355 struct buf *bp; 356 struct msdosfsmount *pmp = dep->de_pmp; 357 358 #ifdef MSDOSFS_DEBUG 359 printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags); 360 #endif 361 362 /* 363 * Disallow attempts to truncate the root directory since it is of 364 * fixed size. That's just the way dos filesystems are. We use 365 * the VROOT bit in the vnode because checking for the directory 366 * bit and a startcluster of 0 in the denode is not adequate to 367 * recognize the root directory at this point in a file or 368 * directory's life. 369 */ 370 if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) { 371 printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n", 372 dep->de_dirclust, dep->de_diroffset); 373 return (EINVAL); 374 } 375 376 uvm_vnp_setsize(DETOV(dep), length); 377 378 if (dep->de_FileSize < length) 379 return (deextend(dep, length, cred)); 380 lastblock = de_clcount(pmp, length) - 1; 381 382 /* 383 * If the desired length is 0 then remember the starting cluster of 384 * the file and set the StartCluster field in the directory entry 385 * to 0. If the desired length is not zero, then get the number of 386 * the last cluster in the shortened file. Then get the number of 387 * the first cluster in the part of the file that is to be freed. 388 * Then set the next cluster pointer in the last cluster of the 389 * file to CLUST_EOFE. 390 */ 391 if (length == 0) { 392 chaintofree = dep->de_StartCluster; 393 dep->de_StartCluster = 0; 394 eofentry = ~0; 395 } else { 396 error = pcbmap(dep, lastblock, 0, &eofentry, 0); 397 if (error) { 398 #ifdef MSDOSFS_DEBUG 399 printf("detrunc(): pcbmap fails %d\n", error); 400 #endif 401 return (error); 402 } 403 } 404 405 /* 406 * If the new length is not a multiple of the cluster size then we 407 * must zero the tail end of the new last cluster in case it 408 * becomes part of the file again because of a seek. 409 */ 410 if ((boff = length & pmp->pm_crbomask) != 0) { 411 if (isadir) { 412 bn = cntobn(pmp, eofentry); 413 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 414 pmp->pm_bpcluster, NOCRED, B_MODIFY, &bp); 415 if (error) { 416 #ifdef MSDOSFS_DEBUG 417 printf("detrunc(): bread fails %d\n", error); 418 #endif 419 return (error); 420 } 421 memset((char *)bp->b_data + boff, 0, 422 pmp->pm_bpcluster - boff); 423 if (flags & IO_SYNC) 424 bwrite(bp); 425 else 426 bdwrite(bp); 427 } else { 428 ubc_zerorange(&DETOV(dep)->v_uobj, length, 429 pmp->pm_bpcluster - boff, 430 UBC_UNMAP_FLAG(DETOV(dep))); 431 } 432 } 433 434 /* 435 * Write out the updated directory entry. Even if the update fails 436 * we free the trailing clusters. 437 */ 438 dep->de_FileSize = length; 439 if (!isadir) 440 dep->de_flag |= DE_UPDATE|DE_MODIFIED; 441 vtruncbuf(DETOV(dep), lastblock + 1, 0, 0); 442 allerror = deupdat(dep, 1); 443 #ifdef MSDOSFS_DEBUG 444 printf("detrunc(): allerror %d, eofentry %lu\n", 445 allerror, eofentry); 446 #endif 447 448 fc_purge(dep, lastblock + 1); 449 450 /* 451 * If we need to break the cluster chain for the file then do it 452 * now. 453 */ 454 if (eofentry != ~0) { 455 error = fatentry(FAT_GET_AND_SET, pmp, eofentry, 456 &chaintofree, CLUST_EOFE); 457 if (error) { 458 #ifdef MSDOSFS_DEBUG 459 printf("detrunc(): fatentry errors %d\n", error); 460 #endif 461 return (error); 462 } 463 fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1), 464 eofentry); 465 } 466 467 /* 468 * Now free the clusters removed from the file because of the 469 * truncation. 470 */ 471 if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask)) 472 freeclusterchain(pmp, chaintofree); 473 474 return (allerror); 475 } 476 477 /* 478 * Extend the file described by dep to length specified by length. 479 */ 480 int 481 deextend(struct denode *dep, u_long length, kauth_cred_t cred) 482 { 483 struct msdosfsmount *pmp = dep->de_pmp; 484 u_long count, osize; 485 int error; 486 487 /* 488 * The root of a DOS filesystem cannot be extended. 489 */ 490 if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) 491 return (EINVAL); 492 493 /* 494 * Directories cannot be extended. 495 */ 496 if (dep->de_Attributes & ATTR_DIRECTORY) 497 return (EISDIR); 498 499 if (length <= dep->de_FileSize) 500 panic("deextend: file too large"); 501 502 /* 503 * Compute the number of clusters to allocate. 504 */ 505 count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize); 506 if (count > 0) { 507 if (count > pmp->pm_freeclustercount) 508 return (ENOSPC); 509 error = extendfile(dep, count, NULL, NULL, DE_CLEAR); 510 if (error) { 511 /* truncate the added clusters away again */ 512 (void) detrunc(dep, dep->de_FileSize, 0, cred); 513 return (error); 514 } 515 } 516 517 /* 518 * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a 519 * memset(); we set the write size so ubc won't read in file data that 520 * is zero'd later. 521 */ 522 osize = dep->de_FileSize; 523 dep->de_FileSize = length; 524 uvm_vnp_setwritesize(DETOV(dep), (voff_t)dep->de_FileSize); 525 dep->de_flag |= DE_UPDATE|DE_MODIFIED; 526 ubc_zerorange(&DETOV(dep)->v_uobj, (off_t)osize, 527 (size_t)(round_page(dep->de_FileSize) - osize), 528 UBC_UNMAP_FLAG(DETOV(dep))); 529 uvm_vnp_setsize(DETOV(dep), (voff_t)dep->de_FileSize); 530 return (deupdat(dep, 1)); 531 } 532 533 int 534 msdosfs_reclaim(void *v) 535 { 536 struct vop_reclaim_args /* { 537 struct vnode *a_vp; 538 } */ *ap = v; 539 struct vnode *vp = ap->a_vp; 540 struct mount *mp = vp->v_mount; 541 struct denode *dep = VTODE(vp); 542 543 fstrans_start(mp, FSTRANS_LAZY); 544 #ifdef MSDOSFS_DEBUG 545 printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n", 546 dep, dep->de_Name, dep->de_refcnt); 547 #endif 548 549 if (prtactive && vp->v_usecount > 1) 550 vprint("msdosfs_reclaim(): pushing active", vp); 551 /* 552 * Remove the denode from the vnode cache. 553 */ 554 vcache_remove(vp->v_mount, &dep->de_key, sizeof(dep->de_key)); 555 /* 556 * Purge old data structures associated with the denode. 557 */ 558 if (dep->de_devvp) { 559 vrele(dep->de_devvp); 560 dep->de_devvp = 0; 561 } 562 #if 0 /* XXX */ 563 dep->de_flag = 0; 564 #endif 565 /* 566 * To interlock with msdosfs_sync(). 567 */ 568 genfs_node_destroy(vp); 569 mutex_enter(vp->v_interlock); 570 vp->v_data = NULL; 571 mutex_exit(vp->v_interlock); 572 pool_put(&msdosfs_denode_pool, dep); 573 fstrans_done(mp); 574 return (0); 575 } 576 577 int 578 msdosfs_inactive(void *v) 579 { 580 struct vop_inactive_args /* { 581 struct vnode *a_vp; 582 bool *a_recycle; 583 } */ *ap = v; 584 struct vnode *vp = ap->a_vp; 585 struct mount *mp = vp->v_mount; 586 struct denode *dep = VTODE(vp); 587 int error = 0; 588 589 #ifdef MSDOSFS_DEBUG 590 printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep, dep->de_Name[0]); 591 #endif 592 593 fstrans_start(mp, FSTRANS_LAZY); 594 /* 595 * Get rid of denodes related to stale file handles. 596 */ 597 if (dep->de_Name[0] == SLOT_DELETED) 598 goto out; 599 600 /* 601 * If the file has been deleted and it is on a read/write 602 * filesystem, then truncate the file, and mark the directory slot 603 * as empty. (This may not be necessary for the dos filesystem.) 604 */ 605 #ifdef MSDOSFS_DEBUG 606 printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x %s\n", 607 dep, dep->de_refcnt, vp->v_mount->mnt_flag, 608 (vp->v_mount->mnt_flag & MNT_RDONLY) ? "MNT_RDONLY" : ""); 609 #endif 610 if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 611 if (dep->de_FileSize != 0) { 612 error = detrunc(dep, (u_long)0, 0, NOCRED); 613 } 614 dep->de_Name[0] = SLOT_DELETED; 615 msdosfs_fh_remove(dep->de_pmp, 616 dep->de_dirclust, dep->de_diroffset); 617 } 618 deupdat(dep, 0); 619 out: 620 /* 621 * If we are done with the denode, reclaim it 622 * so that it can be reused immediately. 623 */ 624 #ifdef MSDOSFS_DEBUG 625 printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", 626 vp->v_usecount, dep->de_Name[0]); 627 #endif 628 *ap->a_recycle = (dep->de_Name[0] == SLOT_DELETED); 629 VOP_UNLOCK(vp); 630 fstrans_done(mp); 631 return (error); 632 } 633 634 int 635 msdosfs_gop_alloc(struct vnode *vp, off_t off, 636 off_t len, int flags, kauth_cred_t cred) 637 { 638 return 0; 639 } 640 641 void 642 msdosfs_gop_markupdate(struct vnode *vp, int flags) 643 { 644 u_long mask = 0; 645 646 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 647 mask = DE_ACCESS; 648 } 649 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 650 mask |= DE_UPDATE; 651 } 652 if (mask) { 653 struct denode *dep = VTODE(vp); 654 655 dep->de_flag |= mask; 656 } 657 } 658 659 int 660 msdosfs_fh_enter(struct msdosfsmount *pmp, 661 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 662 { 663 struct fh_key fhkey; 664 struct fh_node *fhp; 665 666 fhkey.fhk_mount = pmp; 667 fhkey.fhk_dircluster = dircluster; 668 fhkey.fhk_diroffset = diroffset; 669 670 mutex_enter(&fh_lock); 671 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 672 if (fhp == NULL) { 673 mutex_exit(&fh_lock); 674 fhp = pool_get(&fh_pool, PR_WAITOK); 675 mutex_enter(&fh_lock); 676 fhp->fh_key = fhkey; 677 fhp->fh_gen = fh_generation++; 678 rb_tree_insert_node(&fh_rbtree, fhp); 679 } 680 *genp = fhp->fh_gen; 681 mutex_exit(&fh_lock); 682 return 0; 683 } 684 685 int 686 msdosfs_fh_remove(struct msdosfsmount *pmp, 687 uint32_t dircluster, uint32_t diroffset) 688 { 689 struct fh_key fhkey; 690 struct fh_node *fhp; 691 692 fhkey.fhk_mount = pmp; 693 fhkey.fhk_dircluster = dircluster; 694 fhkey.fhk_diroffset = diroffset; 695 696 mutex_enter(&fh_lock); 697 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 698 if (fhp == NULL) { 699 mutex_exit(&fh_lock); 700 return ENOENT; 701 } 702 rb_tree_remove_node(&fh_rbtree, fhp); 703 mutex_exit(&fh_lock); 704 pool_put(&fh_pool, fhp); 705 return 0; 706 } 707 708 int 709 msdosfs_fh_lookup(struct msdosfsmount *pmp, 710 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 711 { 712 struct fh_key fhkey; 713 struct fh_node *fhp; 714 715 fhkey.fhk_mount = pmp; 716 fhkey.fhk_dircluster = dircluster; 717 fhkey.fhk_diroffset = diroffset; 718 719 mutex_enter(&fh_lock); 720 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 721 if (fhp == NULL) { 722 mutex_exit(&fh_lock); 723 return ESTALE; 724 } 725 *genp = fhp->fh_gen; 726 mutex_exit(&fh_lock); 727 return 0; 728 } 729 730 void 731 msdosfs_fh_destroy(struct msdosfsmount *pmp) 732 { 733 struct fh_key fhkey; 734 struct fh_node *fhp, *nfhp; 735 736 fhkey.fhk_mount = pmp; 737 fhkey.fhk_dircluster = 0; 738 fhkey.fhk_diroffset = 0; 739 740 mutex_enter(&fh_lock); 741 for (fhp = rb_tree_find_node_geq(&fh_rbtree, &fhkey); 742 fhp != NULL && fhp->fh_mount == pmp; fhp = nfhp) { 743 nfhp = rb_tree_iterate(&fh_rbtree, fhp, RB_DIR_RIGHT); 744 rb_tree_remove_node(&fh_rbtree, fhp); 745 pool_put(&fh_pool, fhp); 746 } 747 #ifdef DIAGNOSTIC 748 RB_TREE_FOREACH(fhp, &fh_rbtree) { 749 KASSERT(fhp->fh_mount != pmp); 750 } 751 #endif 752 mutex_exit(&fh_lock); 753 } 754