xref: /netbsd-src/sbin/fsck_lfs/inode.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /* $NetBSD: inode.c,v 1.68 2015/09/21 01:24:23 dholland Exp $	 */
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Konrad E. Schroder <perseant@hhhh.org>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1980, 1986, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  */
60 
61 #include <sys/types.h>
62 #include <sys/param.h>
63 #include <sys/time.h>
64 #include <sys/buf.h>
65 #include <sys/mount.h>
66 
67 #define vnode uvnode
68 #include <ufs/lfs/lfs.h>
69 #include <ufs/lfs/lfs_accessors.h>
70 #include <ufs/lfs/lfs_inode.h>
71 #undef vnode
72 
73 #include <err.h>
74 #ifndef SMALL
75 #include <pwd.h>
76 #endif
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <util.h>
81 
82 #include "bufcache.h"
83 #include "vnode.h"
84 #include "lfs_user.h"
85 
86 #include "fsck.h"
87 #include "fsutil.h"
88 #include "extern.h"
89 
90 static int iblock(struct inodesc *, long, u_int64_t);
91 int blksreqd(struct lfs *, int);
92 int lfs_maxino(void);
93 
94 /*
95  * Get a dinode of a given inum.
96  * XXX combine this function with vget.
97  */
98 union lfs_dinode *
99 ginode(ino_t ino)
100 {
101 	struct uvnode *vp;
102 	struct ubuf *bp;
103 	IFILE *ifp;
104 	daddr_t daddr;
105 	unsigned segno;
106 
107 	vp = vget(fs, ino);
108 	if (vp == NULL)
109 		return NULL;
110 
111 	if (din_table[ino] == 0x0) {
112 		LFS_IENTRY(ifp, fs, ino, bp);
113 		daddr = lfs_if_getdaddr(fs, ifp);
114 		segno = lfs_dtosn(fs, daddr);
115 		din_table[ino] = daddr;
116 		seg_table[segno].su_nbytes += DINOSIZE(fs);
117 		brelse(bp, 0);
118 	}
119 	return VTOI(vp)->i_din;
120 }
121 
122 /*
123  * Check validity of held blocks in an inode, recursing through all blocks.
124  */
125 int
126 ckinode(union lfs_dinode *dp, struct inodesc *idesc)
127 {
128 	daddr_t lbn, pbn;
129 	long ret, n, ndb, offset;
130 	union lfs_dinode dino;
131 	u_int64_t remsize, sizepb;
132 	mode_t mode;
133 	char pathbuf[MAXPATHLEN + 1];
134 	struct uvnode *vp, *thisvp;
135 
136 	if (idesc->id_fix != IGNORE)
137 		idesc->id_fix = DONTKNOW;
138 	idesc->id_entryno = 0;
139 	idesc->id_filesize = lfs_dino_getsize(fs, dp);
140 	mode = lfs_dino_getmode(fs, dp) & LFS_IFMT;
141 	if (mode == LFS_IFBLK || mode == LFS_IFCHR ||
142 	    (mode == LFS_IFLNK && (lfs_dino_getsize(fs, dp) < lfs_sb_getmaxsymlinklen(fs) ||
143 		    (lfs_sb_getmaxsymlinklen(fs) == 0 &&
144 			lfs_dino_getblocks(fs, dp) == 0))))
145 		return (KEEPON);
146 	/* XXX is this safe if we're 32-bit? */
147 	dino = *dp;
148 	ndb = howmany(lfs_dino_getsize(fs, &dino), lfs_sb_getbsize(fs));
149 
150 	thisvp = vget(fs, idesc->id_number);
151 	for (lbn = 0; lbn < ULFS_NDADDR; lbn++) {
152 		pbn = lfs_dino_getdb(fs, &dino, lbn);
153 		if (thisvp)
154 			idesc->id_numfrags =
155 				lfs_numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
156 		else {
157 			if (--ndb == 0 && (offset = lfs_blkoff(fs, lfs_dino_getsize(fs, &dino))) != 0) {
158 				idesc->id_numfrags =
159 			    	lfs_numfrags(fs, lfs_fragroundup(fs, offset));
160 			} else
161 				idesc->id_numfrags = lfs_sb_getfrag(fs);
162 		}
163 		if (pbn == 0) {
164 			if (idesc->id_type == DATA && ndb >= 0) {
165 				/* An empty block in a directory XXX */
166 				getpathname(pathbuf, sizeof(pathbuf),
167 				    idesc->id_number, idesc->id_number);
168 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]",
169 				    pathbuf, (long long)idesc->id_number);
170 				if (reply("ADJUST LENGTH") == 1) {
171 					vp = vget(fs, idesc->id_number);
172 					dp = VTOD(vp);
173 					lfs_dino_setsize(fs, dp,
174 					    lbn * lfs_sb_getbsize(fs));
175 					printf(
176 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
177 					rerun = 1;
178 					inodirty(VTOI(vp));
179 				} else
180 					break;
181 			}
182 			continue;
183 		}
184 		idesc->id_blkno = pbn;
185 		idesc->id_lblkno = lbn;
186 		if (idesc->id_type == ADDR) {
187 			ret = (*idesc->id_func) (idesc);
188 		} else
189 			ret = dirscan(idesc);
190 		if (ret & STOP)
191 			return (ret);
192 	}
193 	idesc->id_numfrags = lfs_sb_getfrag(fs);
194 	remsize = lfs_dino_getsize(fs, &dino) - lfs_sb_getbsize(fs) * ULFS_NDADDR;
195 	sizepb = lfs_sb_getbsize(fs);
196 	for (n = 1; n <= ULFS_NIADDR; n++) {
197 		pbn = lfs_dino_getib(fs, &dino, n-1);
198 		if (pbn) {
199 			idesc->id_blkno = pbn;
200 			ret = iblock(idesc, n, remsize);
201 			if (ret & STOP)
202 				return (ret);
203 		} else {
204 			if (idesc->id_type == DATA && remsize > 0) {
205 				/* An empty block in a directory XXX */
206 				getpathname(pathbuf, sizeof(pathbuf),
207 				    idesc->id_number, idesc->id_number);
208 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]",
209 				    pathbuf, (long long)idesc->id_number);
210 				if (reply("ADJUST LENGTH") == 1) {
211 					vp = vget(fs, idesc->id_number);
212 					dp = VTOD(vp);
213 					lfs_dino_setsize(fs, dp,
214 					    lfs_dino_getsize(fs, dp) - remsize);
215 					remsize = 0;
216 					printf(
217 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
218 					rerun = 1;
219 					inodirty(VTOI(vp));
220 					break;
221 				} else
222 					break;
223 			}
224 		}
225 		sizepb *= LFS_NINDIR(fs);
226 		remsize -= sizepb;
227 	}
228 	return (KEEPON);
229 }
230 
231 static int
232 iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
233 {
234 	unsigned j, maxindir;
235 	daddr_t found;
236 	struct ubuf *bp;
237 	int i, n, (*func) (struct inodesc *), nif;
238 	u_int64_t sizepb;
239 	char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
240 	struct uvnode *devvp, *vp;
241 	int diddirty = 0;
242 
243 	if (idesc->id_type == ADDR) {
244 		func = idesc->id_func;
245 		n = (*func) (idesc);
246 		if ((n & KEEPON) == 0)
247 			return (n);
248 	} else
249 		func = dirscan;
250 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
251 		return (SKIP);
252 
253 	devvp = fs->lfs_devvp;
254 	bread(devvp, LFS_FSBTODB(fs, idesc->id_blkno), lfs_sb_getbsize(fs),
255 	    0, &bp);
256 	ilevel--;
257 	for (sizepb = lfs_sb_getbsize(fs), i = 0; i < ilevel; i++)
258 		sizepb *= LFS_NINDIR(fs);
259 	if (isize > sizepb * LFS_NINDIR(fs))
260 		nif = LFS_NINDIR(fs);
261 	else
262 		nif = howmany(isize, sizepb);
263 	if (idesc->id_func == pass1check && nif < LFS_NINDIR(fs)) {
264 		maxindir = LFS_NINDIR(fs);
265 		for (j = nif; j < maxindir; j++) {
266 			found = lfs_iblock_get(fs, bp->b_data, j);
267 			if (found == 0)
268 				continue;
269 			(void)snprintf(buf, sizeof(buf),
270 			    "PARTIALLY TRUNCATED INODE I=%llu",
271 			    (unsigned long long)idesc->id_number);
272 			if (dofix(idesc, buf)) {
273 				lfs_iblock_set(fs, bp->b_data, j, 0);
274 				++diddirty;
275 			}
276 		}
277 	}
278 	maxindir = nif;
279 	for (j = 0; j < maxindir; j++) {
280 		found = lfs_iblock_get(fs, bp->b_data, j);
281 		if (found) {
282 			idesc->id_blkno = found;
283 			if (ilevel == 0) {
284 				/*
285 				 * dirscan needs lfs_lblkno.
286 				 */
287 				idesc->id_lblkno++;
288 				n = (*func) (idesc);
289 			} else {
290 				n = iblock(idesc, ilevel, isize);
291 			}
292 			if (n & STOP) {
293 				if (diddirty)
294 					VOP_BWRITE(bp);
295 				else
296 					brelse(bp, 0);
297 				return (n);
298 			}
299 		} else {
300 			if (idesc->id_type == DATA && isize > 0) {
301 				/* An empty block in a directory XXX */
302 				getpathname(pathbuf, sizeof(pathbuf),
303 				    idesc->id_number, idesc->id_number);
304 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]",
305 				    pathbuf, (long long)idesc->id_number);
306 				if (reply("ADJUST LENGTH") == 1) {
307 					vp = vget(fs, idesc->id_number);
308 					lfs_dino_setsize(fs, VTOI(vp)->i_din,
309 					    lfs_dino_getsize(fs,
310 							     VTOI(vp)->i_din)
311 					    - isize);
312 					isize = 0;
313 					printf(
314 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
315 					rerun = 1;
316 					inodirty(VTOI(vp));
317 					if (diddirty)
318 						VOP_BWRITE(bp);
319 					else
320 						brelse(bp, 0);
321 					return (STOP);
322 				}
323 			}
324 		}
325 		isize -= sizepb;
326 	}
327 	if (diddirty)
328 		VOP_BWRITE(bp);
329 	else
330 		brelse(bp, 0);
331 	return (KEEPON);
332 }
333 
334 /*
335  * Check that a block in a legal block number.
336  * Return 0 if in range, 1 if out of range.
337  */
338 int
339 chkrange(daddr_t blk, int cnt)
340 {
341 	if (blk < lfs_sntod(fs, 0)) {
342 		return (1);
343 	}
344 	if (blk > maxfsblock) {
345 		return (1);
346 	}
347 	if (blk + cnt < lfs_sntod(fs, 0)) {
348 		return (1);
349 	}
350 	if (blk + cnt > maxfsblock) {
351 		return (1);
352 	}
353 	return (0);
354 }
355 
356 /*
357  * Routines to maintain information about directory inodes.
358  * This is built during the first pass and used during the
359  * second and third passes.
360  *
361  * Enter inodes into the cache.
362  */
363 void
364 cacheino(union lfs_dinode *dp, ino_t inumber)
365 {
366 	struct inoinfo *inp;
367 	struct inoinfo **inpp, **ninpsort;
368 	unsigned int blks, i;
369 
370 	blks = howmany(lfs_dino_getsize(fs, dp), lfs_sb_getbsize(fs));
371 	if (blks > ULFS_NDADDR)
372 		blks = ULFS_NDADDR + ULFS_NIADDR;
373 	inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(inp->i_blks[0]));
374 	inpp = &inphead[inumber % numdirs];
375 	inp->i_nexthash = *inpp;
376 	*inpp = inp;
377 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
378 	if (inumber == ULFS_ROOTINO)
379 		inp->i_parent = ULFS_ROOTINO;
380 	else
381 		inp->i_parent = (ino_t) 0;
382 	inp->i_dotdot = (ino_t) 0;
383 	inp->i_number = inumber;
384 	inp->i_isize = lfs_dino_getsize(fs, dp);
385 
386 	inp->i_numblks = blks * sizeof(inp->i_blks[0]);
387 	for (i=0; i<blks && i<ULFS_NDADDR; i++) {
388 		inp->i_blks[i] = lfs_dino_getdb(fs, dp, i);
389 	}
390 	for (; i<blks; i++) {
391 		inp->i_blks[i] = lfs_dino_getib(fs, dp, i - ULFS_NDADDR);
392 	}
393 	if (inplast == listmax) {
394 		ninpsort = erealloc(inpsort,
395 		    (listmax + 100) * sizeof(struct inoinfo *));
396 		inpsort = ninpsort;
397 		listmax += 100;
398 	}
399 	inpsort[inplast++] = inp;
400 }
401 
402 /*
403  * Look up an inode cache structure.
404  */
405 struct inoinfo *
406 getinoinfo(ino_t inumber)
407 {
408 	struct inoinfo *inp;
409 
410 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
411 		if (inp->i_number != inumber)
412 			continue;
413 		return (inp);
414 	}
415 	err(EEXIT, "cannot find inode %llu", (unsigned long long)inumber);
416 	return ((struct inoinfo *) 0);
417 }
418 
419 /*
420  * Clean up all the inode cache structure.
421  */
422 void
423 inocleanup(void)
424 {
425 	struct inoinfo **inpp;
426 
427 	if (inphead == NULL)
428 		return;
429 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
430 		free((char *) (*inpp));
431 	free((char *) inphead);
432 	free((char *) inpsort);
433 	inphead = inpsort = NULL;
434 }
435 
436 void
437 inodirty(struct inode *ip)
438 {
439 	ip->i_flag |= IN_MODIFIED;
440 }
441 
442 void
443 clri(struct inodesc * idesc, const char *type, int flag)
444 {
445 	struct uvnode *vp;
446 
447 	vp = vget(fs, idesc->id_number);
448 	if (flag & 0x1) {
449 		pwarn("%s %s", type,
450 		      (lfs_dino_getmode(fs, VTOI(vp)->i_din) & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE");
451 		pinode(idesc->id_number);
452 	}
453 	if ((flag & 0x2) || preen || reply("CLEAR") == 1) {
454 		if (preen && flag != 2)
455 			printf(" (CLEARED)\n");
456 		n_files--;
457 		(void) ckinode(VTOD(vp), idesc);
458 		clearinode(idesc->id_number);
459 		statemap[idesc->id_number] = USTATE;
460 		vnode_destroy(vp);
461 		return;
462 	}
463 	return;
464 }
465 
466 void
467 clearinode(ino_t inumber)
468 {
469 	struct ubuf *bp;
470 	IFILE *ifp;
471 	daddr_t daddr;
472 
473 	/* Send cleared inode to the free list */
474 
475 	LFS_IENTRY(ifp, fs, inumber, bp);
476 	daddr = lfs_if_getdaddr(fs, ifp);
477 	if (daddr == LFS_UNUSED_DADDR) {
478 		brelse(bp, 0);
479 		return;
480 	}
481 	lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
482 	lfs_if_setnextfree(fs, ifp, lfs_sb_getfreehd(fs));
483 	lfs_sb_setfreehd(fs, inumber);
484 	sbdirty();
485 	VOP_BWRITE(bp);
486 
487 	/*
488 	 * update segment usage.
489 	 */
490 	if (daddr != LFS_UNUSED_DADDR) {
491 		SEGUSE *sup;
492 		u_int32_t oldsn = lfs_dtosn(fs, daddr);
493 
494 		seg_table[oldsn].su_nbytes -= DINOSIZE(fs);
495 		LFS_SEGENTRY(sup, fs, oldsn, bp);
496 		sup->su_nbytes -= DINOSIZE(fs);
497 		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);	/* Ifile */
498 	}
499 }
500 
501 int
502 findname(struct inodesc * idesc)
503 {
504 	LFS_DIRHEADER *dirp = idesc->id_dirp;
505 	size_t len;
506 	char *buf;
507 
508 	if (lfs_dir_getino(fs, dirp) != idesc->id_parent)
509 		return (KEEPON);
510 	len = lfs_dir_getnamlen(fs, dirp) + 1;
511 	if (len > MAXPATHLEN) {
512 		/* Truncate it but don't overflow the buffer */
513 		/* XXX: this case doesn't null-terminate the result */
514 		len = MAXPATHLEN;
515 	}
516 	/* this is namebuf with utils.h */
517 	buf = __UNCONST(idesc->id_name);
518 	(void)memcpy(buf, lfs_dir_nameptr(fs, dirp), len);
519 	return (STOP | FOUND);
520 }
521 
522 int
523 findino(struct inodesc * idesc)
524 {
525 	LFS_DIRHEADER *dirp = idesc->id_dirp;
526 	ino_t ino;
527 
528 	ino = lfs_dir_getino(fs, dirp);
529 	if (ino == 0)
530 		return (KEEPON);
531 	if (strcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name) == 0 &&
532 	    ino >= ULFS_ROOTINO && ino < maxino) {
533 		idesc->id_parent = ino;
534 		return (STOP | FOUND);
535 	}
536 	return (KEEPON);
537 }
538 
539 void
540 pinode(ino_t ino)
541 {
542 	union lfs_dinode *dp;
543 	struct passwd *pw;
544 
545 	printf(" I=%llu ", (unsigned long long)ino);
546 	if (ino < ULFS_ROOTINO || ino >= maxino)
547 		return;
548 	dp = ginode(ino);
549 	if (dp) {
550 		printf(" OWNER=");
551 #ifndef SMALL
552 		if (Uflag && (pw = getpwuid(lfs_dino_getuid(fs, dp))) != 0)
553 			printf("%s ", pw->pw_name);
554 		else
555 #endif
556 			printf("%u ", (unsigned)lfs_dino_getuid(fs, dp));
557 		printf("MODE=%o\n", lfs_dino_getmode(fs, dp));
558 		if (preen)
559 			printf("%s: ", cdevname());
560 		printf("SIZE=%ju ", (uintmax_t) lfs_dino_getsize(fs, dp));
561 		printf("MTIME=%s ", print_mtime(lfs_dino_getmtime(fs, dp)));
562 	}
563 }
564 
565 void
566 blkerror(ino_t ino, const char *type, daddr_t blk)
567 {
568 
569 	pfatal("%lld %s I=%llu", (long long) blk, type,
570 	    (unsigned long long)ino);
571 	printf("\n");
572 	if (exitonfail)
573 		exit(1);
574 	switch (statemap[ino]) {
575 
576 	case FSTATE:
577 		statemap[ino] = FCLEAR;
578 		return;
579 
580 	case DSTATE:
581 		statemap[ino] = DCLEAR;
582 		return;
583 
584 	case FCLEAR:
585 	case DCLEAR:
586 		return;
587 
588 	default:
589 		err(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
590 		/* NOTREACHED */
591 	}
592 }
593 
594 /*
595  * allocate an unused inode
596  */
597 ino_t
598 allocino(ino_t request, int type)
599 {
600 	ino_t ino;
601 	union lfs_dinode *dp;
602 	time_t t;
603 	struct uvnode *vp;
604 	struct ubuf *bp;
605 
606 	if (request == 0)
607 		request = ULFS_ROOTINO;
608 	else if (statemap[request] != USTATE)
609 		return (0);
610 	for (ino = request; ino < maxino; ino++)
611 		if (statemap[ino] == USTATE)
612 			break;
613 	if (ino == maxino)
614 		extend_ifile(fs);
615 
616 	switch (type & LFS_IFMT) {
617 	case LFS_IFDIR:
618 		statemap[ino] = DSTATE;
619 		break;
620 	case LFS_IFREG:
621 	case LFS_IFLNK:
622 		statemap[ino] = FSTATE;
623 		break;
624 	default:
625 		return (0);
626 	}
627         vp = lfs_valloc(fs, ino);
628 	if (vp == NULL)
629 		return (0);
630 	dp = VTOI(vp)->i_din;
631 	bp = getblk(vp, 0, lfs_sb_getfsize(fs));
632 	VOP_BWRITE(bp);
633 	lfs_dino_setmode(fs, dp, type);
634 	(void) time(&t);
635 	lfs_dino_setatime(fs, dp, t);
636 	lfs_dino_setctime(fs, dp, t);
637 	lfs_dino_setmtime(fs, dp, t);
638 	lfs_dino_setsize(fs, dp, lfs_sb_getfsize(fs));
639 	lfs_dino_setblocks(fs, dp, lfs_btofsb(fs, lfs_sb_getfsize(fs)));
640 	n_files++;
641 	inodirty(VTOI(vp));
642 	typemap[ino] = LFS_IFTODT(type);
643 	return (ino);
644 }
645 
646 /*
647  * deallocate an inode
648  */
649 void
650 freeino(ino_t ino)
651 {
652 	struct inodesc idesc;
653 	struct uvnode *vp;
654 
655 	memset(&idesc, 0, sizeof(struct inodesc));
656 	idesc.id_type = ADDR;
657 	idesc.id_func = pass4check;
658 	idesc.id_number = ino;
659 	vp = vget(fs, ino);
660 	(void) ckinode(VTOD(vp), &idesc);
661 	clearinode(ino);
662 	statemap[ino] = USTATE;
663 	vnode_destroy(vp);
664 
665 	n_files--;
666 }
667