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