1 /* $FreeBSD$ */
2 /* $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $ */
3
4 /*-
5 * SPDX-License-Identifier: BSD-4-Clause
6 *
7 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
8 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
9 * All rights reserved.
10 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by TooLs GmbH.
23 * 4. The name of TooLs GmbH may not be used to endorse or promote products
24 * derived from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 /*-
38 * Written by Paul Popelka (paulp@uts.amdahl.com)
39 *
40 * You can do anything you want with this software, just don't say you wrote
41 * it, and don't remove this notice.
42 *
43 * This software is provided "as is".
44 *
45 * The author supplies this software to be publicly redistributed on the
46 * understanding that the author is not responsible for the correct
47 * functioning of this software in any circumstances and is not liable for
48 * any damages caused by this software.
49 *
50 * October 1992
51 */
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/buf.h>
56 #include <sys/kernel.h>
57 #include <sys/malloc.h>
58 #include <sys/proc.h>
59 #include <sys/mount.h>
60 #include <sys/vnode.h>
61 #include <sys/time.h>
62
63 #include <vm/vm.h>
64 #include <vm/vm_extern.h>
65 #include <vm/vm_page2.h>
66
67 #include <sys/buf2.h>
68
69 #include <vfs/msdosfs/bpb.h>
70 #include <vfs/msdosfs/direntry.h>
71 #include <vfs/msdosfs/denode.h>
72 #include <vfs/msdosfs/fat.h>
73 #include <vfs/msdosfs/msdosfsmount.h>
74
75 static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");
76
77 /*
78 * Hash table caching denode instances.
79 *
80 * denodes are keyed by the disk location (cluster num, entry offset) of the
81 * directory entry of the file they represent.
82 *
83 * denodes representing deleted but still opened files are left in this cache
84 * until reclaimed. Deleted directory entries can be reused when files are
85 * renamed or new files created. As a consequence, several denodes associated
86 * with the same entry may coexist in this cache as long as a single one of
87 * them map to an existing file (de_refcnt > 0).
88 *
89 * R/w access to this cache is protected by dehash_token.
90 */
91 static struct denode **dehashtbl;
92 static u_long dehash; /* size of hash table - 1 */
93 static struct lwkt_token dehash_token;
94
95 #define DEHASH(dev, dcl, doff) (dehashtbl[(minor(dev) + (dcl) + (doff) / \
96 sizeof(struct direntry)) & dehash])
97
98 /*ARGSUSED*/
99 int
msdosfs_init(struct vfsconf * vfsp)100 msdosfs_init(struct vfsconf *vfsp)
101 {
102 dehash = vfs_inodehashsize();
103 dehashtbl = kmalloc(sizeof(void *) * dehash,
104 M_MSDOSFSMNT, M_WAITOK|M_ZERO);
105 --dehash;
106 lwkt_token_init(&dehash_token, "msdosihash");
107
108 return (0);
109 }
110
111 int
msdosfs_uninit(struct vfsconf * vfsp)112 msdosfs_uninit(struct vfsconf *vfsp)
113 {
114 if (dehashtbl)
115 kfree(dehashtbl, M_MSDOSFSMNT);
116 return (0);
117 }
118
119 static struct denode *
msdosfs_hashget(cdev_t dev,u_long dirclust,u_long diroff)120 msdosfs_hashget(cdev_t dev, u_long dirclust, u_long diroff)
121 {
122 struct denode *dep;
123 struct vnode *vp;
124
125 lwkt_gettoken(&dehash_token);
126 loop:
127 for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next) {
128 if (dirclust != dep->de_dirclust
129 || diroff != dep->de_diroffset
130 || dev != dep->de_dev
131 || dep->de_refcnt <= 0) {
132 continue;
133 }
134 vp = DETOV(dep);
135 if (vget(vp, LK_EXCLUSIVE))
136 goto loop;
137
138 /*
139 * We must check to see if the inode has been ripped
140 * out from under us after blocking.
141 */
142 for (dep = DEHASH(dev, dirclust, diroff); dep;
143 dep = dep->de_next) {
144 if (dirclust == dep->de_dirclust
145 && diroff == dep->de_diroffset
146 && dev == dep->de_dev
147 && dep->de_refcnt > 0) {
148 break;
149 }
150 }
151 if (dep == NULL || DETOV(dep) != vp) {
152 vput(vp);
153 goto loop;
154 }
155 lwkt_reltoken(&dehash_token);
156 return (dep);
157 }
158 lwkt_reltoken(&dehash_token);
159 return (NULL);
160 }
161
162 /*
163 * Try to insert specified denode into the hash table. Return 0 on success
164 * and EBUSY if there is already a denode with the same key.
165 */
166 static
167 int
msdosfs_hashins(struct denode * dep)168 msdosfs_hashins(struct denode *dep)
169 {
170 struct denode **depp, *deq;
171
172 lwkt_gettoken(&dehash_token);
173 depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
174 while ((deq = *depp) != NULL) {
175 if (deq->de_dev == dep->de_dev &&
176 deq->de_dirclust == dep->de_dirclust &&
177 deq->de_diroffset == dep->de_diroffset &&
178 deq->de_refcnt > 0) {
179 lwkt_reltoken(&dehash_token);
180 return(EBUSY);
181 }
182 depp = &deq->de_next;
183 }
184 dep->de_next = NULL;
185 *depp = dep;
186 lwkt_reltoken(&dehash_token);
187 return(0);
188 }
189
190 static
191 void
msdosfs_hashrem(struct denode * dep)192 msdosfs_hashrem(struct denode *dep)
193 {
194 struct denode **depp, *deq;
195
196 lwkt_gettoken(&dehash_token);
197 depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
198 while ((deq = *depp) != NULL) {
199 if (dep == deq)
200 break;
201 depp = &deq->de_next;
202 }
203 KKASSERT(dep == deq);
204 *depp = dep->de_next;
205 dep->de_next = NULL;
206 lwkt_reltoken(&dehash_token);
207 }
208
209 void
msdosfs_reinsert(struct denode * ip,u_long new_dirclust,u_long new_diroffset)210 msdosfs_reinsert(struct denode *ip, u_long new_dirclust, u_long new_diroffset)
211 {
212 int error;
213
214 lwkt_gettoken(&dehash_token);
215 msdosfs_hashrem(ip);
216 ip->de_dirclust = new_dirclust;
217 ip->de_diroffset = new_diroffset;
218 error = msdosfs_hashins(ip);
219 KASSERT(!error, ("msdosfs_reinsert: insertion failed %d", error));
220 lwkt_reltoken(&dehash_token);
221 }
222
223 /*
224 * If deget() succeeds it returns with the gotten denode locked().
225 *
226 * pmp - address of msdosfsmount structure of the filesystem containing
227 * the denode of interest. The address of
228 * the msdosfsmount structure are used.
229 * dirclust - which cluster bp contains, if dirclust is 0 (root directory)
230 * diroffset is relative to the beginning of the root directory,
231 * otherwise it is cluster relative.
232 * diroffset - offset past begin of cluster of denode we want
233 * depp - returns the address of the gotten denode.
234 */
235 int
deget(struct msdosfsmount * pmp,u_long dirclust,u_long diroffset,struct denode ** depp)236 deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
237 struct denode **depp)
238 {
239 int error;
240 cdev_t dev = pmp->pm_dev;
241 struct mount *mntp = pmp->pm_mountp;
242 struct direntry *direntptr;
243 struct denode *ldep;
244 struct vnode *nvp;
245 struct buf *bp;
246
247 mprintf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
248 pmp, dirclust, diroffset, depp);
249
250 /*
251 * On FAT32 filesystems, root is a (more or less) normal
252 * directory
253 */
254 if (FAT32(pmp) && dirclust == MSDOSFSROOT)
255 dirclust = pmp->pm_rootdirblk;
256
257 again:
258 /*
259 * See if the denode is in the denode cache. Use the location of
260 * the directory entry to compute the hash value. For subdir use
261 * address of "." entry. For root dir (if not FAT32) use cluster
262 * MSDOSFSROOT, offset MSDOSFSROOT_OFS
263 *
264 * NOTE: The check for de_refcnt > 0 below insures the denode being
265 * examined does not represent an unlinked but still open file.
266 * These files are not to be accessible even when the directory
267 * entry that represented the file happens to be reused while the
268 * deleted file is still open.
269 */
270 ldep = msdosfs_hashget(dev, dirclust, diroffset);
271 if (ldep) {
272 *depp = ldep;
273 return (0);
274 }
275
276 /*
277 * Do the MALLOC before the getnewvnode since doing so afterward
278 * might cause a bogus v_data pointer to get dereferenced
279 * elsewhere if MALLOC should block.
280 */
281 ldep = kmalloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK | M_ZERO);
282
283 /*
284 * Directory entry was not in cache, have to create a vnode and
285 * copy it from the passed disk buffer.
286 */
287
288 /* getnewvnode() does a vref() on the vnode */
289 error = getnewvnode(VT_MSDOSFS, mntp, &nvp, VLKTIMEOUT, 0);
290 if (error) {
291 *depp = NULL;
292 kfree(ldep, M_MSDOSFSNODE);
293 return error;
294 }
295
296 ldep->de_vnode = nvp;
297 ldep->de_flag = 0;
298 ldep->de_devvp = 0;
299 ldep->de_dev = dev;
300 ldep->de_dirclust = dirclust;
301 ldep->de_diroffset = diroffset;
302 fc_purge(ldep, 0); /* init the fat cache for this denode */
303
304 /*
305 * Insert the denode into the hash queue. If a collision occurs
306 * throw away the vnode and try again.
307 */
308 error = msdosfs_hashins(ldep);
309 if (error == EBUSY) {
310 nvp->v_type = VBAD;
311 vx_put(nvp);
312 kfree(ldep, M_MSDOSFSNODE);
313 goto again;
314 } else if (error) {
315 nvp->v_type = VBAD;
316 vx_put(nvp);
317 kfree(ldep, M_MSDOSFSNODE);
318 *depp = NULL;
319 return (EINVAL);
320 }
321 nvp->v_data = ldep;
322 ldep->de_pmp = pmp;
323 ldep->de_refcnt = 1;
324 /*
325 * Copy the directory entry into the denode area of the vnode.
326 */
327 if ((dirclust == MSDOSFSROOT ||
328 (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) &&
329 diroffset == MSDOSFSROOT_OFS) {
330 /*
331 * Directory entry for the root directory. There isn't one,
332 * so we manufacture one. We should probably rummage
333 * through the root directory and find a label entry (if it
334 * exists), and then use the time and date from that entry
335 * as the time and date for the root denode.
336 */
337 vsetflags(nvp, VROOT); /* should be further down XXX */
338
339 ldep->de_Attributes = ATTR_DIRECTORY;
340 ldep->de_LowerCase = 0;
341 if (FAT32(pmp)) {
342 ldep->de_StartCluster = pmp->pm_rootdirblk;
343 /* de_FileSize will be filled in further down */
344 } else {
345 ldep->de_StartCluster = MSDOSFSROOT;
346 ldep->de_FileSize = pmp->pm_rootdirsize * DEV_BSIZE;
347 }
348 /*
349 * fill in time and date so that fattime2timespec() doesn't
350 * spit up when called from msdosfs_getattr() with root
351 * denode
352 */
353 ldep->de_CHun = 0;
354 ldep->de_CTime = 0x0000; /* 00:00:00 */
355 ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
356 | (1 << DD_DAY_SHIFT);
357 /* Jan 1, 1980 */
358 ldep->de_ADate = ldep->de_CDate;
359 ldep->de_MTime = ldep->de_CTime;
360 ldep->de_MDate = ldep->de_CDate;
361 /* leave the other fields as garbage */
362 } else {
363 error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
364 if (error) {
365 /*
366 * The denode does not contain anything useful, so
367 * it would be wrong to leave it on its hash chain.
368 * Arrange for vput() to just forget about it.
369 */
370 ldep->de_Name[0] = SLOT_DELETED;
371 nvp->v_type = VBAD;
372
373 vx_put(nvp);
374 *depp = NULL;
375 return (error);
376 }
377 DE_INTERNALIZE(ldep, direntptr);
378 brelse(bp);
379 }
380
381 /*
382 * Fill in a few fields of the vnode and finish filling in the
383 * denode. Then return the address of the found denode.
384 */
385 if (ldep->de_Attributes & ATTR_DIRECTORY) {
386 /*
387 * Since DOS directory entries that describe directories
388 * have 0 in the filesize field, we take this opportunity
389 * to find out the length of the directory and plug it into
390 * the denode structure.
391 */
392 u_long size;
393
394 /*
395 * XXX it sometimes happens that the "." entry has cluster
396 * number 0 when it shouldn't. Use the actual cluster number
397 * instead of what is written in directory entry.
398 */
399 if (diroffset == 0 && ldep->de_StartCluster != dirclust) {
400 kprintf("deget(): \".\" entry at clust %lu != %lu\n",
401 dirclust, ldep->de_StartCluster);
402 ldep->de_StartCluster = dirclust;
403 }
404
405 nvp->v_type = VDIR;
406 if (ldep->de_StartCluster != MSDOSFSROOT) {
407 error = pcbmap(ldep, 0xffff, NULL, &size, NULL);
408 if (error == E2BIG) {
409 ldep->de_FileSize = de_cn2off(pmp, size);
410 error = 0;
411 } else
412 kprintf("deget(): pcbmap returned %d\n", error);
413 }
414 } else
415 nvp->v_type = VREG;
416
417 ldep->de_modrev = init_va_filerev();
418 ldep->de_devvp = pmp->pm_devvp;
419 vref(ldep->de_devvp);
420 vinitvmio(nvp, ldep->de_FileSize, PAGE_SIZE, -1);
421 /*
422 * Leave nvp locked and refd so the returned inode is effectively
423 * locked and refd.
424 */
425 vx_downgrade(nvp);
426 *depp = ldep;
427 return (0);
428 }
429
430 int
deupdat(struct denode * dep,int waitfor)431 deupdat(struct denode *dep, int waitfor)
432 {
433 struct direntry dir;
434 struct timespec ts;
435 struct buf *bp;
436 struct direntry *dirp;
437 int error;
438
439 if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) {
440 dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS |
441 DE_MODIFIED);
442 return (0);
443 }
444 vfs_timestamp(&ts);
445 DETIMES(dep, &ts, &ts, &ts);
446 if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0)
447 return (0);
448 dep->de_flag &= ~DE_MODIFIED;
449 if (DETOV(dep)->v_flag & VROOT)
450 return (EINVAL);
451 if (dep->de_refcnt <= 0)
452 return (0);
453 error = readde(dep, &bp, &dirp);
454 if (error)
455 return (error);
456 DE_EXTERNALIZE(&dir, dep);
457 if (bcmp(dirp, &dir, sizeof(dir)) == 0) {
458 if (waitfor == 0 || (bp->b_flags & B_DELWRI) == 0) {
459 brelse(bp);
460 return (0);
461 }
462 } else
463 *dirp = dir;
464 if ((DETOV(dep)->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0)
465 bp->b_flags |= B_CLUSTEROK;
466 if (waitfor)
467 error = bwrite(bp);
468 else if (vm_paging_min() || buf_dirty_count_severe())
469 bawrite(bp);
470 else
471 bdwrite(bp);
472 return (error);
473 }
474
475 /*
476 * Truncate the file described by dep to the length specified by length.
477 */
478 int
detrunc(struct denode * dep,u_long length,int flags)479 detrunc(struct denode *dep, u_long length, int flags)
480 {
481 int error;
482 int allerror;
483 u_long eofentry;
484 u_long chaintofree;
485 daddr_t bn;
486 int boff;
487 int isadir = dep->de_Attributes & ATTR_DIRECTORY;
488 struct buf *bp;
489 struct msdosfsmount *pmp = dep->de_pmp;
490
491 mprintf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name,
492 length, flags);
493
494 /*
495 * Disallow attempts to truncate the root directory since it is of
496 * fixed size. That's just the way dos filesystems are. We use
497 * the VROOT bit in the vnode because checking for the directory
498 * bit and a startcluster of 0 in the denode is not adequate to
499 * recognize the root directory at this point in a file or
500 * directory's life.
501 */
502 if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp)) {
503 kprintf("detrunc(): can't truncate root directory, clust %ld, "
504 "offset %ld\n",
505 dep->de_dirclust, dep->de_diroffset);
506 return (EINVAL);
507 }
508
509 if (dep->de_FileSize < length) {
510 vnode_pager_setsize(DETOV(dep), length);
511 return (deextend(dep, length));
512 }
513
514 /*
515 * If the desired length is 0 then remember the starting cluster of
516 * the file and set the StartCluster field in the directory entry
517 * to 0. If the desired length is not zero, then get the number of
518 * the last cluster in the shortened file. Then get the number of
519 * the first cluster in the part of the file that is to be freed.
520 * Then set the next cluster pointer in the last cluster of the
521 * file to CLUST_EOFE.
522 */
523 if (length == 0) {
524 chaintofree = dep->de_StartCluster;
525 dep->de_StartCluster = 0;
526 eofentry = ~0;
527 } else {
528 error = pcbmap(dep, de_clcount(pmp, length) - 1,
529 NULL, &eofentry, NULL);
530 if (error) {
531 mprintf("detrunc(): pcbmap fails %d\n", error);
532 return (error);
533 }
534 }
535
536 fc_purge(dep, de_clcount(pmp, length));
537
538 /*
539 * If the new length is not a multiple of the cluster size then we
540 * must zero the tail end of the new last cluster in case it
541 * becomes part of the file again because of a seek.
542 */
543 if ((boff = length & pmp->pm_crbomask) != 0) {
544 if (isadir) {
545 bn = cntobn(pmp, eofentry);
546 error = bread(pmp->pm_devvp, de_bn2doff(pmp, bn),
547 pmp->pm_bpcluster, &bp);
548 } else {
549 u_long cn = de_cluster(pmp, length);
550 error = bread(DETOV(dep), de_cn2doff(pmp, cn),
551 pmp->pm_bpcluster, &bp);
552 }
553 if (error) {
554 brelse(bp);
555 mprintf("detrunc(): bread fails %d\n", error);
556 return (error);
557 }
558 memset(bp->b_data + boff, 0, pmp->pm_bpcluster - boff);
559 if ((flags & IO_SYNC) != 0)
560 bwrite(bp);
561 else
562 bdwrite(bp);
563 }
564
565 /*
566 * Write out the updated directory entry. Even if the update fails
567 * we free the trailing clusters.
568 */
569 dep->de_FileSize = length;
570 if (!isadir)
571 dep->de_flag |= DE_UPDATE | DE_MODIFIED;
572 allerror = vtruncbuf(DETOV(dep), length, pmp->pm_bpcluster);
573 #ifdef MSDOSFS_DEBUG
574 if (allerror)
575 kprintf("detrunc(): vtruncbuf error %d\n", allerror);
576 #endif
577 error = deupdat(dep, !DOINGASYNC((DETOV(dep))));
578 if (error != 0 && allerror == 0)
579 allerror = error;
580 mprintf("detrunc(): allerror %d, eofentry %lu\n",
581 allerror, eofentry);
582
583 /*
584 * If we need to break the cluster chain for the file then do it
585 * now.
586 */
587 if (eofentry != ~0) {
588 error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
589 &chaintofree, CLUST_EOFE);
590 if (error) {
591 mprintf("detrunc(): fatentry errors %d\n", error);
592 return (error);
593 }
594 fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
595 eofentry);
596 }
597
598 /*
599 * Now free the clusters removed from the file because of the
600 * truncation.
601 */
602 if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
603 freeclusterchain(pmp, chaintofree);
604
605 return (allerror);
606 }
607
608 /*
609 * Extend the file described by dep to length specified by length.
610 */
611 int
deextend(struct denode * dep,u_long length)612 deextend(struct denode *dep, u_long length)
613 {
614 struct msdosfsmount *pmp = dep->de_pmp;
615 u_long count;
616 int error;
617
618 /*
619 * The root of a DOS filesystem cannot be extended.
620 */
621 if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
622 return (EINVAL);
623
624 /*
625 * Directories cannot be extended.
626 */
627 if (dep->de_Attributes & ATTR_DIRECTORY)
628 return (EISDIR);
629
630 if (length <= dep->de_FileSize)
631 panic("deextend: file too large");
632
633 /*
634 * Compute the number of clusters to allocate.
635 */
636 count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
637 if (count > 0) {
638 if (count > pmp->pm_freeclustercount)
639 return (ENOSPC);
640 error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
641 if (error) {
642 /* truncate the added clusters away again */
643 detrunc(dep, dep->de_FileSize, 0);
644 return (error);
645 }
646 }
647 dep->de_FileSize = length;
648 dep->de_flag |= DE_UPDATE | DE_MODIFIED;
649 return (deupdat(dep, !DOINGASYNC(DETOV(dep))));
650 }
651
652 int
msdosfs_reclaim(struct vop_reclaim_args * ap)653 msdosfs_reclaim(struct vop_reclaim_args *ap)
654 {
655 struct vnode *vp = ap->a_vp;
656 struct denode *dep = VTODE(vp);
657
658 mprintf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n",
659 dep, dep ? (char *)dep->de_Name : "?", dep ? dep->de_refcnt : -1);
660
661 if (prtactive && VREFCNT(vp) > 1)
662 vprint("msdosfs_reclaim(): pushing active", vp);
663 /*
664 * Remove the denode from its hash chain.
665 */
666 vp->v_data = NULL;
667 if (dep) {
668 msdosfs_hashrem(dep);
669 if (dep->de_devvp) {
670 vrele(dep->de_devvp);
671 dep->de_devvp = 0;
672 }
673 kfree(dep, M_MSDOSFSNODE);
674 }
675 return (0);
676 }
677
678 int
msdosfs_inactive(struct vop_inactive_args * ap)679 msdosfs_inactive(struct vop_inactive_args *ap)
680 {
681 struct vnode *vp = ap->a_vp;
682 struct denode *dep = VTODE(vp);
683 int error = 0;
684
685 mprintf("msdosfs_inactive(): dep %p, de_Name[0] %x\n",
686 dep, (dep ? dep->de_Name[0] : 0));
687
688 if (prtactive && VREFCNT(vp) > 1)
689 vprint("msdosfs_inactive(): pushing active", vp);
690
691 /*
692 * Ignore denodes related to stale file handles.
693 */
694 if (dep == NULL || dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY)
695 goto out;
696
697 /*
698 * If the file has been deleted and it is on a read/write
699 * filesystem, then truncate the file, and mark the directory slot
700 * as empty. (This may not be necessary for the dos filesystem.)
701 */
702 mprintf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %llx, MNT_RDONLY %llx\n",
703 dep, dep->de_refcnt, (unsigned long long)vp->v_mount->mnt_flag,
704 (unsigned long long)MNT_RDONLY);
705 if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
706 error = detrunc(dep, (u_long) 0, 0);
707 dep->de_flag |= DE_UPDATE;
708 dep->de_Name[0] = SLOT_DELETED;
709 }
710 deupdat(dep, 0);
711
712 out:
713 /*
714 * If we are done with the denode, reclaim it
715 * so that it can be reused immediately.
716 */
717 mprintf("msdosfs_inactive(): v_refcnt 0x%08x, de_Name[0] %x\n",
718 vp->v_refcnt, (dep ? dep->de_Name[0] : 0));
719 if (dep == NULL || dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY)
720 vrecycle(vp);
721 return (error);
722 }
723