xref: /netbsd-src/sbin/fsck_lfs/inode.c (revision a74e29fe24406e588e4c7ad6d03168a00d009bc1)
1 /* $NetBSD: inode.c,v 1.70 2020/04/03 19:36:33 joerg 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 "lfs_user.h"
84 
85 #include "fsck.h"
86 #include "fsutil.h"
87 #include "extern.h"
88 
89 static int iblock(struct inodesc *, long, u_int64_t);
90 int blksreqd(struct lfs *, int);
91 int lfs_maxino(void);
92 
93 /*
94  * Get a dinode of a given inum.
95  * XXX combine this function with vget.
96  */
97 union lfs_dinode *
ginode(ino_t ino)98 ginode(ino_t ino)
99 {
100 	struct uvnode *vp;
101 	struct ubuf *bp;
102 	IFILE *ifp;
103 	daddr_t daddr;
104 	unsigned segno;
105 
106 	vp = vget(fs, ino);
107 	if (vp == NULL)
108 		return NULL;
109 
110 	if (din_table[ino] == 0x0) {
111 		LFS_IENTRY(ifp, fs, ino, bp);
112 		daddr = lfs_if_getdaddr(fs, ifp);
113 		segno = lfs_dtosn(fs, daddr);
114 		din_table[ino] = daddr;
115 		seg_table[segno].su_nbytes += DINOSIZE(fs);
116 		brelse(bp, 0);
117 	}
118 	return VTOI(vp)->i_din;
119 }
120 
121 /*
122  * Check validity of held blocks in an inode, recursing through all blocks.
123  */
124 int
ckinode(union lfs_dinode * dp,struct inodesc * idesc)125 ckinode(union lfs_dinode *dp, struct inodesc *idesc)
126 {
127 	daddr_t lbn, pbn;
128 	long ret, n, ndb, offset;
129 	union lfs_dinode dino;
130 	u_int64_t remsize, sizepb;
131 	mode_t mode;
132 	char pathbuf[MAXPATHLEN + 1];
133 	struct uvnode *vp, *thisvp;
134 
135 	if (idesc->id_fix != IGNORE)
136 		idesc->id_fix = DONTKNOW;
137 	idesc->id_entryno = 0;
138 	idesc->id_filesize = lfs_dino_getsize(fs, dp);
139 	mode = lfs_dino_getmode(fs, dp) & LFS_IFMT;
140 	if (mode == LFS_IFBLK || mode == LFS_IFCHR ||
141 	    (mode == LFS_IFLNK && (lfs_dino_getsize(fs, dp) < lfs_sb_getmaxsymlinklen(fs) ||
142 		    (lfs_sb_getmaxsymlinklen(fs) == 0 &&
143 			lfs_dino_getblocks(fs, dp) == 0))))
144 		return (KEEPON);
145 	/* XXX is this safe if we're 32-bit? */
146 	dino = *dp;
147 	ndb = howmany(lfs_dino_getsize(fs, &dino), lfs_sb_getbsize(fs));
148 
149 	thisvp = vget(fs, idesc->id_number);
150 	for (lbn = 0; lbn < ULFS_NDADDR; lbn++) {
151 		pbn = lfs_dino_getdb(fs, &dino, lbn);
152 		if (thisvp)
153 			idesc->id_numfrags =
154 				lfs_numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
155 		else {
156 			if (--ndb == 0 && (offset = lfs_blkoff(fs, lfs_dino_getsize(fs, &dino))) != 0) {
157 				idesc->id_numfrags =
158 			    	lfs_numfrags(fs, lfs_fragroundup(fs, offset));
159 			} else
160 				idesc->id_numfrags = lfs_sb_getfrag(fs);
161 		}
162 		if (pbn == 0) {
163 			if (idesc->id_type == DATA && ndb >= 0) {
164 				/* An empty block in a directory XXX */
165 				getpathname(pathbuf, sizeof(pathbuf),
166 				    idesc->id_number, idesc->id_number);
167 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]",
168 				    pathbuf, (long long)idesc->id_number);
169 				if (reply("ADJUST LENGTH") == 1) {
170 					vp = vget(fs, idesc->id_number);
171 					dp = VTOD(vp);
172 					lfs_dino_setsize(fs, dp,
173 					    lbn * lfs_sb_getbsize(fs));
174 					printf(
175 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
176 					rerun = 1;
177 					inodirty(VTOI(vp));
178 				} else
179 					break;
180 			}
181 			continue;
182 		}
183 		idesc->id_blkno = pbn;
184 		idesc->id_lblkno = lbn;
185 		if (idesc->id_type == ADDR) {
186 			ret = (*idesc->id_func) (idesc);
187 		} else
188 			ret = dirscan(idesc);
189 		if (ret & STOP)
190 			return (ret);
191 	}
192 	idesc->id_numfrags = lfs_sb_getfrag(fs);
193 	remsize = lfs_dino_getsize(fs, &dino) - lfs_sb_getbsize(fs) * ULFS_NDADDR;
194 	sizepb = lfs_sb_getbsize(fs);
195 	for (n = 1; n <= ULFS_NIADDR; n++) {
196 		pbn = lfs_dino_getib(fs, &dino, n-1);
197 		if (pbn) {
198 			idesc->id_blkno = pbn;
199 			ret = iblock(idesc, n, remsize);
200 			if (ret & STOP)
201 				return (ret);
202 		} else {
203 			if (idesc->id_type == DATA && remsize > 0) {
204 				/* An empty block in a directory XXX */
205 				getpathname(pathbuf, sizeof(pathbuf),
206 				    idesc->id_number, idesc->id_number);
207 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]",
208 				    pathbuf, (long long)idesc->id_number);
209 				if (reply("ADJUST LENGTH") == 1) {
210 					vp = vget(fs, idesc->id_number);
211 					dp = VTOD(vp);
212 					lfs_dino_setsize(fs, dp,
213 					    lfs_dino_getsize(fs, dp) - remsize);
214 					remsize = 0;
215 					printf(
216 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
217 					rerun = 1;
218 					inodirty(VTOI(vp));
219 					break;
220 				} else
221 					break;
222 			}
223 		}
224 		sizepb *= LFS_NINDIR(fs);
225 		remsize -= sizepb;
226 	}
227 	return (KEEPON);
228 }
229 
230 static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)231 iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
232 {
233 	unsigned j, maxindir;
234 	daddr_t found;
235 	struct ubuf *bp;
236 	int i, n, (*func) (struct inodesc *), nif;
237 	u_int64_t sizepb;
238 	char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
239 	struct uvnode *devvp, *vp;
240 	int diddirty = 0;
241 
242 	if (idesc->id_type == ADDR) {
243 		func = idesc->id_func;
244 		n = (*func) (idesc);
245 		if ((n & KEEPON) == 0)
246 			return (n);
247 	} else
248 		func = dirscan;
249 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
250 		return (SKIP);
251 
252 	devvp = fs->lfs_devvp;
253 	bread(devvp, LFS_FSBTODB(fs, idesc->id_blkno), lfs_sb_getbsize(fs),
254 	    0, &bp);
255 	ilevel--;
256 	for (sizepb = lfs_sb_getbsize(fs), i = 0; i < ilevel; i++)
257 		sizepb *= LFS_NINDIR(fs);
258 	if (isize > sizepb * LFS_NINDIR(fs))
259 		nif = LFS_NINDIR(fs);
260 	else
261 		nif = howmany(isize, sizepb);
262 	if (idesc->id_func == pass1check && nif < LFS_NINDIR(fs)) {
263 		maxindir = LFS_NINDIR(fs);
264 		for (j = nif; j < maxindir; j++) {
265 			found = lfs_iblock_get(fs, bp->b_data, j);
266 			if (found == 0)
267 				continue;
268 			(void)snprintf(buf, sizeof(buf),
269 			    "PARTIALLY TRUNCATED INODE I=%llu",
270 			    (unsigned long long)idesc->id_number);
271 			if (dofix(idesc, buf)) {
272 				lfs_iblock_set(fs, bp->b_data, j, 0);
273 				++diddirty;
274 			}
275 		}
276 	}
277 	maxindir = nif;
278 	for (j = 0; j < maxindir; j++) {
279 		found = lfs_iblock_get(fs, bp->b_data, j);
280 		if (found) {
281 			idesc->id_blkno = found;
282 			if (ilevel == 0) {
283 				/*
284 				 * dirscan needs lfs_lblkno.
285 				 */
286 				idesc->id_lblkno++;
287 				n = (*func) (idesc);
288 			} else {
289 				n = iblock(idesc, ilevel, isize);
290 			}
291 			if (n & STOP) {
292 				if (diddirty)
293 					VOP_BWRITE(bp);
294 				else
295 					brelse(bp, 0);
296 				return (n);
297 			}
298 		} else {
299 			if (idesc->id_type == DATA && isize > 0) {
300 				/* An empty block in a directory XXX */
301 				getpathname(pathbuf, sizeof(pathbuf),
302 				    idesc->id_number, idesc->id_number);
303 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]",
304 				    pathbuf, (long long)idesc->id_number);
305 				if (reply("ADJUST LENGTH") == 1) {
306 					vp = vget(fs, idesc->id_number);
307 					lfs_dino_setsize(fs, VTOI(vp)->i_din,
308 					    lfs_dino_getsize(fs,
309 							     VTOI(vp)->i_din)
310 					    - isize);
311 					isize = 0;
312 					printf(
313 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
314 					rerun = 1;
315 					inodirty(VTOI(vp));
316 					if (diddirty)
317 						VOP_BWRITE(bp);
318 					else
319 						brelse(bp, 0);
320 					return (STOP);
321 				}
322 			}
323 		}
324 		isize -= sizepb;
325 	}
326 	if (diddirty)
327 		VOP_BWRITE(bp);
328 	else
329 		brelse(bp, 0);
330 	return (KEEPON);
331 }
332 
333 /*
334  * Check that a block in a legal block number.
335  * Return 0 if in range, 1 if out of range.
336  */
337 int
chkrange(daddr_t blk,int cnt)338 chkrange(daddr_t blk, int cnt)
339 {
340 	if (blk < lfs_sntod(fs, 0)) {
341 		return (1);
342 	}
343 	if (blk > maxfsblock) {
344 		return (1);
345 	}
346 	if (blk + cnt < lfs_sntod(fs, 0)) {
347 		return (1);
348 	}
349 	if (blk + cnt > maxfsblock) {
350 		return (1);
351 	}
352 	return (0);
353 }
354 
355 /*
356  * Routines to maintain information about directory inodes.
357  * This is built during the first pass and used during the
358  * second and third passes.
359  *
360  * Enter inodes into the cache.
361  */
362 void
cacheino(union lfs_dinode * dp,ino_t inumber)363 cacheino(union lfs_dinode *dp, ino_t inumber)
364 {
365 	struct inoinfo *inp;
366 	struct inoinfo **inpp, **ninpsort;
367 	unsigned int blks, i;
368 
369 	blks = howmany(lfs_dino_getsize(fs, dp), lfs_sb_getbsize(fs));
370 	if (blks > ULFS_NDADDR)
371 		blks = ULFS_NDADDR + ULFS_NIADDR;
372 	inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(inp->i_blks[0]));
373 	inpp = &inphead[inumber % numdirs];
374 	inp->i_nexthash = *inpp;
375 	*inpp = inp;
376 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
377 	if (inumber == ULFS_ROOTINO)
378 		inp->i_parent = ULFS_ROOTINO;
379 	else
380 		inp->i_parent = (ino_t) 0;
381 	inp->i_dotdot = (ino_t) 0;
382 	inp->i_number = inumber;
383 	inp->i_isize = lfs_dino_getsize(fs, dp);
384 
385 	inp->i_numblks = blks * sizeof(inp->i_blks[0]);
386 	for (i=0; i<blks && i<ULFS_NDADDR; i++) {
387 		inp->i_blks[i] = lfs_dino_getdb(fs, dp, i);
388 	}
389 	for (; i<blks; i++) {
390 		inp->i_blks[i] = lfs_dino_getib(fs, dp, i - ULFS_NDADDR);
391 	}
392 	if (inplast == listmax) {
393 		ninpsort = erealloc(inpsort,
394 		    (listmax + 100) * sizeof(struct inoinfo *));
395 		inpsort = ninpsort;
396 		listmax += 100;
397 	}
398 	inpsort[inplast++] = inp;
399 }
400 
401 /*
402  * Look up an inode cache structure.
403  */
404 struct inoinfo *
getinoinfo(ino_t inumber)405 getinoinfo(ino_t inumber)
406 {
407 	struct inoinfo *inp;
408 
409 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
410 		if (inp->i_number != inumber)
411 			continue;
412 		return (inp);
413 	}
414 	err(EEXIT, "cannot find inode %llu", (unsigned long long)inumber);
415 	return ((struct inoinfo *) 0);
416 }
417 
418 /*
419  * Clean up all the inode cache structure.
420  */
421 void
inocleanup(void)422 inocleanup(void)
423 {
424 	struct inoinfo **inpp;
425 
426 	if (inphead == NULL)
427 		return;
428 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
429 		free((char *) (*inpp));
430 	free((char *) inphead);
431 	free((char *) inpsort);
432 	inphead = inpsort = NULL;
433 }
434 
435 void
inodirty(struct inode * ip)436 inodirty(struct inode *ip)
437 {
438 	ip->i_state |= IN_MODIFIED;
439 }
440 
441 void
clri(struct inodesc * idesc,const char * type,int flag)442 clri(struct inodesc * idesc, const char *type, int flag)
443 {
444 	struct uvnode *vp;
445 
446 	vp = vget(fs, idesc->id_number);
447 	if (flag & 0x1) {
448 		pwarn("%s %s", type,
449 		      (lfs_dino_getmode(fs, VTOI(vp)->i_din) & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE");
450 		pinode(idesc->id_number);
451 	}
452 	if ((flag & 0x2) || preen || reply("CLEAR") == 1) {
453 		if (preen && flag != 2)
454 			printf(" (CLEARED)\n");
455 		n_files--;
456 		(void) ckinode(VTOD(vp), idesc);
457 		clearinode(idesc->id_number);
458 		statemap[idesc->id_number] = USTATE;
459 		vnode_destroy(vp);
460 		return;
461 	}
462 	return;
463 }
464 
465 void
clearinode(ino_t inumber)466 clearinode(ino_t inumber)
467 {
468 	struct ubuf *bp;
469 	IFILE *ifp;
470 	daddr_t daddr;
471 
472 	/* Send cleared inode to the free list */
473 
474 	LFS_IENTRY(ifp, fs, inumber, bp);
475 	daddr = lfs_if_getdaddr(fs, ifp);
476 	if (daddr == LFS_UNUSED_DADDR) {
477 		brelse(bp, 0);
478 		return;
479 	}
480 	lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
481 	lfs_if_setnextfree(fs, ifp, lfs_sb_getfreehd(fs));
482 	lfs_sb_setfreehd(fs, inumber);
483 	sbdirty();
484 	VOP_BWRITE(bp);
485 
486 	/*
487 	 * update segment usage.
488 	 */
489 	if (daddr != LFS_UNUSED_DADDR) {
490 		SEGUSE *sup;
491 		u_int32_t oldsn = lfs_dtosn(fs, daddr);
492 
493 		seg_table[oldsn].su_nbytes -= DINOSIZE(fs);
494 		LFS_SEGENTRY(sup, fs, oldsn, bp);
495 		sup->su_nbytes -= DINOSIZE(fs);
496 		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);	/* Ifile */
497 	}
498 }
499 
500 int
findname(struct inodesc * idesc)501 findname(struct inodesc * idesc)
502 {
503 	LFS_DIRHEADER *dirp = idesc->id_dirp;
504 	size_t len;
505 	char *buf;
506 
507 	if (lfs_dir_getino(fs, dirp) != idesc->id_parent)
508 		return (KEEPON);
509 	len = lfs_dir_getnamlen(fs, dirp) + 1;
510 	if (len > MAXPATHLEN) {
511 		/* Truncate it but don't overflow the buffer */
512 		/* XXX: this case doesn't null-terminate the result */
513 		len = MAXPATHLEN;
514 	}
515 	/* this is namebuf with utils.h */
516 	buf = __UNCONST(idesc->id_name);
517 	(void)memcpy(buf, lfs_dir_nameptr(fs, dirp), len);
518 	return (STOP | FOUND);
519 }
520 
521 int
findino(struct inodesc * idesc)522 findino(struct inodesc * idesc)
523 {
524 	LFS_DIRHEADER *dirp = idesc->id_dirp;
525 	ino_t ino;
526 
527 	ino = lfs_dir_getino(fs, dirp);
528 	if (ino == 0)
529 		return (KEEPON);
530 	if (strcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name) == 0 &&
531 	    ino >= ULFS_ROOTINO && ino < maxino) {
532 		idesc->id_parent = ino;
533 		return (STOP | FOUND);
534 	}
535 	return (KEEPON);
536 }
537 
538 void
pinode(ino_t ino)539 pinode(ino_t ino)
540 {
541 	union lfs_dinode *dp;
542 	struct passwd *pw;
543 
544 	printf(" I=%llu ", (unsigned long long)ino);
545 	if (ino < ULFS_ROOTINO || ino >= maxino)
546 		return;
547 	dp = ginode(ino);
548 	if (dp) {
549 		printf(" OWNER=");
550 #ifndef SMALL
551 		if (Uflag && (pw = getpwuid(lfs_dino_getuid(fs, dp))) != 0)
552 			printf("%s ", pw->pw_name);
553 		else
554 #endif
555 			printf("%u ", (unsigned)lfs_dino_getuid(fs, dp));
556 		printf("MODE=%o\n", lfs_dino_getmode(fs, dp));
557 		if (preen)
558 			printf("%s: ", cdevname());
559 		printf("SIZE=%ju ", (uintmax_t) lfs_dino_getsize(fs, dp));
560 		printf("MTIME=%s ", print_mtime(lfs_dino_getmtime(fs, dp)));
561 	}
562 }
563 
564 void
blkerror(ino_t ino,const char * type,daddr_t blk)565 blkerror(ino_t ino, const char *type, daddr_t blk)
566 {
567 
568 	pfatal("%lld %s I=%llu", (long long) blk, type,
569 	    (unsigned long long)ino);
570 	printf("\n");
571 	if (exitonfail)
572 		exit(1);
573 	switch (statemap[ino]) {
574 
575 	case FSTATE:
576 		statemap[ino] = FCLEAR;
577 		return;
578 
579 	case DSTATE:
580 		statemap[ino] = DCLEAR;
581 		return;
582 
583 	case FCLEAR:
584 	case DCLEAR:
585 		return;
586 
587 	default:
588 		err(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
589 		/* NOTREACHED */
590 	}
591 }
592 
593 /*
594  * allocate an unused inode
595  */
596 ino_t
allocino(ino_t request,int type)597 allocino(ino_t request, int type)
598 {
599 	ino_t ino;
600 	union lfs_dinode *dp;
601 	time_t t;
602 	struct uvnode *vp;
603 	struct ubuf *bp;
604 
605 	if (request == 0)
606 		request = ULFS_ROOTINO;
607 	else if (statemap[request] != USTATE)
608 		return (0);
609 	for (ino = request; ino < maxino; ino++)
610 		if (statemap[ino] == USTATE)
611 			break;
612 	if (ino == maxino)
613 		extend_ifile(fs);
614 
615 	switch (type & LFS_IFMT) {
616 	case LFS_IFDIR:
617 		statemap[ino] = DSTATE;
618 		break;
619 	case LFS_IFREG:
620 	case LFS_IFLNK:
621 		statemap[ino] = FSTATE;
622 		break;
623 	default:
624 		return (0);
625 	}
626         vp = lfs_valloc(fs, ino);
627 	if (vp == NULL)
628 		return (0);
629 	dp = VTOI(vp)->i_din;
630 	bp = getblk(vp, 0, lfs_sb_getfsize(fs));
631 	VOP_BWRITE(bp);
632 	lfs_dino_setmode(fs, dp, type);
633 	(void) time(&t);
634 	lfs_dino_setatime(fs, dp, t);
635 	lfs_dino_setctime(fs, dp, t);
636 	lfs_dino_setmtime(fs, dp, t);
637 	lfs_dino_setsize(fs, dp, lfs_sb_getfsize(fs));
638 	lfs_dino_setblocks(fs, dp, lfs_btofsb(fs, lfs_sb_getfsize(fs)));
639 	n_files++;
640 	inodirty(VTOI(vp));
641 	typemap[ino] = LFS_IFTODT(type);
642 	return (ino);
643 }
644 
645 /*
646  * deallocate an inode
647  */
648 void
freeino(ino_t ino)649 freeino(ino_t ino)
650 {
651 	struct inodesc idesc;
652 	struct uvnode *vp;
653 
654 	memset(&idesc, 0, sizeof(struct inodesc));
655 	idesc.id_type = ADDR;
656 	idesc.id_func = pass4check;
657 	idesc.id_number = ino;
658 	vp = vget(fs, ino);
659 	(void) ckinode(VTOD(vp), &idesc);
660 	clearinode(ino);
661 	statemap[ino] = USTATE;
662 	vnode_destroy(vp);
663 
664 	n_files--;
665 }
666