xref: /netbsd/sbin/fsck_ffs/inode.c (revision bf9ec67e)
1 /*	$NetBSD: inode.c,v 1.34 2001/01/05 02:02:57 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1986, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
40 #else
41 __RCSID("$NetBSD: inode.c,v 1.34 2001/01/05 02:02:57 lukem Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/time.h>
47 
48 #include <ufs/ufs/dinode.h>
49 #include <ufs/ufs/dir.h>
50 #include <ufs/ffs/fs.h>
51 #include <ufs/ffs/ffs_extern.h>
52 #include <ufs/ufs/ufs_bswap.h>
53 
54 #ifndef SMALL
55 #include <err.h>
56 #include <pwd.h>
57 #endif
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <time.h>
62 
63 #include "fsck.h"
64 #include "fsutil.h"
65 #include "extern.h"
66 
67 static ino_t startinum;
68 
69 static int iblock __P((struct inodesc *, long, u_int64_t));
70 
71 int
72 ckinode(dp, idesc)
73 	struct dinode *dp;
74 	struct inodesc *idesc;
75 {
76 	ufs_daddr_t *ap;
77 	long ret, n, ndb, offset;
78 	struct dinode dino;
79 	u_int64_t sizepb;
80 	int64_t remsize;
81 	mode_t mode;
82 	char pathbuf[MAXPATHLEN + 1];
83 
84 	if (idesc->id_fix != IGNORE)
85 		idesc->id_fix = DONTKNOW;
86 	idesc->id_entryno = 0;
87 	idesc->id_filesize = iswap64(dp->di_size);
88 	mode = iswap16(dp->di_mode) & IFMT;
89 	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
90 	    (idesc->id_filesize < sblock->fs_maxsymlinklen ||
91 	     (sblock->fs_maxsymlinklen == 0 && dp->di_blocks == 0))))
92 		return (KEEPON);
93 	dino = *dp;
94 	ndb = howmany(iswap64(dino.di_size), sblock->fs_bsize);
95 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
96 		if (--ndb == 0 &&
97 			(offset = blkoff(sblock, iswap64(dino.di_size))) != 0)
98 			idesc->id_numfrags =
99 				numfrags(sblock, fragroundup(sblock, offset));
100 		else
101 			idesc->id_numfrags = sblock->fs_frag;
102 		if (*ap == 0) {
103 			if (idesc->id_type == DATA && ndb >= 0) {
104 				/* An empty block in a directory XXX */
105 				markclean = 0;
106 				getpathname(pathbuf, idesc->id_number,
107 				    idesc->id_number);
108 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
109 				    pathbuf);
110 				if (reply("ADJUST LENGTH") == 1) {
111 					dp = ginode(idesc->id_number);
112 					dp->di_size = iswap64((ap - &dino.di_db[0]) *
113 					    sblock->fs_bsize);
114 					printf(
115 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
116 					rerun = 1;
117 					inodirty();
118 				}
119 			}
120 			continue;
121 		}
122 		idesc->id_blkno = iswap32(*ap);
123 		if (idesc->id_type == ADDR)
124 			ret = (*idesc->id_func)(idesc);
125 		else
126 			ret = dirscan(idesc);
127 		if (ret & STOP)
128 			return (ret);
129 	}
130 	idesc->id_numfrags = sblock->fs_frag;
131 	remsize = iswap64(dino.di_size) - sblock->fs_bsize * NDADDR;
132 	sizepb = sblock->fs_bsize;
133 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
134 		if (*ap) {
135 			idesc->id_blkno = iswap32(*ap);
136 			ret = iblock(idesc, n, remsize);
137 			if (ret & STOP)
138 				return (ret);
139 		} else {
140 			if (idesc->id_type == DATA && remsize > 0) {
141 				/* An empty block in a directory XXX */
142 				markclean = 0;
143 				getpathname(pathbuf, idesc->id_number,
144 				    idesc->id_number);
145 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
146 				    pathbuf);
147 				if (reply("ADJUST LENGTH") == 1) {
148 					dp = ginode(idesc->id_number);
149 					dp->di_size = iswap64(iswap64(dp->di_size) - remsize);
150 					remsize = 0;
151 					printf(
152 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
153 					rerun = 1;
154 					inodirty();
155 					break;
156 				}
157 			}
158 		}
159 		sizepb *= NINDIR(sblock);
160 		remsize -= sizepb;
161 	}
162 	return (KEEPON);
163 }
164 
165 static int
166 iblock(idesc, ilevel, isize)
167 	struct inodesc *idesc;
168 	long ilevel;
169 	u_int64_t isize;
170 {
171 	ufs_daddr_t *ap;
172 	ufs_daddr_t *aplim;
173 	struct bufarea *bp;
174 	int i, n, (*func) __P((struct inodesc *)), nif;
175 	u_int64_t sizepb;
176 	char buf[BUFSIZ];
177 	char pathbuf[MAXPATHLEN + 1];
178 	struct dinode *dp;
179 
180 	if (idesc->id_type == ADDR) {
181 		func = idesc->id_func;
182 		if (((n = (*func)(idesc)) & KEEPON) == 0)
183 			return (n);
184 	} else
185 		func = dirscan;
186 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
187 		return (SKIP);
188 	bp = getdatablk(idesc->id_blkno, sblock->fs_bsize);
189 	ilevel--;
190 	for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++)
191 		sizepb *= NINDIR(sblock);
192 	if (isize > sizepb * NINDIR(sblock))
193 		nif = NINDIR(sblock);
194 	else
195 		nif = howmany(isize, sizepb);
196 	if (do_blkswap) { /* swap byte order of the whole blk */
197 		aplim = &bp->b_un.b_indir[nif];
198 		for (ap = bp->b_un.b_indir; ap < aplim; ap++)
199 			*ap = bswap32(*ap);
200 		dirty(bp);
201 		flush(fswritefd, bp);
202 	}
203 	if (idesc->id_func == pass1check && nif < NINDIR(sblock)) {
204 		aplim = &bp->b_un.b_indir[NINDIR(sblock)];
205 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
206 			if (*ap == 0)
207 				continue;
208 			(void)snprintf(buf, sizeof(buf),
209 			    "PARTIALLY TRUNCATED INODE I=%u", idesc->id_number);
210 			if (dofix(idesc, buf)) {
211 				*ap = 0;
212 				dirty(bp);
213 			} else
214 				markclean=  0;
215 		}
216 		flush(fswritefd, bp);
217 	}
218 	aplim = &bp->b_un.b_indir[nif];
219 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
220 		if (*ap) {
221 			idesc->id_blkno = iswap32(*ap);
222 			if (ilevel == 0)
223 				n = (*func)(idesc);
224 			else
225 				n = iblock(idesc, ilevel, isize);
226 			if (n & STOP) {
227 				bp->b_flags &= ~B_INUSE;
228 				return (n);
229 			}
230 		} else {
231 			if (idesc->id_type == DATA && isize > 0) {
232 				/* An empty block in a directory XXX */
233 				markclean=  0;
234 				getpathname(pathbuf, idesc->id_number,
235 				    idesc->id_number);
236 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
237 				    pathbuf);
238 				if (reply("ADJUST LENGTH") == 1) {
239 					dp = ginode(idesc->id_number);
240 					dp->di_size = iswap64(iswap64(dp->di_size) - isize);
241 					isize = 0;
242 					printf(
243 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
244 					rerun = 1;
245 					inodirty();
246 					bp->b_flags &= ~B_INUSE;
247 					return(STOP);
248 				}
249 			}
250 		}
251 		isize -= sizepb;
252 	}
253 	bp->b_flags &= ~B_INUSE;
254 	return (KEEPON);
255 }
256 
257 /*
258  * Check that a block in a legal block number.
259  * Return 0 if in range, 1 if out of range.
260  */
261 int
262 chkrange(blk, cnt)
263 	ufs_daddr_t blk;
264 	int cnt;
265 {
266 	int c;
267 
268 	if ((unsigned)(blk + cnt) > maxfsblock)
269 		return (1);
270 	c = dtog(sblock, blk);
271 	if (blk < cgdmin(sblock, c)) {
272 		if ((blk + cnt) > cgsblock(sblock, c)) {
273 			if (debug) {
274 				printf("blk %d < cgdmin %d;",
275 				    blk, cgdmin(sblock, c));
276 				printf(" blk + cnt %d > cgsbase %d\n",
277 				    blk + cnt, cgsblock(sblock, c));
278 			}
279 			return (1);
280 		}
281 	} else {
282 		if ((blk + cnt) > cgbase(sblock, c+1)) {
283 			if (debug)  {
284 				printf("blk %d >= cgdmin %d;",
285 				    blk, cgdmin(sblock, c));
286 				printf(" blk + cnt %d > sblock->fs_fpg %d\n",
287 				    blk+cnt, sblock->fs_fpg);
288 			}
289 			return (1);
290 		}
291 	}
292 	return (0);
293 }
294 
295 /*
296  * General purpose interface for reading inodes.
297  */
298 struct dinode *
299 ginode(inumber)
300 	ino_t inumber;
301 {
302 	ufs_daddr_t iblk;
303 	int blkoff;
304 
305 	if (inumber < ROOTINO || inumber > maxino)
306 		errx(EEXIT, "bad inode number %d to ginode", inumber);
307 	if (startinum == 0 ||
308 	    inumber < startinum || inumber >= startinum + INOPB(sblock)) {
309 		iblk = ino_to_fsba(sblock, inumber);
310 		if (pbp != 0)
311 			pbp->b_flags &= ~B_INUSE;
312 		pbp = getdatablk(iblk, sblock->fs_bsize);
313 		startinum = (inumber / INOPB(sblock)) * INOPB(sblock);
314 	}
315 	blkoff = (inumber % INOPB(sblock)) * DINODE_SIZE;
316 	return ((struct dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
317 }
318 
319 /*
320  * Special purpose version of ginode used to optimize first pass
321  * over all the inodes in numerical order.
322  */
323 ino_t nextino, lastinum;
324 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
325 struct dinode *inodebuf;
326 
327 struct dinode *
328 getnextinode(inumber)
329 	ino_t inumber;
330 {
331 	long size;
332 	ufs_daddr_t dblk;
333 	static struct dinode *dp;
334 
335 	if (inumber != nextino++ || inumber > maxino)
336 		errx(EEXIT, "bad inode number %d to nextinode", inumber);
337 	if (inumber >= lastinum) {
338 		readcnt++;
339 		dblk = fsbtodb(sblock, ino_to_fsba(sblock, lastinum));
340 		if (readcnt % readpercg == 0) {
341 			size = partialsize;
342 			lastinum += partialcnt;
343 		} else {
344 			size = inobufsize;
345 			lastinum += fullcnt;
346 		}
347 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
348 		if (doswap) {
349 			int i, j;
350 			for (i = inumber, dp  = inodebuf; i < lastinum; i++, dp++) {
351 				ffs_dinode_swap(dp, dp);
352 				/* ffs_dinode_swap() doesn't swap blocks addrs */
353 				if ((iswap16(dp->di_mode) & IFMT) != IFLNK ||
354 					iswap64(dp->di_size) > sblock->fs_maxsymlinklen) {
355 					for (j=0; j<NDADDR + NIADDR; j++)
356 						dp->di_db[j] = bswap32(dp->di_db[j]);
357 				}
358 			}
359 			bwrite(fswritefd, (char *)inodebuf, dblk, size);
360 		}
361 		dp = inodebuf;
362 	}
363 	return (dp++);
364 }
365 
366 void
367 resetinodebuf()
368 {
369 
370 	startinum = 0;
371 	nextino = 0;
372 	lastinum = 0;
373 	readcnt = 0;
374 	inobufsize = blkroundup(sblock, INOBUFSIZE);
375 	fullcnt = inobufsize / DINODE_SIZE;
376 	readpercg = sblock->fs_ipg / fullcnt;
377 	partialcnt = sblock->fs_ipg % fullcnt;
378 	partialsize = partialcnt * DINODE_SIZE;
379 	if (partialcnt != 0) {
380 		readpercg++;
381 	} else {
382 		partialcnt = fullcnt;
383 		partialsize = inobufsize;
384 	}
385 	if (inodebuf == NULL &&
386 	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
387 		errx(EEXIT, "Cannot allocate space for inode buffer");
388 	while (nextino < ROOTINO)
389 		(void)getnextinode(nextino);
390 }
391 
392 void
393 freeinodebuf()
394 {
395 
396 	if (inodebuf != NULL)
397 		free((char *)inodebuf);
398 	inodebuf = NULL;
399 }
400 
401 /*
402  * Routines to maintain information about directory inodes.
403  * This is built during the first pass and used during the
404  * second and third passes.
405  *
406  * Enter inodes into the cache.
407  */
408 void
409 cacheino(dp, inumber)
410 	struct dinode *dp;
411 	ino_t inumber;
412 {
413 	struct inoinfo *inp;
414 	struct inoinfo **inpp;
415 	unsigned int blks, extra;
416 
417 	blks = howmany(iswap64(dp->di_size), sblock->fs_bsize);
418 	if (blks > NDADDR)
419 		blks = NDADDR + NIADDR;
420 	if (blks > 0)
421 		extra =  (blks - 1) * sizeof(ufs_daddr_t);
422 	else
423 		extra = 0;
424 	inp = (struct inoinfo *) malloc(sizeof(*inp) + extra);
425 	if (inp == NULL)
426 		return;
427 	inpp = &inphead[inumber % numdirs];
428 	inp->i_nexthash = *inpp;
429 	*inpp = inp;
430 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
431 	if (inumber == ROOTINO)
432 		inp->i_parent = ROOTINO;
433 	else
434 		inp->i_parent = (ino_t)0;
435 	inp->i_dotdot = (ino_t)0;
436 	inp->i_number = inumber;
437 	inp->i_isize = iswap64(dp->di_size);
438 	inp->i_numblks = blks * sizeof(ufs_daddr_t);
439 	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
440 	if (inplast == listmax) {
441 		listmax += 100;
442 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
443 		    (unsigned)listmax * sizeof(struct inoinfo *));
444 		if (inpsort == NULL)
445 			errx(EEXIT, "cannot increase directory list");
446 	}
447 	inpsort[inplast++] = inp;
448 }
449 
450 /*
451  * Look up an inode cache structure.
452  */
453 struct inoinfo *
454 getinoinfo(inumber)
455 	ino_t inumber;
456 {
457 	struct inoinfo *inp;
458 
459 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
460 		if (inp->i_number != inumber)
461 			continue;
462 		return (inp);
463 	}
464 	errx(EEXIT, "cannot find inode %d", inumber);
465 	return ((struct inoinfo *)0);
466 }
467 
468 /*
469  * Clean up all the inode cache structure.
470  */
471 void
472 inocleanup()
473 {
474 	struct inoinfo **inpp;
475 
476 	if (inphead == NULL)
477 		return;
478 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
479 		free((char *)(*inpp));
480 	free((char *)inphead);
481 	free((char *)inpsort);
482 	inphead = inpsort = NULL;
483 }
484 
485 void
486 inodirty()
487 {
488 
489 	dirty(pbp);
490 }
491 
492 void
493 clri(idesc, type, flag)
494 	struct inodesc *idesc;
495 	char *type;
496 	int flag;
497 {
498 	struct dinode *dp;
499 
500 	dp = ginode(idesc->id_number);
501 	if (flag == 1) {
502 		pwarn("%s %s", type,
503 		    (iswap16(dp->di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
504 		pinode(idesc->id_number);
505 	}
506 	if (preen || reply("CLEAR") == 1) {
507 		if (preen)
508 			printf(" (CLEARED)\n");
509 		n_files--;
510 		(void)ckinode(dp, idesc);
511 		clearinode(dp);
512 		statemap[idesc->id_number] = USTATE;
513 		inodirty();
514 	} else
515 		markclean=  0;
516 }
517 
518 int
519 findname(idesc)
520 	struct inodesc *idesc;
521 {
522 	struct direct *dirp = idesc->id_dirp;
523 
524 	if (iswap32(dirp->d_ino) != idesc->id_parent)
525 		return (KEEPON);
526 	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
527 	return (STOP|FOUND);
528 }
529 
530 int
531 findino(idesc)
532 	struct inodesc *idesc;
533 {
534 	struct direct *dirp = idesc->id_dirp;
535 
536 	if (dirp->d_ino == 0)
537 		return (KEEPON);
538 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
539 	    iswap32(dirp->d_ino) >= ROOTINO && iswap32(dirp->d_ino) <= maxino) {
540 		idesc->id_parent = iswap32(dirp->d_ino);
541 		return (STOP|FOUND);
542 	}
543 	return (KEEPON);
544 }
545 
546 void
547 pinode(ino)
548 	ino_t ino;
549 {
550 	struct dinode *dp;
551 	char *p;
552 	struct passwd *pw;
553 	time_t t;
554 
555 	printf(" I=%u ", ino);
556 	if (ino < ROOTINO || ino > maxino)
557 		return;
558 	dp = ginode(ino);
559 	printf(" OWNER=");
560 #ifndef SMALL
561 	if ((pw = getpwuid((int)iswap32(dp->di_uid))) != 0)
562 		printf("%s ", pw->pw_name);
563 	else
564 #endif
565 		printf("%u ", (unsigned)iswap32(dp->di_uid));
566 	printf("MODE=%o\n", iswap16(dp->di_mode));
567 	if (preen)
568 		printf("%s: ", cdevname());
569 	printf("SIZE=%llu ", (unsigned long long)iswap64(dp->di_size));
570 	t = iswap32(dp->di_mtime);
571 	p = ctime(&t);
572 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
573 }
574 
575 void
576 blkerror(ino, type, blk)
577 	ino_t ino;
578 	char *type;
579 	ufs_daddr_t blk;
580 {
581 
582 	pfatal("%d %s I=%u", blk, type, ino);
583 	printf("\n");
584 	switch (statemap[ino]) {
585 
586 	case FSTATE:
587 		statemap[ino] = FCLEAR;
588 		return;
589 
590 	case DSTATE:
591 		statemap[ino] = DCLEAR;
592 		return;
593 
594 	case FCLEAR:
595 	case DCLEAR:
596 		return;
597 
598 	default:
599 		errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
600 		/* NOTREACHED */
601 	}
602 }
603 
604 /*
605  * allocate an unused inode
606  */
607 ino_t
608 allocino(request, type)
609 	ino_t request;
610 	int type;
611 {
612 	ino_t ino;
613 	struct dinode *dp;
614 	time_t t;
615 	struct cg *cgp = cgrp;
616 	int cg;
617 
618 	if (request == 0)
619 		request = ROOTINO;
620 	else if (statemap[request] != USTATE)
621 		return (0);
622 	for (ino = request; ino < maxino; ino++)
623 		if (statemap[ino] == USTATE)
624 			break;
625 	if (ino == maxino)
626 		return (0);
627 	cg = ino_to_cg(sblock, ino);
628 	getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
629 	memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
630 	if ((doswap && !needswap) || (!doswap && needswap))
631 		swap_cg(cgblk.b_un.b_cg, cgp);
632 	if (!cg_chkmagic(cgp, 0))
633 		pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg);
634 	if (doswap)
635 		cgdirty();
636 	setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
637 	cgp->cg_cs.cs_nifree--;
638 	switch (type & IFMT) {
639 	case IFDIR:
640 		statemap[ino] = DSTATE;
641 		cgp->cg_cs.cs_ndir++;
642 		break;
643 	case IFREG:
644 	case IFLNK:
645 		statemap[ino] = FSTATE;
646 		break;
647 	default:
648 		return (0);
649 	}
650 	cgdirty();
651 	dp = ginode(ino);
652 	dp->di_db[0] = iswap32(allocblk((long)1));
653 	if (dp->di_db[0] == 0) {
654 		statemap[ino] = USTATE;
655 		return (0);
656 	}
657 	dp->di_mode = iswap16(type);
658 	dp->di_flags = 0;
659 	(void)time(&t);
660 	dp->di_atime = iswap32(t);
661 	dp->di_mtime = dp->di_ctime = dp->di_atime;
662 	dp->di_size = iswap64(sblock->fs_fsize);
663 	dp->di_blocks = iswap32(btodb(sblock->fs_fsize));
664 	n_files++;
665 	inodirty();
666 	if (newinofmt)
667 		typemap[ino] = IFTODT(type);
668 	return (ino);
669 }
670 
671 /*
672  * deallocate an inode
673  */
674 void
675 freeino(ino)
676 	ino_t ino;
677 {
678 	struct inodesc idesc;
679 	struct dinode *dp;
680 
681 	memset(&idesc, 0, sizeof(struct inodesc));
682 	idesc.id_type = ADDR;
683 	idesc.id_func = pass4check;
684 	idesc.id_number = ino;
685 	dp = ginode(ino);
686 	(void)ckinode(dp, &idesc);
687 	clearinode(dp);
688 	inodirty();
689 	statemap[ino] = USTATE;
690 	n_files--;
691 }
692