1 /* $NetBSD: msdosfs_denode.c,v 1.49 2014/05/30 08:42:35 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.49 2014/05/30 08:42:35 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 mount *mp = vp->v_mount; 675 struct denode *dep = VTODE(vp); 676 677 fstrans_start(mp, FSTRANS_LAZY); 678 #ifdef MSDOSFS_DEBUG 679 printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n", 680 dep, dep->de_Name, dep->de_refcnt); 681 #endif 682 683 if (prtactive && vp->v_usecount > 1) 684 vprint("msdosfs_reclaim(): pushing active", vp); 685 /* 686 * Remove the denode from its hash chain. 687 */ 688 msdosfs_hashrem(dep); 689 /* 690 * Purge old data structures associated with the denode. 691 */ 692 if (dep->de_devvp) { 693 vrele(dep->de_devvp); 694 dep->de_devvp = 0; 695 } 696 #if 0 /* XXX */ 697 dep->de_flag = 0; 698 #endif 699 /* 700 * To interlock with msdosfs_sync(). 701 */ 702 genfs_node_destroy(vp); 703 mutex_enter(vp->v_interlock); 704 vp->v_data = NULL; 705 mutex_exit(vp->v_interlock); 706 pool_put(&msdosfs_denode_pool, dep); 707 fstrans_done(mp); 708 return (0); 709 } 710 711 int 712 msdosfs_inactive(void *v) 713 { 714 struct vop_inactive_args /* { 715 struct vnode *a_vp; 716 bool *a_recycle; 717 } */ *ap = v; 718 struct vnode *vp = ap->a_vp; 719 struct mount *mp = vp->v_mount; 720 struct denode *dep = VTODE(vp); 721 int error = 0; 722 723 #ifdef MSDOSFS_DEBUG 724 printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep, dep->de_Name[0]); 725 #endif 726 727 fstrans_start(mp, FSTRANS_LAZY); 728 /* 729 * Get rid of denodes related to stale file handles. 730 */ 731 if (dep->de_Name[0] == SLOT_DELETED) 732 goto out; 733 734 /* 735 * If the file has been deleted and it is on a read/write 736 * filesystem, then truncate the file, and mark the directory slot 737 * as empty. (This may not be necessary for the dos filesystem.) 738 */ 739 #ifdef MSDOSFS_DEBUG 740 printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x %s\n", 741 dep, dep->de_refcnt, vp->v_mount->mnt_flag, 742 (vp->v_mount->mnt_flag & MNT_RDONLY) ? "MNT_RDONLY" : ""); 743 #endif 744 if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 745 if (dep->de_FileSize != 0) { 746 error = detrunc(dep, (u_long)0, 0, NOCRED); 747 } 748 dep->de_Name[0] = SLOT_DELETED; 749 msdosfs_fh_remove(dep->de_pmp, 750 dep->de_dirclust, dep->de_diroffset); 751 } 752 deupdat(dep, 0); 753 out: 754 /* 755 * If we are done with the denode, reclaim it 756 * so that it can be reused immediately. 757 */ 758 #ifdef MSDOSFS_DEBUG 759 printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", 760 vp->v_usecount, dep->de_Name[0]); 761 #endif 762 *ap->a_recycle = (dep->de_Name[0] == SLOT_DELETED); 763 VOP_UNLOCK(vp); 764 fstrans_done(mp); 765 return (error); 766 } 767 768 int 769 msdosfs_gop_alloc(struct vnode *vp, off_t off, 770 off_t len, int flags, kauth_cred_t cred) 771 { 772 return 0; 773 } 774 775 void 776 msdosfs_gop_markupdate(struct vnode *vp, int flags) 777 { 778 u_long mask = 0; 779 780 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 781 mask = DE_ACCESS; 782 } 783 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 784 mask |= DE_UPDATE; 785 } 786 if (mask) { 787 struct denode *dep = VTODE(vp); 788 789 dep->de_flag |= mask; 790 } 791 } 792 793 int 794 msdosfs_fh_enter(struct msdosfsmount *pmp, 795 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 796 { 797 struct fh_key fhkey; 798 struct fh_node *fhp; 799 800 fhkey.fhk_mount = pmp; 801 fhkey.fhk_dircluster = dircluster; 802 fhkey.fhk_diroffset = diroffset; 803 804 mutex_enter(&fh_lock); 805 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 806 if (fhp == NULL) { 807 mutex_exit(&fh_lock); 808 fhp = pool_get(&fh_pool, PR_WAITOK); 809 mutex_enter(&fh_lock); 810 fhp->fh_key = fhkey; 811 fhp->fh_gen = fh_generation++; 812 rb_tree_insert_node(&fh_rbtree, fhp); 813 } 814 *genp = fhp->fh_gen; 815 mutex_exit(&fh_lock); 816 return 0; 817 } 818 819 int 820 msdosfs_fh_remove(struct msdosfsmount *pmp, 821 uint32_t dircluster, uint32_t diroffset) 822 { 823 struct fh_key fhkey; 824 struct fh_node *fhp; 825 826 fhkey.fhk_mount = pmp; 827 fhkey.fhk_dircluster = dircluster; 828 fhkey.fhk_diroffset = diroffset; 829 830 mutex_enter(&fh_lock); 831 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 832 if (fhp == NULL) { 833 mutex_exit(&fh_lock); 834 return ENOENT; 835 } 836 rb_tree_remove_node(&fh_rbtree, fhp); 837 mutex_exit(&fh_lock); 838 pool_put(&fh_pool, fhp); 839 return 0; 840 } 841 842 int 843 msdosfs_fh_lookup(struct msdosfsmount *pmp, 844 uint32_t dircluster, uint32_t diroffset, uint32_t *genp) 845 { 846 struct fh_key fhkey; 847 struct fh_node *fhp; 848 849 fhkey.fhk_mount = pmp; 850 fhkey.fhk_dircluster = dircluster; 851 fhkey.fhk_diroffset = diroffset; 852 853 mutex_enter(&fh_lock); 854 fhp = rb_tree_find_node(&fh_rbtree, &fhkey); 855 if (fhp == NULL) { 856 mutex_exit(&fh_lock); 857 return ESTALE; 858 } 859 *genp = fhp->fh_gen; 860 mutex_exit(&fh_lock); 861 return 0; 862 } 863 864 void 865 msdosfs_fh_destroy(struct msdosfsmount *pmp) 866 { 867 struct fh_key fhkey; 868 struct fh_node *fhp, *nfhp; 869 870 fhkey.fhk_mount = pmp; 871 fhkey.fhk_dircluster = 0; 872 fhkey.fhk_diroffset = 0; 873 874 mutex_enter(&fh_lock); 875 for (fhp = rb_tree_find_node_geq(&fh_rbtree, &fhkey); 876 fhp != NULL && fhp->fh_mount == pmp; fhp = nfhp) { 877 nfhp = rb_tree_iterate(&fh_rbtree, fhp, RB_DIR_RIGHT); 878 rb_tree_remove_node(&fh_rbtree, fhp); 879 pool_put(&fh_pool, fhp); 880 } 881 #ifdef DIAGNOSTIC 882 RB_TREE_FOREACH(fhp, &fh_rbtree) { 883 KASSERT(fhp->fh_mount != pmp); 884 } 885 #endif 886 mutex_exit(&fh_lock); 887 } 888