1 /* $NetBSD: msdosfs_denode.c,v 1.48 2012/12/20 08:03:42 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.48 2012/12/20 08:03:42 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 LIST_HEAD(ihashhead, denode) *dehashtbl; 76 u_long dehash; /* size of hash table - 1 */ 77 #define DEHASH(dev, dcl, doff) \ 78 (((dev) + (dcl) + (doff) / sizeof(struct direntry)) & dehash) 79 80 kmutex_t msdosfs_ihash_lock; 81 kmutex_t msdosfs_hashlock; 82 83 struct pool msdosfs_denode_pool; 84 85 extern int prtactive; 86 87 struct fh_key { 88 struct msdosfsmount *fhk_mount; 89 uint32_t fhk_dircluster; 90 uint32_t fhk_diroffset; 91 }; 92 struct fh_node { 93 struct rb_node fh_rbnode; 94 struct fh_key fh_key; 95 #define fh_mount fh_key.fhk_mount 96 #define fh_dircluster fh_key.fhk_dircluster 97 #define fh_diroffset fh_key.fhk_diroffset 98 uint32_t fh_gen; 99 }; 100 101 static int 102 fh_compare_node_fh(void *ctx, const void *b, const void *key) 103 { 104 const struct fh_node * const pnp = b; 105 const struct fh_key * const fhp = key; 106 107 /* msdosfs_fh_destroy() below depends on first sorting on fh_mount. */ 108 if (pnp->fh_mount != fhp->fhk_mount) 109 return (intptr_t)pnp->fh_mount - (intptr_t)fhp->fhk_mount; 110 if (pnp->fh_dircluster != fhp->fhk_dircluster) 111 return pnp->fh_dircluster - fhp->fhk_dircluster; 112 return pnp->fh_diroffset - fhp->fhk_diroffset; 113 } 114 115 static int 116 fh_compare_nodes(void *ctx, const void *parent, const void *node) 117 { 118 const struct fh_node * const np = node; 119 120 return fh_compare_node_fh(ctx, parent, &np->fh_key); 121 } 122 123 static uint32_t fh_generation; 124 static kmutex_t fh_lock; 125 static struct pool fh_pool; 126 static rb_tree_t fh_rbtree; 127 static const rb_tree_ops_t fh_rbtree_ops = { 128 .rbto_compare_nodes = fh_compare_nodes, 129 .rbto_compare_key = fh_compare_node_fh, 130 .rbto_node_offset = offsetof(struct fh_node, fh_rbnode), 131 .rbto_context = NULL 132 }; 133 134 static const struct genfs_ops msdosfs_genfsops = { 135 .gop_size = genfs_size, 136 .gop_alloc = msdosfs_gop_alloc, 137 .gop_write = genfs_gop_write, 138 .gop_markupdate = msdosfs_gop_markupdate, 139 }; 140 141 static struct denode *msdosfs_hashget(dev_t, u_long, u_long, int); 142 static void msdosfs_hashins(struct denode *); 143 static void msdosfs_hashrem(struct denode *); 144 145 MALLOC_DECLARE(M_MSDOSFSFAT); 146 147 void 148 msdosfs_init(void) 149 { 150 151 malloc_type_attach(M_MSDOSFSMNT); 152 malloc_type_attach(M_MSDOSFSFAT); 153 malloc_type_attach(M_MSDOSFSTMP); 154 pool_init(&msdosfs_denode_pool, sizeof(struct denode), 0, 0, 0, 155 "msdosnopl", &pool_allocator_nointr, IPL_NONE); 156 pool_init(&fh_pool, sizeof(struct fh_node), 0, 0, 0, 157 "msdosfhpl", &pool_allocator_nointr, IPL_NONE); 158 dehashtbl = hashinit(desiredvnodes / 2, HASH_LIST, true, &dehash); 159 rb_tree_init(&fh_rbtree, &fh_rbtree_ops); 160 mutex_init(&msdosfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE); 161 mutex_init(&fh_lock, MUTEX_DEFAULT, IPL_NONE); 162 mutex_init(&msdosfs_hashlock, MUTEX_DEFAULT, IPL_NONE); 163 } 164 165 /* 166 * Reinitialize inode hash table. 167 */ 168 169 void 170 msdosfs_reinit(void) 171 { 172 struct denode *dep; 173 struct ihashhead *oldhash, *hash; 174 u_long oldmask, mask, val; 175 int i; 176 177 hash = hashinit(desiredvnodes / 2, HASH_LIST, true, &mask); 178 179 mutex_enter(&msdosfs_ihash_lock); 180 oldhash = dehashtbl; 181 oldmask = dehash; 182 dehashtbl = hash; 183 dehash = mask; 184 for (i = 0; i <= oldmask; i++) { 185 while ((dep = LIST_FIRST(&oldhash[i])) != NULL) { 186 LIST_REMOVE(dep, de_hash); 187 val = DEHASH(dep->de_dev, dep->de_dirclust, 188 dep->de_diroffset); 189 LIST_INSERT_HEAD(&hash[val], dep, de_hash); 190 } 191 } 192 mutex_exit(&msdosfs_ihash_lock); 193 hashdone(oldhash, HASH_LIST, oldmask); 194 } 195 196 void 197 msdosfs_done(void) 198 { 199 hashdone(dehashtbl, HASH_LIST, dehash); 200 pool_destroy(&msdosfs_denode_pool); 201 pool_destroy(&fh_pool); 202 mutex_destroy(&msdosfs_ihash_lock); 203 mutex_destroy(&fh_lock); 204 mutex_destroy(&msdosfs_hashlock); 205 malloc_type_detach(M_MSDOSFSTMP); 206 malloc_type_detach(M_MSDOSFSFAT); 207 malloc_type_detach(M_MSDOSFSMNT); 208 } 209 210 static struct denode * 211 msdosfs_hashget(dev_t dev, u_long dirclust, u_long diroff, int flags) 212 { 213 struct denode *dep; 214 struct vnode *vp; 215 216 loop: 217 mutex_enter(&msdosfs_ihash_lock); 218 LIST_FOREACH(dep, &dehashtbl[DEHASH(dev, dirclust, diroff)], de_hash) { 219 if (dirclust == dep->de_dirclust && 220 diroff == dep->de_diroffset && 221 dev == dep->de_dev && 222 dep->de_refcnt != 0) { 223 vp = DETOV(dep); 224 if (flags == 0) { 225 mutex_exit(&msdosfs_ihash_lock); 226 } else { 227 mutex_enter(vp->v_interlock); 228 mutex_exit(&msdosfs_ihash_lock); 229 if (vget(vp, flags)) 230 goto loop; 231 } 232 return (dep); 233 } 234 } 235 mutex_exit(&msdosfs_ihash_lock); 236 return (NULL); 237 } 238 239 static void 240 msdosfs_hashins(struct denode *dep) 241 { 242 struct ihashhead *depp; 243 int val; 244 245 KASSERT(mutex_owned(&msdosfs_hashlock)); 246 247 mutex_enter(&msdosfs_ihash_lock); 248 val = DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset); 249 depp = &dehashtbl[val]; 250 LIST_INSERT_HEAD(depp, dep, de_hash); 251 mutex_exit(&msdosfs_ihash_lock); 252 } 253 254 static void 255 msdosfs_hashrem(struct denode *dep) 256 { 257 mutex_enter(&msdosfs_ihash_lock); 258 LIST_REMOVE(dep, de_hash); 259 mutex_exit(&msdosfs_ihash_lock); 260 } 261 262 /* 263 * If deget() succeeds it returns with the gotten denode locked(). 264 * 265 * pmp - address of msdosfsmount structure of the filesystem containing 266 * the denode of interest. The pm_dev field and the address of 267 * the msdosfsmount structure are used. 268 * dirclust - which cluster bp contains, if dirclust is 0 (root directory) 269 * diroffset is relative to the beginning of the root directory, 270 * otherwise it is cluster relative. 271 * diroffset - offset past begin of cluster of denode we want 272 * depp - returns the address of the gotten denode. 273 */ 274 int 275 deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode **depp) 276 /* pmp: so we know the maj/min number */ 277 /* dirclust: cluster this dir entry came from */ 278 /* diroffset: index of entry within the cluster */ 279 /* depp: returns the addr of the gotten denode */ 280 { 281 int error; 282 extern int (**msdosfs_vnodeop_p)(void *); 283 struct direntry *direntptr; 284 struct denode *ldep; 285 struct vnode *nvp; 286 struct buf *bp; 287 288 #ifdef MSDOSFS_DEBUG 289 printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n", 290 pmp, dirclust, diroffset, depp); 291 #endif 292 293 /* 294 * On FAT32 filesystems, root is a (more or less) normal 295 * directory 296 */ 297 if (FAT32(pmp) && dirclust == MSDOSFSROOT) 298 dirclust = pmp->pm_rootdirblk; 299 300 /* 301 * See if the denode is in the denode cache. Use the location of 302 * the directory entry to compute the hash value. For subdir use 303 * address of "." entry. For root dir (if not FAT32) use cluster 304 * MSDOSFSROOT, offset MSDOSFSROOT_OFS 305 * 306 * NOTE: The check for de_refcnt > 0 below insures the denode being 307 * examined does not represent an unlinked but still open file. 308 * These files are not to be accessible even when the directory 309 * entry that represented the file happens to be reused while the 310 * deleted file is still open. 311 */ 312 retry: 313 ldep = msdosfs_hashget(pmp->pm_dev, dirclust, diroffset, LK_EXCLUSIVE); 314 if (ldep) { 315 *depp = ldep; 316 return (0); 317 } 318 319 /* 320 * Directory entry was not in cache, have to create a vnode and 321 * copy it from the passed disk buffer. 322 */ 323 error = getnewvnode(VT_MSDOSFS, pmp->pm_mountp, msdosfs_vnodeop_p, 324 NULL, &nvp); 325 if (error) { 326 *depp = 0; 327 return (error); 328 } 329 ldep = pool_get(&msdosfs_denode_pool, PR_WAITOK); 330 331 /* 332 * If someone beat us to it, put back the freshly allocated 333 * vnode/inode pair and retry. 334 */ 335 mutex_enter(&msdosfs_hashlock); 336 if (msdosfs_hashget(pmp->pm_dev, dirclust, diroffset, 0)) { 337 mutex_exit(&msdosfs_hashlock); 338 ungetnewvnode(nvp); 339 pool_put(&msdosfs_denode_pool, ldep); 340 goto retry; 341 } 342 memset(ldep, 0, sizeof *ldep); 343 nvp->v_data = ldep; 344 ldep->de_vnode = nvp; 345 ldep->de_flag = 0; 346 ldep->de_devvp = 0; 347 ldep->de_lockf = 0; 348 ldep->de_dev = pmp->pm_dev; 349 ldep->de_dirclust = dirclust; 350 ldep->de_diroffset = diroffset; 351 fc_purge(ldep, 0); /* init the FAT cache for this denode */ 352 353 /* 354 * Insert the denode into the hash queue and lock the denode so it 355 * can't be accessed until we've read it in and have done what we 356 * need to it. 357 */ 358 vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY); 359 genfs_node_init(nvp, &msdosfs_genfsops); 360 msdosfs_hashins(ldep); 361 mutex_exit(&msdosfs_hashlock); 362 363 ldep->de_pmp = pmp; 364 ldep->de_devvp = pmp->pm_devvp; 365 ldep->de_refcnt = 1; 366 /* 367 * Copy the directory entry into the denode area of the vnode. 368 */ 369 if ((dirclust == MSDOSFSROOT 370 || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) 371 && diroffset == MSDOSFSROOT_OFS) { 372 /* 373 * Directory entry for the root directory. There isn't one, 374 * so we manufacture one. We should probably rummage 375 * through the root directory and find a label entry (if it 376 * exists), and then use the time and date from that entry 377 * as the time and date for the root denode. 378 */ 379 nvp->v_vflag |= VV_ROOT; /* should be further down XXX */ 380 381 ldep->de_Attributes = ATTR_DIRECTORY; 382 if (FAT32(pmp)) 383 ldep->de_StartCluster = pmp->pm_rootdirblk; 384 /* de_FileSize will be filled in further down */ 385 else { 386 ldep->de_StartCluster = MSDOSFSROOT; 387 ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec; 388 } 389 /* 390 * fill in time and date so that dos2unixtime() doesn't 391 * spit up when called from msdosfs_getattr() with root 392 * denode 393 */ 394 ldep->de_CHun = 0; 395 ldep->de_CTime = 0x0000; /* 00:00:00 */ 396 ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT) 397 | (1 << DD_DAY_SHIFT); 398 /* Jan 1, 1980 */ 399 ldep->de_ADate = ldep->de_CDate; 400 ldep->de_MTime = ldep->de_CTime; 401 ldep->de_MDate = ldep->de_CDate; 402 /* leave the other fields as garbage */ 403 } else { 404 error = readep(pmp, dirclust, diroffset, &bp, &direntptr); 405 if (error) { 406 ldep->de_devvp = NULL; 407 ldep->de_Name[0] = SLOT_DELETED; 408 vput(nvp); 409 return (error); 410 } 411 DE_INTERNALIZE(ldep, direntptr); 412 brelse(bp, 0); 413 } 414 415 /* 416 * Fill in a few fields of the vnode and finish filling in the 417 * denode. Then return the address of the found denode. 418 */ 419 if (ldep->de_Attributes & ATTR_DIRECTORY) { 420 /* 421 * Since DOS directory entries that describe directories 422 * have 0 in the filesize field, we take this opportunity 423 * to find out the length of the directory and plug it into 424 * the denode structure. 425 */ 426 u_long size; 427 428 nvp->v_type = VDIR; 429 if (ldep->de_StartCluster != MSDOSFSROOT) { 430 error = pcbmap(ldep, CLUST_END, 0, &size, 0); 431 if (error == E2BIG) { 432 ldep->de_FileSize = de_cn2off(pmp, size); 433 error = 0; 434 } else 435 printf("deget(): pcbmap returned %d\n", error); 436 } 437 } else 438 nvp->v_type = VREG; 439 vref(ldep->de_devvp); 440 *depp = ldep; 441 uvm_vnp_setsize(nvp, ldep->de_FileSize); 442 return (0); 443 } 444 445 int 446 deupdat(struct denode *dep, int waitfor) 447 { 448 449 return (msdosfs_update(DETOV(dep), NULL, NULL, 450 waitfor ? UPDATE_WAIT : 0)); 451 } 452 453 /* 454 * Truncate the file described by dep to the length specified by length. 455 */ 456 int 457 detrunc(struct denode *dep, u_long length, int flags, kauth_cred_t cred) 458 { 459 int error; 460 int allerror; 461 u_long eofentry; 462 u_long chaintofree = 0; 463 daddr_t bn, lastblock; 464 int boff; 465 int isadir = dep->de_Attributes & ATTR_DIRECTORY; 466 struct buf *bp; 467 struct msdosfsmount *pmp = dep->de_pmp; 468 469 #ifdef MSDOSFS_DEBUG 470 printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags); 471 #endif 472 473 /* 474 * Disallow attempts to truncate the root directory since it is of 475 * fixed size. That's just the way dos filesystems are. We use 476 * the VROOT bit in the vnode because checking for the directory 477 * bit and a startcluster of 0 in the denode is not adequate to 478 * recognize the root directory at this point in a file or 479 * directory's life. 480 */ 481 if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) { 482 printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n", 483 dep->de_dirclust, dep->de_diroffset); 484 return (EINVAL); 485 } 486 487 uvm_vnp_setsize(DETOV(dep), length); 488 489 if (dep->de_FileSize < length) 490 return (deextend(dep, length, cred)); 491 lastblock = de_clcount(pmp, length) - 1; 492 493 /* 494 * If the desired length is 0 then remember the starting cluster of 495 * the file and set the StartCluster field in the directory entry 496 * to 0. If the desired length is not zero, then get the number of 497 * the last cluster in the shortened file. Then get the number of 498 * the first cluster in the part of the file that is to be freed. 499 * Then set the next cluster pointer in the last cluster of the 500 * file to CLUST_EOFE. 501 */ 502 if (length == 0) { 503 chaintofree = dep->de_StartCluster; 504 dep->de_StartCluster = 0; 505 eofentry = ~0; 506 } else { 507 error = pcbmap(dep, lastblock, 0, &eofentry, 0); 508 if (error) { 509 #ifdef MSDOSFS_DEBUG 510 printf("detrunc(): pcbmap fails %d\n", error); 511 #endif 512 return (error); 513 } 514 } 515 516 /* 517 * If the new length is not a multiple of the cluster size then we 518 * must zero the tail end of the new last cluster in case it 519 * becomes part of the file again because of a seek. 520 */ 521 if ((boff = length & pmp->pm_crbomask) != 0) { 522 if (isadir) { 523 bn = cntobn(pmp, eofentry); 524 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 525 pmp->pm_bpcluster, NOCRED, B_MODIFY, &bp); 526 if (error) { 527 #ifdef MSDOSFS_DEBUG 528 printf("detrunc(): bread fails %d\n", error); 529 #endif 530 return (error); 531 } 532 memset((char *)bp->b_data + boff, 0, 533 pmp->pm_bpcluster - boff); 534 if (flags & IO_SYNC) 535 bwrite(bp); 536 else 537 bdwrite(bp); 538 } else { 539 ubc_zerorange(&DETOV(dep)->v_uobj, length, 540 pmp->pm_bpcluster - boff, 541 UBC_UNMAP_FLAG(DETOV(dep))); 542 } 543 } 544 545 /* 546 * Write out the updated directory entry. Even if the update fails 547 * we free the trailing clusters. 548 */ 549 dep->de_FileSize = length; 550 if (!isadir) 551 dep->de_flag |= DE_UPDATE|DE_MODIFIED; 552 vtruncbuf(DETOV(dep), lastblock + 1, 0, 0); 553 allerror = deupdat(dep, 1); 554 #ifdef MSDOSFS_DEBUG 555 printf("detrunc(): allerror %d, eofentry %lu\n", 556 allerror, eofentry); 557 #endif 558 559 fc_purge(dep, lastblock + 1); 560 561 /* 562 * If we need to break the cluster chain for the file then do it 563 * now. 564 */ 565 if (eofentry != ~0) { 566 error = fatentry(FAT_GET_AND_SET, pmp, eofentry, 567 &chaintofree, CLUST_EOFE); 568 if (error) { 569 #ifdef MSDOSFS_DEBUG 570 printf("detrunc(): fatentry errors %d\n", error); 571 #endif 572 return (error); 573 } 574 fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1), 575 eofentry); 576 } 577 578 /* 579 * Now free the clusters removed from the file because of the 580 * truncation. 581 */ 582 if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask)) 583 freeclusterchain(pmp, chaintofree); 584 585 return (allerror); 586 } 587 588 /* 589 * Extend the file described by dep to length specified by length. 590 */ 591 int 592 deextend(struct denode *dep, u_long length, kauth_cred_t cred) 593 { 594 struct msdosfsmount *pmp = dep->de_pmp; 595 u_long count, osize; 596 int error; 597 598 /* 599 * The root of a DOS filesystem cannot be extended. 600 */ 601 if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) 602 return (EINVAL); 603 604 /* 605 * Directories cannot be extended. 606 */ 607 if (dep->de_Attributes & ATTR_DIRECTORY) 608 return (EISDIR); 609 610 if (length <= dep->de_FileSize) 611 panic("deextend: file too large"); 612 613 /* 614 * Compute the number of clusters to allocate. 615 */ 616 count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize); 617 if (count > 0) { 618 if (count > pmp->pm_freeclustercount) 619 return (ENOSPC); 620 error = extendfile(dep, count, NULL, NULL, DE_CLEAR); 621 if (error) { 622 /* truncate the added clusters away again */ 623 (void) detrunc(dep, dep->de_FileSize, 0, cred); 624 return (error); 625 } 626 } 627 628 /* 629 * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a 630 * memset(); we set the write size so ubc won't read in file data that 631 * is zero'd later. 632 */ 633 osize = dep->de_FileSize; 634 dep->de_FileSize = length; 635 uvm_vnp_setwritesize(DETOV(dep), (voff_t)dep->de_FileSize); 636 dep->de_flag |= DE_UPDATE|DE_MODIFIED; 637 ubc_zerorange(&DETOV(dep)->v_uobj, (off_t)osize, 638 (size_t)(round_page(dep->de_FileSize) - osize), 639 UBC_UNMAP_FLAG(DETOV(dep))); 640 uvm_vnp_setsize(DETOV(dep), (voff_t)dep->de_FileSize); 641 return (deupdat(dep, 1)); 642 } 643 644 /* 645 * Move a denode to its correct hash queue after the file it represents has 646 * been moved to a new directory. 647 */ 648 void 649 reinsert(struct denode *dep) 650 { 651 /* 652 * Fix up the denode cache. If the denode is for a directory, 653 * there is nothing to do since the hash is based on the starting 654 * cluster of the directory file and that hasn't changed. If for a 655 * file the hash is based on the location of the directory entry, 656 * so we must remove it from the cache and re-enter it with the 657 * hash based on the new location of the directory entry. 658 */ 659 if (dep->de_Attributes & ATTR_DIRECTORY) 660 return; 661 mutex_enter(&msdosfs_hashlock); 662 msdosfs_hashrem(dep); 663 msdosfs_hashins(dep); 664 mutex_exit(&msdosfs_hashlock); 665 } 666 667 int 668 msdosfs_reclaim(void *v) 669 { 670 struct vop_reclaim_args /* { 671 struct vnode *a_vp; 672 } */ *ap = v; 673 struct vnode *vp = ap->a_vp; 674 struct denode *dep = VTODE(vp); 675 676 #ifdef MSDOSFS_DEBUG 677 printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n", 678 dep, dep->de_Name, dep->de_refcnt); 679 #endif 680 681 if (prtactive && vp->v_usecount > 1) 682 vprint("msdosfs_reclaim(): pushing active", vp); 683 /* 684 * Remove the denode from its hash chain. 685 */ 686 msdosfs_hashrem(dep); 687 /* 688 * Purge old data structures associated with the denode. 689 */ 690 if (dep->de_devvp) { 691 vrele(dep->de_devvp); 692 dep->de_devvp = 0; 693 } 694 #if 0 /* XXX */ 695 dep->de_flag = 0; 696 #endif 697 genfs_node_destroy(vp); 698 pool_put(&msdosfs_denode_pool, dep); 699 vp->v_data = NULL; 700 return (0); 701 } 702 703 int 704 msdosfs_inactive(void *v) 705 { 706 struct vop_inactive_args /* { 707 struct vnode *a_vp; 708 bool *a_recycle; 709 } */ *ap = v; 710 struct vnode *vp = ap->a_vp; 711 struct mount *mp = vp->v_mount; 712 struct denode *dep = VTODE(vp); 713 int error = 0; 714 715 #ifdef MSDOSFS_DEBUG 716 printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep, dep->de_Name[0]); 717 #endif 718 719 fstrans_start(mp, FSTRANS_LAZY); 720 /* 721 * Get rid of denodes related to stale file handles. 722 */ 723 if (dep->de_Name[0] == SLOT_DELETED) 724 goto out; 725 726 /* 727 * If the file has been deleted and it is on a read/write 728 * filesystem, then truncate the file, and mark the directory slot 729 * as empty. (This may not be necessary for the dos filesystem.) 730 */ 731 #ifdef MSDOSFS_DEBUG 732 printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x %s\n", 733 dep, dep->de_refcnt, vp->v_mount->mnt_flag, 734 (vp->v_mount->mnt_flag & MNT_RDONLY) ? "MNT_RDONLY" : ""); 735 #endif 736 if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 737 if (dep->de_FileSize != 0) { 738 error = detrunc(dep, (u_long)0, 0, NOCRED); 739 } 740 dep->de_Name[0] = SLOT_DELETED; 741 msdosfs_fh_remove(dep->de_pmp, 742 dep->de_dirclust, dep->de_diroffset); 743 } 744 deupdat(dep, 0); 745 out: 746 /* 747 * If we are done with the denode, reclaim it 748 * so that it can be reused immediately. 749 */ 750 #ifdef MSDOSFS_DEBUG 751 printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", 752 vp->v_usecount, dep->de_Name[0]); 753 #endif 754 *ap->a_recycle = (dep->de_Name[0] == SLOT_DELETED); 755 VOP_UNLOCK(vp); 756 fstrans_done(mp); 757 return (error); 758 } 759 760 int 761 msdosfs_gop_alloc(struct vnode *vp, off_t off, 762 off_t len, int flags, kauth_cred_t cred) 763 { 764 return 0; 765 } 766 767 void 768 msdosfs_gop_markupdate(struct vnode *vp, int flags) 769 { 770 u_long mask = 0; 771 772 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 773 mask = DE_ACCESS; 774 } 775 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 776 mask |= DE_UPDATE; 777 } 778 if (mask) { 779 struct denode *dep = VTODE(vp); 780 781 dep->de_flag |= mask; 782 } 783 } 784 785 int 786 msdosfs_fh_enter(struct msdosfsmount *pmp, 787 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 788 { 789 struct fh_key fhkey; 790 struct fh_node *fhp; 791 792 fhkey.fhk_mount = pmp; 793 fhkey.fhk_dircluster = dircluster; 794 fhkey.fhk_diroffset = diroffset; 795 796 mutex_enter(&fh_lock); 797 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 798 if (fhp == NULL) { 799 mutex_exit(&fh_lock); 800 fhp = pool_get(&fh_pool, PR_WAITOK); 801 mutex_enter(&fh_lock); 802 fhp->fh_key = fhkey; 803 fhp->fh_gen = fh_generation++; 804 rb_tree_insert_node(&fh_rbtree, fhp); 805 } 806 *genp = fhp->fh_gen; 807 mutex_exit(&fh_lock); 808 return 0; 809 } 810 811 int 812 msdosfs_fh_remove(struct msdosfsmount *pmp, 813 uint32_t dircluster, uint32_t diroffset) 814 { 815 struct fh_key fhkey; 816 struct fh_node *fhp; 817 818 fhkey.fhk_mount = pmp; 819 fhkey.fhk_dircluster = dircluster; 820 fhkey.fhk_diroffset = diroffset; 821 822 mutex_enter(&fh_lock); 823 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 824 if (fhp == NULL) { 825 mutex_exit(&fh_lock); 826 return ENOENT; 827 } 828 rb_tree_remove_node(&fh_rbtree, fhp); 829 mutex_exit(&fh_lock); 830 pool_put(&fh_pool, fhp); 831 return 0; 832 } 833 834 int 835 msdosfs_fh_lookup(struct msdosfsmount *pmp, 836 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 837 { 838 struct fh_key fhkey; 839 struct fh_node *fhp; 840 841 fhkey.fhk_mount = pmp; 842 fhkey.fhk_dircluster = dircluster; 843 fhkey.fhk_diroffset = diroffset; 844 845 mutex_enter(&fh_lock); 846 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 847 if (fhp == NULL) { 848 mutex_exit(&fh_lock); 849 return ESTALE; 850 } 851 *genp = fhp->fh_gen; 852 mutex_exit(&fh_lock); 853 return 0; 854 } 855 856 void 857 msdosfs_fh_destroy(struct msdosfsmount *pmp) 858 { 859 struct fh_key fhkey; 860 struct fh_node *fhp, *nfhp; 861 862 fhkey.fhk_mount = pmp; 863 fhkey.fhk_dircluster = 0; 864 fhkey.fhk_diroffset = 0; 865 866 mutex_enter(&fh_lock); 867 for (fhp = rb_tree_find_node_geq(&fh_rbtree, &fhkey); 868 fhp != NULL && fhp->fh_mount == pmp; fhp = nfhp) { 869 nfhp = rb_tree_iterate(&fh_rbtree, fhp, RB_DIR_RIGHT); 870 rb_tree_remove_node(&fh_rbtree, fhp); 871 pool_put(&fh_pool, fhp); 872 } 873 #ifdef DIAGNOSTIC 874 RB_TREE_FOREACH(fhp, &fh_rbtree) { 875 KASSERT(fhp->fh_mount != pmp); 876 } 877 #endif 878 mutex_exit(&fh_lock); 879 } 880