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