xref: /netbsd-src/sys/fs/msdosfs/msdosfs_denode.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: msdosfs_denode.c,v 1.7 2004/05/20 05:39:34 atatat 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.7 2004/05/20 05:39:34 atatat Exp $");
52 
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/mount.h>
56 #include <sys/malloc.h>
57 #include <sys/pool.h>
58 #include <sys/proc.h>
59 #include <sys/buf.h>
60 #include <sys/vnode.h>
61 #include <sys/kernel.h>		/* defines "time" */
62 #include <sys/dirent.h>
63 #include <sys/namei.h>
64 
65 #include <uvm/uvm_extern.h>
66 
67 #include <fs/msdosfs/bpb.h>
68 #include <fs/msdosfs/msdosfsmount.h>
69 #include <fs/msdosfs/direntry.h>
70 #include <fs/msdosfs/denode.h>
71 #include <fs/msdosfs/fat.h>
72 
73 LIST_HEAD(ihashhead, denode) *dehashtbl;
74 u_long dehash;			/* size of hash table - 1 */
75 #define	DEHASH(dev, dcl, doff) \
76     (((dev) + (dcl) + (doff) / sizeof(struct direntry)) & dehash)
77 
78 struct simplelock msdosfs_ihash_slock;
79 
80 POOL_INIT(msdosfs_denode_pool, sizeof(struct denode), 0, 0, 0, "msdosnopl",
81     &pool_allocator_nointr);
82 
83 extern int prtactive;
84 
85 struct genfs_ops msdosfs_genfsops = {
86 	genfs_size,
87 	msdosfs_gop_alloc,
88 	genfs_gop_write,
89 };
90 
91 static struct denode *msdosfs_hashget __P((dev_t, u_long, u_long));
92 static void msdosfs_hashins __P((struct denode *));
93 static void msdosfs_hashrem __P((struct denode *));
94 
95 #ifdef _LKM
96 MALLOC_DECLARE(M_MSDOSFSFAT);
97 #endif
98 
99 void
100 msdosfs_init()
101 {
102 #ifdef _LKM
103 	malloc_type_attach(M_MSDOSFSMNT);
104 	malloc_type_attach(M_MSDOSFSFAT);
105 	pool_init(&msdosfs_denode_pool, sizeof(struct denode), 0, 0, 0,
106 	    "msdosnopl", &pool_allocator_nointr);
107 #endif
108 	dehashtbl = hashinit(desiredvnodes / 2, HASH_LIST, M_MSDOSFSMNT,
109 	    M_WAITOK, &dehash);
110 	simple_lock_init(&msdosfs_ihash_slock);
111 }
112 
113 /*
114  * Reinitialize inode hash table.
115  */
116 
117 void
118 msdosfs_reinit()
119 {
120 	struct denode *dep;
121 	struct ihashhead *oldhash, *hash;
122 	u_long oldmask, mask, val;
123 	int i;
124 
125 	hash = hashinit(desiredvnodes / 2, HASH_LIST, M_MSDOSFSMNT, M_WAITOK,
126 	    &mask);
127 
128 	simple_lock(&msdosfs_ihash_slock);
129 	oldhash = dehashtbl;
130 	oldmask = dehash;
131 	dehashtbl = hash;
132 	dehash = mask;
133 	for (i = 0; i <= oldmask; i++) {
134 		while ((dep = LIST_FIRST(&oldhash[i])) != NULL) {
135 			LIST_REMOVE(dep, de_hash);
136 			val = DEHASH(dep->de_dev, dep->de_dirclust,
137 			    dep->de_diroffset);
138 			LIST_INSERT_HEAD(&hash[val], dep, de_hash);
139 		}
140 	}
141 	simple_unlock(&msdosfs_ihash_slock);
142 	hashdone(oldhash, M_MSDOSFSMNT);
143 }
144 
145 void
146 msdosfs_done()
147 {
148 	hashdone(dehashtbl, M_MSDOSFSMNT);
149 #ifdef _LKM
150 	pool_destroy(&msdosfs_denode_pool);
151 	malloc_type_detach(M_MSDOSFSFAT);
152 	malloc_type_detach(M_MSDOSFSMNT);
153 #endif
154 }
155 
156 static struct denode *
157 msdosfs_hashget(dev, dirclust, diroff)
158 	dev_t dev;
159 	u_long dirclust;
160 	u_long diroff;
161 {
162 	struct denode *dep;
163 	struct vnode *vp;
164 
165 loop:
166 	simple_lock(&msdosfs_ihash_slock);
167 	LIST_FOREACH(dep, &dehashtbl[DEHASH(dev, dirclust, diroff)], de_hash) {
168 		if (dirclust == dep->de_dirclust &&
169 		    diroff == dep->de_diroffset &&
170 		    dev == dep->de_dev &&
171 		    dep->de_refcnt != 0) {
172 			vp = DETOV(dep);
173 			simple_lock(&vp->v_interlock);
174 			simple_unlock(&msdosfs_ihash_slock);
175 			if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
176 				goto loop;
177 			return (dep);
178 		}
179 	}
180 	simple_unlock(&msdosfs_ihash_slock);
181 	return (NULL);
182 }
183 
184 static void
185 msdosfs_hashins(dep)
186 	struct denode *dep;
187 {
188 	struct ihashhead *depp;
189 	int val;
190 
191 	simple_lock(&msdosfs_ihash_slock);
192 	val = DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
193 	depp = &dehashtbl[val];
194 	LIST_INSERT_HEAD(depp, dep, de_hash);
195 	simple_unlock(&msdosfs_ihash_slock);
196 }
197 
198 static void
199 msdosfs_hashrem(dep)
200 	struct denode *dep;
201 {
202 	simple_lock(&msdosfs_ihash_slock);
203 	LIST_REMOVE(dep, de_hash);
204 	simple_unlock(&msdosfs_ihash_slock);
205 }
206 
207 /*
208  * If deget() succeeds it returns with the gotten denode locked().
209  *
210  * pmp	     - address of msdosfsmount structure of the filesystem containing
211  *	       the denode of interest.  The pm_dev field and the address of
212  *	       the msdosfsmount structure are used.
213  * dirclust  - which cluster bp contains, if dirclust is 0 (root directory)
214  *	       diroffset is relative to the beginning of the root directory,
215  *	       otherwise it is cluster relative.
216  * diroffset - offset past begin of cluster of denode we want
217  * depp	     - returns the address of the gotten denode.
218  */
219 int
220 deget(pmp, dirclust, diroffset, depp)
221 	struct msdosfsmount *pmp;	/* so we know the maj/min number */
222 	u_long dirclust;		/* cluster this dir entry came from */
223 	u_long diroffset;		/* index of entry within the cluster */
224 	struct denode **depp;		/* returns the addr of the gotten denode */
225 {
226 	int error;
227 	extern int (**msdosfs_vnodeop_p) __P((void *));
228 	struct direntry *direntptr;
229 	struct denode *ldep;
230 	struct vnode *nvp;
231 	struct buf *bp;
232 
233 #ifdef MSDOSFS_DEBUG
234 	printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
235 	    pmp, dirclust, diroffset, depp);
236 #endif
237 
238 	/*
239 	 * On FAT32 filesystems, root is a (more or less) normal
240 	 * directory
241 	 */
242 	if (FAT32(pmp) && dirclust == MSDOSFSROOT)
243 		dirclust = pmp->pm_rootdirblk;
244 
245 	/*
246 	 * See if the denode is in the denode cache. Use the location of
247 	 * the directory entry to compute the hash value. For subdir use
248 	 * address of "." entry. For root dir (if not FAT32) use cluster
249 	 * MSDOSFSROOT, offset MSDOSFSROOT_OFS
250 	 *
251 	 * NOTE: The check for de_refcnt > 0 below insures the denode being
252 	 * examined does not represent an unlinked but still open file.
253 	 * These files are not to be accessible even when the directory
254 	 * entry that represented the file happens to be reused while the
255 	 * deleted file is still open.
256 	 */
257 	ldep = msdosfs_hashget(pmp->pm_dev, dirclust, diroffset);
258 	if (ldep) {
259 		*depp = ldep;
260 		return (0);
261 	}
262 
263 	/*
264 	 * Directory entry was not in cache, have to create a vnode and
265 	 * copy it from the passed disk buffer.
266 	 */
267 	/* getnewvnode() does a VREF() on the vnode */
268 	error = getnewvnode(VT_MSDOSFS, pmp->pm_mountp,
269 			    msdosfs_vnodeop_p, &nvp);
270 	if (error) {
271 		*depp = 0;
272 		return (error);
273 	}
274 	ldep = pool_get(&msdosfs_denode_pool, PR_WAITOK);
275 	memset(ldep, 0, sizeof *ldep);
276 	nvp->v_data = ldep;
277 	ldep->de_vnode = nvp;
278 	ldep->de_flag = 0;
279 	ldep->de_devvp = 0;
280 	ldep->de_lockf = 0;
281 	ldep->de_dev = pmp->pm_dev;
282 	ldep->de_dirclust = dirclust;
283 	ldep->de_diroffset = diroffset;
284 	fc_purge(ldep, 0);	/* init the fat cache for this denode */
285 
286 	/*
287 	 * Insert the denode into the hash queue and lock the denode so it
288 	 * can't be accessed until we've read it in and have done what we
289 	 * need to it.
290 	 */
291 	vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY);
292 	msdosfs_hashins(ldep);
293 
294 	ldep->de_pmp = pmp;
295 	ldep->de_devvp = pmp->pm_devvp;
296 	ldep->de_refcnt = 1;
297 	/*
298 	 * Copy the directory entry into the denode area of the vnode.
299 	 */
300 	if ((dirclust == MSDOSFSROOT
301 	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
302 	    && diroffset == MSDOSFSROOT_OFS) {
303 		/*
304 		 * Directory entry for the root directory. There isn't one,
305 		 * so we manufacture one. We should probably rummage
306 		 * through the root directory and find a label entry (if it
307 		 * exists), and then use the time and date from that entry
308 		 * as the time and date for the root denode.
309 		 */
310 		nvp->v_flag |= VROOT; /* should be further down		XXX */
311 
312 		ldep->de_Attributes = ATTR_DIRECTORY;
313 		if (FAT32(pmp))
314 			ldep->de_StartCluster = pmp->pm_rootdirblk;
315 			/* de_FileSize will be filled in further down */
316 		else {
317 			ldep->de_StartCluster = MSDOSFSROOT;
318 			ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
319 		}
320 		/*
321 		 * fill in time and date so that dos2unixtime() doesn't
322 		 * spit up when called from msdosfs_getattr() with root
323 		 * denode
324 		 */
325 		ldep->de_CHun = 0;
326 		ldep->de_CTime = 0x0000;	/* 00:00:00	 */
327 		ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
328 		    | (1 << DD_DAY_SHIFT);
329 		/* Jan 1, 1980	 */
330 		ldep->de_ADate = ldep->de_CDate;
331 		ldep->de_MTime = ldep->de_CTime;
332 		ldep->de_MDate = ldep->de_CDate;
333 		/* leave the other fields as garbage */
334 	} else {
335 		error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
336 		if (error)
337 			return (error);
338 		DE_INTERNALIZE(ldep, direntptr);
339 		brelse(bp);
340 	}
341 
342 	/*
343 	 * Fill in a few fields of the vnode and finish filling in the
344 	 * denode.  Then return the address of the found denode.
345 	 */
346 	if (ldep->de_Attributes & ATTR_DIRECTORY) {
347 		/*
348 		 * Since DOS directory entries that describe directories
349 		 * have 0 in the filesize field, we take this opportunity
350 		 * to find out the length of the directory and plug it into
351 		 * the denode structure.
352 		 */
353 		u_long size;
354 
355 		nvp->v_type = VDIR;
356 		if (ldep->de_StartCluster != MSDOSFSROOT) {
357 			error = pcbmap(ldep, CLUST_END, 0, &size, 0);
358 			if (error == E2BIG) {
359 				ldep->de_FileSize = de_cn2off(pmp, size);
360 				error = 0;
361 			} else
362 				printf("deget(): pcbmap returned %d\n", error);
363 		}
364 	} else
365 		nvp->v_type = VREG;
366 	genfs_node_init(nvp, &msdosfs_genfsops);
367 	VREF(ldep->de_devvp);
368 	*depp = ldep;
369 	nvp->v_size = ldep->de_FileSize;
370 	return (0);
371 }
372 
373 int
374 deupdat(dep, waitfor)
375 	struct denode *dep;
376 	int waitfor;
377 {
378 
379 	return (VOP_UPDATE(DETOV(dep), NULL, NULL, waitfor ? UPDATE_WAIT : 0));
380 }
381 
382 /*
383  * Truncate the file described by dep to the length specified by length.
384  */
385 int
386 detrunc(dep, length, flags, cred, p)
387 	struct denode *dep;
388 	u_long length;
389 	int flags;
390 	struct ucred *cred;
391 	struct proc *p;
392 {
393 	int error;
394 	int allerror;
395 	u_long eofentry;
396 	u_long chaintofree;
397 	daddr_t bn, lastblock;
398 	int boff;
399 	int isadir = dep->de_Attributes & ATTR_DIRECTORY;
400 	struct buf *bp;
401 	struct msdosfsmount *pmp = dep->de_pmp;
402 
403 #ifdef MSDOSFS_DEBUG
404 	printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
405 #endif
406 
407 	/*
408 	 * Disallow attempts to truncate the root directory since it is of
409 	 * fixed size.  That's just the way dos filesystems are.  We use
410 	 * the VROOT bit in the vnode because checking for the directory
411 	 * bit and a startcluster of 0 in the denode is not adequate to
412 	 * recognize the root directory at this point in a file or
413 	 * directory's life.
414 	 */
415 	if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp)) {
416 		printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
417 		    dep->de_dirclust, dep->de_diroffset);
418 		return (EINVAL);
419 	}
420 
421 	uvm_vnp_setsize(DETOV(dep), length);
422 
423 	if (dep->de_FileSize < length)
424 		return (deextend(dep, length, cred));
425 	lastblock = de_clcount(pmp, length) - 1;
426 
427 	/*
428 	 * If the desired length is 0 then remember the starting cluster of
429 	 * the file and set the StartCluster field in the directory entry
430 	 * to 0.  If the desired length is not zero, then get the number of
431 	 * the last cluster in the shortened file.  Then get the number of
432 	 * the first cluster in the part of the file that is to be freed.
433 	 * Then set the next cluster pointer in the last cluster of the
434 	 * file to CLUST_EOFE.
435 	 */
436 	if (length == 0) {
437 		chaintofree = dep->de_StartCluster;
438 		dep->de_StartCluster = 0;
439 		eofentry = ~0;
440 	} else {
441 		error = pcbmap(dep, lastblock, 0, &eofentry, 0);
442 		if (error) {
443 #ifdef MSDOSFS_DEBUG
444 			printf("detrunc(): pcbmap fails %d\n", error);
445 #endif
446 			return (error);
447 		}
448 	}
449 
450 	fc_purge(dep, lastblock + 1);
451 
452 	/*
453 	 * If the new length is not a multiple of the cluster size then we
454 	 * must zero the tail end of the new last cluster in case it
455 	 * becomes part of the file again because of a seek.
456 	 */
457 	if ((boff = length & pmp->pm_crbomask) != 0) {
458 		if (isadir) {
459 			bn = cntobn(pmp, eofentry);
460 			error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
461 			    NOCRED, &bp);
462 			if (error) {
463 				brelse(bp);
464 #ifdef MSDOSFS_DEBUG
465 				printf("detrunc(): bread fails %d\n", error);
466 #endif
467 				return (error);
468 			}
469 			memset(bp->b_data + boff, 0, pmp->pm_bpcluster - boff);
470 			if (flags & IO_SYNC)
471 				bwrite(bp);
472 			else
473 				bdwrite(bp);
474 		} else {
475 			uvm_vnp_zerorange(DETOV(dep), length,
476 					  pmp->pm_bpcluster - boff);
477 		}
478 	}
479 
480 	/*
481 	 * Write out the updated directory entry.  Even if the update fails
482 	 * we free the trailing clusters.
483 	 */
484 	dep->de_FileSize = length;
485 	if (!isadir)
486 		dep->de_flag |= DE_UPDATE|DE_MODIFIED;
487 	vtruncbuf(DETOV(dep), lastblock + 1, 0, 0);
488 	allerror = deupdat(dep, 1);
489 #ifdef MSDOSFS_DEBUG
490 	printf("detrunc(): allerror %d, eofentry %lu\n",
491 	       allerror, eofentry);
492 #endif
493 
494 	/*
495 	 * If we need to break the cluster chain for the file then do it
496 	 * now.
497 	 */
498 	if (eofentry != ~0) {
499 		error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
500 				 &chaintofree, CLUST_EOFE);
501 		if (error) {
502 #ifdef MSDOSFS_DEBUG
503 			printf("detrunc(): fatentry errors %d\n", error);
504 #endif
505 			return (error);
506 		}
507 		fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
508 			    eofentry);
509 	}
510 
511 	/*
512 	 * Now free the clusters removed from the file because of the
513 	 * truncation.
514 	 */
515 	if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask))
516 		freeclusterchain(pmp, chaintofree);
517 
518 	return (allerror);
519 }
520 
521 /*
522  * Extend the file described by dep to length specified by length.
523  */
524 int
525 deextend(dep, length, cred)
526 	struct denode *dep;
527 	u_long length;
528 	struct ucred *cred;
529 {
530 	struct msdosfsmount *pmp = dep->de_pmp;
531 	u_long count, osize;
532 	int error;
533 
534 	/*
535 	 * The root of a DOS filesystem cannot be extended.
536 	 */
537 	if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
538 		return (EINVAL);
539 
540 	/*
541 	 * Directories cannot be extended.
542 	 */
543 	if (dep->de_Attributes & ATTR_DIRECTORY)
544 		return (EISDIR);
545 
546 	if (length <= dep->de_FileSize)
547 		panic("deextend: file too large");
548 
549 	/*
550 	 * Compute the number of clusters to allocate.
551 	 */
552 	count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
553 	if (count > 0) {
554 		if (count > pmp->pm_freeclustercount)
555 			return (ENOSPC);
556 		error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
557 		if (error) {
558 			/* truncate the added clusters away again */
559 			(void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
560 			return (error);
561 		}
562 	}
563 
564 	osize = dep->de_FileSize;
565 	dep->de_FileSize = length;
566 	uvm_vnp_setsize(DETOV(dep), (voff_t)dep->de_FileSize);
567 	dep->de_flag |= DE_UPDATE|DE_MODIFIED;
568 	uvm_vnp_zerorange(DETOV(dep), (off_t)osize,
569 	    (size_t)(dep->de_FileSize - osize));
570 	return (deupdat(dep, 1));
571 }
572 
573 /*
574  * Move a denode to its correct hash queue after the file it represents has
575  * been moved to a new directory.
576  */
577 void
578 reinsert(dep)
579 	struct denode *dep;
580 {
581 	/*
582 	 * Fix up the denode cache.  If the denode is for a directory,
583 	 * there is nothing to do since the hash is based on the starting
584 	 * cluster of the directory file and that hasn't changed.  If for a
585 	 * file the hash is based on the location of the directory entry,
586 	 * so we must remove it from the cache and re-enter it with the
587 	 * hash based on the new location of the directory entry.
588 	 */
589 	if (dep->de_Attributes & ATTR_DIRECTORY)
590 		return;
591 	msdosfs_hashrem(dep);
592 	msdosfs_hashins(dep);
593 }
594 
595 int
596 msdosfs_reclaim(v)
597 	void *v;
598 {
599 	struct vop_reclaim_args /* {
600 		struct vnode *a_vp;
601 	} */ *ap = v;
602 	struct vnode *vp = ap->a_vp;
603 	struct denode *dep = VTODE(vp);
604 
605 #ifdef MSDOSFS_DEBUG
606 	printf("msdosfs_reclaim(): dep %p, file %s, refcnt %ld\n",
607 	    dep, dep->de_Name, dep->de_refcnt);
608 #endif
609 
610 	if (prtactive && vp->v_usecount != 0)
611 		vprint("msdosfs_reclaim(): pushing active", vp);
612 	/*
613 	 * Remove the denode from its hash chain.
614 	 */
615 	msdosfs_hashrem(dep);
616 	/*
617 	 * Purge old data structures associated with the denode.
618 	 */
619 	cache_purge(vp);
620 	if (dep->de_devvp) {
621 		vrele(dep->de_devvp);
622 		dep->de_devvp = 0;
623 	}
624 #if 0 /* XXX */
625 	dep->de_flag = 0;
626 #endif
627 	pool_put(&msdosfs_denode_pool, dep);
628 	vp->v_data = NULL;
629 	return (0);
630 }
631 
632 int
633 msdosfs_inactive(v)
634 	void *v;
635 {
636 	struct vop_inactive_args /* {
637 		struct vnode *a_vp;
638 		struct proc *a_p;
639 	} */ *ap = v;
640 	struct proc *p = ap->a_p;
641 	struct vnode *vp = ap->a_vp;
642 	struct denode *dep = VTODE(vp);
643 	int error = 0;
644 
645 #ifdef MSDOSFS_DEBUG
646 	printf("msdosfs_inactive(): dep %p, de_Name[0] %x\n", dep, dep->de_Name[0]);
647 #endif
648 
649 	if (prtactive && vp->v_usecount != 0)
650 		vprint("msdosfs_inactive(): pushing active", vp);
651 
652 	/*
653 	 * Get rid of denodes related to stale file handles.
654 	 */
655 	if (dep->de_Name[0] == SLOT_DELETED)
656 		goto out;
657 
658 	/*
659 	 * If the file has been deleted and it is on a read/write
660 	 * filesystem, then truncate the file, and mark the directory slot
661 	 * as empty.  (This may not be necessary for the dos filesystem.)
662 	 */
663 #ifdef MSDOSFS_DEBUG
664 	printf("msdosfs_inactive(): dep %p, refcnt %ld, mntflag %x %s\n",
665 	       dep, dep->de_refcnt, vp->v_mount->mnt_flag,
666 		(vp->v_mount->mnt_flag & MNT_RDONLY) ? "MNT_RDONLY" : "");
667 #endif
668 	if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
669 		if (dep->de_FileSize != 0) {
670 			error = detrunc(dep, (u_long)0, 0, NOCRED, NULL);
671 		}
672 		dep->de_Name[0] = SLOT_DELETED;
673 	}
674 	deupdat(dep, 0);
675 out:
676 	VOP_UNLOCK(vp, 0);
677 	/*
678 	 * If we are done with the denode, reclaim it
679 	 * so that it can be reused immediately.
680 	 */
681 #ifdef MSDOSFS_DEBUG
682 	printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n",
683 		vp->v_usecount, dep->de_Name[0]);
684 #endif
685 	if (dep->de_Name[0] == SLOT_DELETED)
686 		vrecycle(vp, (struct simplelock *)0, p);
687 	return (error);
688 }
689 
690 int
691 msdosfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
692     struct ucred *cred)
693 {
694 	return 0;
695 }
696