10Sstevel@tonic-gate /*
2392Sswilcox * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
70Sstevel@tonic-gate /* All Rights Reserved */
80Sstevel@tonic-gate
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
110Sstevel@tonic-gate * All rights reserved.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
140Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
150Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
160Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
170Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
180Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
190Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
200Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
210Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
220Sstevel@tonic-gate * from this software without specific prior written permission.
230Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
240Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
250Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
290Sstevel@tonic-gate
30392Sswilcox #include <stdio.h>
31392Sswilcox #include <stdlib.h>
32392Sswilcox #include <unistd.h>
33392Sswilcox #include <string.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/mntent.h>
370Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
380Sstevel@tonic-gate #include <sys/vnode.h>
390Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
400Sstevel@tonic-gate #define _KERNEL
410Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
420Sstevel@tonic-gate #undef _KERNEL
430Sstevel@tonic-gate #include "fsck.h"
440Sstevel@tonic-gate
45392Sswilcox static int pass3acheck(struct inodesc *);
460Sstevel@tonic-gate static void setcurino(struct inodesc *, struct dinode *, struct inoinfo *);
470Sstevel@tonic-gate
48392Sswilcox void
pass3a(void)49392Sswilcox pass3a(void)
500Sstevel@tonic-gate {
51392Sswilcox caddr_t flow;
520Sstevel@tonic-gate struct inoinfo **inpp, *inp;
53392Sswilcox fsck_ino_t orphan;
540Sstevel@tonic-gate int loopcnt;
55392Sswilcox int state;
56392Sswilcox struct shadowclientinfo *sci, *sci_victim, *sci_prev, **sci_rootp;
570Sstevel@tonic-gate struct inodesc curino;
580Sstevel@tonic-gate struct dinode *dp;
59392Sswilcox struct inodesc idesc;
60392Sswilcox char namebuf[MAXNAMLEN + 1];
610Sstevel@tonic-gate
620Sstevel@tonic-gate for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
630Sstevel@tonic-gate inp = *inpp;
64392Sswilcox state = statemap[inp->i_number];
650Sstevel@tonic-gate if (inp->i_number == UFSROOTINO ||
66392Sswilcox (inp->i_parent != 0 && !S_IS_DUNFOUND(state)))
67392Sswilcox continue;
68392Sswilcox if (state == DCLEAR || state == USTATE || (state & INORPHAN))
690Sstevel@tonic-gate continue;
70392Sswilcox /*
71392Sswilcox * If we are running with logging and we come
72392Sswilcox * across unreferenced directories, we just leave
73392Sswilcox * them in DSTATE which will cause them to be pitched
74392Sswilcox * in pass 4.
75392Sswilcox */
76392Sswilcox if (preen && !iscorrupt && islog && S_IS_DUNFOUND(state)) {
77392Sswilcox if (inp->i_dotdot >= UFSROOTINO) {
78392Sswilcox LINK_RANGE(flow, lncntp[inp->i_dotdot], 1);
79392Sswilcox if (flow != NULL) {
80392Sswilcox dp = ginode(inp->i_dotdot);
81392Sswilcox LINK_CLEAR(flow, inp->i_dotdot,
82392Sswilcox dp->di_mode, &idesc);
83392Sswilcox if (statemap[inp->i_dotdot] == USTATE)
84392Sswilcox continue;
85392Sswilcox }
86392Sswilcox TRACK_LNCNTP(inp->i_dotdot,
87392Sswilcox lncntp[inp->i_dotdot]++);
88392Sswilcox }
890Sstevel@tonic-gate continue;
90392Sswilcox }
91392Sswilcox
920Sstevel@tonic-gate for (loopcnt = 0; ; loopcnt++) {
930Sstevel@tonic-gate orphan = inp->i_number;
94392Sswilcox /*
95392Sswilcox * Skip out if we aren't connected to the name
96392Sswilcox * space, or our parent is connected, or we've
97392Sswilcox * looked at too many directories. Our parent
98392Sswilcox * being connected means that orphan is the
99392Sswilcox * first ancestor of *inpp with questionable
100392Sswilcox * antecedents.
101392Sswilcox */
1020Sstevel@tonic-gate if (inp->i_parent == 0 ||
103392Sswilcox !INO_IS_DUNFOUND(inp->i_parent) ||
1040Sstevel@tonic-gate loopcnt > numdirs)
1050Sstevel@tonic-gate break;
1060Sstevel@tonic-gate inp = getinoinfo(inp->i_parent);
107392Sswilcox /*
108392Sswilcox * Can't happen, because a non-zero parent's already
109392Sswilcox * been seen and therefore cached.
110392Sswilcox */
111392Sswilcox if (inp == NULL)
112392Sswilcox errexit("pass3 could not find cached "
113392Sswilcox "inode I=%d\n",
114392Sswilcox inp->i_parent);
1150Sstevel@tonic-gate }
116392Sswilcox
117392Sswilcox /*
118392Sswilcox * Already did this one. Don't bother the user
119392Sswilcox * with redundant questions.
120392Sswilcox */
121392Sswilcox if (statemap[orphan] & INORPHAN)
122392Sswilcox continue;
123392Sswilcox
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * A link count of 0 with parent and .. inodes of 0
1260Sstevel@tonic-gate * indicates a partly deleted directory.
1270Sstevel@tonic-gate * Clear it.
1280Sstevel@tonic-gate */
129392Sswilcox dp = ginode(orphan);
1300Sstevel@tonic-gate if (dp->di_nlink == 0 && inp->i_dotdot == 0 &&
1310Sstevel@tonic-gate inp->i_parent == 0) {
132392Sswilcox /*
133392Sswilcox * clri() just uses curino.id_number; in other
134392Sswilcox * words, it won't use the callback that setcurino()
135392Sswilcox * puts in.
136392Sswilcox */
1370Sstevel@tonic-gate setcurino(&curino, dp, inp);
138392Sswilcox clri(&curino, "UNREF", CLRI_VERBOSE, CLRI_NOP_OK);
139392Sswilcox
140392Sswilcox /*
141392Sswilcox * If we didn't clear it, at least mark it so
142392Sswilcox * we don't waste time on it again.
143392Sswilcox */
144392Sswilcox if (statemap[orphan] != USTATE) {
145392Sswilcox statemap[orphan] |= INORPHAN;
146392Sswilcox }
147392Sswilcox continue;
148392Sswilcox }
149392Sswilcox
150392Sswilcox /*
151392Sswilcox * We can call linkup() multiple times on the same directory
152392Sswilcox * inode, if we were told not to reconnect it the first time.
153392Sswilcox * This is because we find it as a disconnected parent of
154392Sswilcox * of its children (and mark it found), and then finally get
155392Sswilcox * to it in the inpsort array. This is better than in the
156392Sswilcox * past, where we'd call it every time we found it as a
157392Sswilcox * child's parent. Ideally, we'd suppress even the second
158392Sswilcox * query, but that confuses pass 4's interpretation of
159392Sswilcox * the state flags.
160392Sswilcox */
161392Sswilcox if (loopcnt <= countdirs) {
162392Sswilcox if (linkup(orphan, inp->i_dotdot, NULL)) {
163392Sswilcox /*
164392Sswilcox * Bookkeeping for any sort of relinked
165392Sswilcox * directory.
166392Sswilcox */
167392Sswilcox inp->i_dotdot = lfdir;
168392Sswilcox inp->i_parent = inp->i_dotdot;
169392Sswilcox statemap[orphan] &= ~(INORPHAN);
170392Sswilcox } else {
171392Sswilcox statemap[orphan] |= INORPHAN;
172392Sswilcox }
173392Sswilcox propagate();
1740Sstevel@tonic-gate continue;
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate
177392Sswilcox /*
178392Sswilcox * We visited more directories than exist in the
179392Sswilcox * filesystem. The only way to do that is if there's
180392Sswilcox * a loop.
181392Sswilcox */
182392Sswilcox pfatal("ORPHANED DIRECTORY LOOP DETECTED I=%d\n", orphan);
183392Sswilcox
184392Sswilcox /*
185392Sswilcox * Can never get here with inp->i_parent zero, because
186392Sswilcox * of the interactions between the for() and the
187392Sswilcox * if (loopcnt <= countdirs) above.
188392Sswilcox */
189392Sswilcox init_inodesc(&idesc);
190392Sswilcox idesc.id_type = DATA;
191392Sswilcox idesc.id_number = inp->i_parent;
192392Sswilcox idesc.id_parent = orphan;
193392Sswilcox idesc.id_func = findname;
194392Sswilcox idesc.id_name = namebuf;
195392Sswilcox namebuf[0] = '\0';
196392Sswilcox
197392Sswilcox /*
198392Sswilcox * Theoretically, this lookup via ckinode can't fail
199392Sswilcox * (if orphan doesn't exist in i_parent, then i_parent
200*504Sswilcox * would not have been filled in by pass2check()).
201392Sswilcox * However, if we're interactive, we want to at least
202392Sswilcox * attempt to continue. The worst case is that it
203392Sswilcox * gets reconnected as #nnn into lost+found instead of
204392Sswilcox * to its old parent with its old name.
205392Sswilcox */
206392Sswilcox if ((ckinode(ginode(inp->i_parent),
207392Sswilcox &idesc, CKI_TRAVERSE) & FOUND) == 0)
208392Sswilcox pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY");
209392Sswilcox
210392Sswilcox if (linkup(orphan, inp->i_parent, namebuf)) {
211392Sswilcox if (cleardirentry(inp->i_parent, orphan) & FOUND) {
212392Sswilcox LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], 1,
213392Sswilcox &idesc);
214392Sswilcox TRACK_LNCNTP(orphan, lncntp[orphan]++);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate inp->i_parent = inp->i_dotdot = lfdir;
217392Sswilcox LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], -1,
218392Sswilcox &idesc);
219392Sswilcox TRACK_LNCNTP(lfdir, lncntp[lfdir]--);
2200Sstevel@tonic-gate statemap[orphan] = DFOUND;
221392Sswilcox } else {
222392Sswilcox /*
223392Sswilcox * Represents a on-disk leak, not an inconsistency,
224392Sswilcox * so don't set iscorrupt. Such leaks are harmless
225392Sswilcox * in the context of discrepancies that the kernel
226392Sswilcox * will panic over.
227392Sswilcox *
228392Sswilcox * We don't care if tsearch() returns non-NULL
229392Sswilcox * != orphan, since there's no dynamic memory
230392Sswilcox * to free here.
231392Sswilcox */
232392Sswilcox if (tsearch((void *)orphan, &limbo_dirs,
233392Sswilcox ino_t_cmp) == NULL)
234392Sswilcox errexit("out of memory");
235392Sswilcox statemap[orphan] |= INORPHAN;
236392Sswilcox continue;
2370Sstevel@tonic-gate }
238392Sswilcox propagate();
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
241392Sswilcox /*
242392Sswilcox * The essence of the inner loop is to update the inode of
243392Sswilcox * every shadow or attribute inode's lncntp[] by the number of
244392Sswilcox * links we've found to them in pass 2 and above. Logically,
245392Sswilcox * all that is needed is just the one line:
246392Sswilcox *
247392Sswilcox * lncntp[sci->shadow] -= sci->totalclients;
248392Sswilcox *
249392Sswilcox * However, there's the possibility of wrapping the link count
250392Sswilcox * (this is especially true for shadows, which are expected to
251392Sswilcox * be shared amongst many files). This means that we have to
252392Sswilcox * range-check before changing anything, and if the check
253392Sswilcox * fails, offer to clear the shadow or attribute. If we do
254392Sswilcox * clear it, then we have to remove it from the linked list of
255392Sswilcox * all of the type of inodes that we're going through.
256392Sswilcox *
257392Sswilcox * Just to make things a little more complicated, these are
258392Sswilcox * singly-linked lists, so we have to do all the extra
259392Sswilcox * bookkeeping that goes along with that as well.
260392Sswilcox *
261392Sswilcox * The only connection between the shadowclientinfo and
262392Sswilcox * attrclientinfo lists is that they use the same underlying
263392Sswilcox * struct. Both need this scan, so the outer loop is just to
264392Sswilcox * pick which one we're working on at the moment. There is no
265392Sswilcox * requirement as to which of these lists is scanned first.
266392Sswilcox */
267392Sswilcox for (loopcnt = 0; loopcnt < 2; loopcnt++) {
268392Sswilcox if (loopcnt == 0)
269392Sswilcox sci_rootp = &shadowclientinfo;
270392Sswilcox else
271392Sswilcox sci_rootp = &attrclientinfo;
2720Sstevel@tonic-gate
273392Sswilcox sci = *sci_rootp;
274392Sswilcox sci_prev = NULL;
275392Sswilcox while (sci != NULL) {
276392Sswilcox sci_victim = NULL;
277392Sswilcox LINK_RANGE(flow, lncntp[sci->shadow],
278392Sswilcox -(sci->totalClients));
279392Sswilcox if (flow != NULL) {
280392Sswilcox /*
281392Sswilcox * Overflowed the link count.
282392Sswilcox */
283392Sswilcox dp = ginode(sci->shadow);
284392Sswilcox LINK_CLEAR(flow, sci->shadow, dp->di_mode,
285392Sswilcox &idesc);
286392Sswilcox if (statemap[sci->shadow] == USTATE) {
287392Sswilcox /*
288392Sswilcox * It's been cleared, fix the
289392Sswilcox * lists.
290392Sswilcox */
291392Sswilcox if (sci_prev == NULL) {
292392Sswilcox *sci_rootp = sci->next;
293392Sswilcox } else {
294392Sswilcox sci_prev->next = sci->next;
295392Sswilcox }
296392Sswilcox sci_victim = sci;
297392Sswilcox }
298392Sswilcox }
299392Sswilcox
300392Sswilcox /*
301392Sswilcox * If we did not clear the shadow, then we
302392Sswilcox * need to update the count and advance the
303392Sswilcox * previous pointer. Otherwise, finish the
304392Sswilcox * clean up once we're done with the struct.
305392Sswilcox */
306392Sswilcox if (sci_victim == NULL) {
307392Sswilcox TRACK_LNCNTP(sci->shadow,
308392Sswilcox lncntp[sci->shadow] -= sci->totalClients);
309392Sswilcox sci_prev = sci;
310392Sswilcox }
311392Sswilcox sci = sci->next;
312392Sswilcox if (sci_victim != NULL)
313392Sswilcox deshadow(sci_victim, NULL);
314392Sswilcox }
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate * This is used to verify the cflags of files
321392Sswilcox * under a directory that used to be an attrdir.
3220Sstevel@tonic-gate */
3230Sstevel@tonic-gate
324392Sswilcox static int
pass3acheck(struct inodesc * idesc)325392Sswilcox pass3acheck(struct inodesc *idesc)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate struct direct *dirp = idesc->id_dirp;
328392Sswilcox int n = 0, ret = 0;
3290Sstevel@tonic-gate struct dinode *dp, *pdirp;
330392Sswilcox int isattr;
331392Sswilcox int dirtype;
332392Sswilcox int inotype;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate if (dirp->d_ino == 0)
3350Sstevel@tonic-gate return (KEEPON);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate idesc->id_entryno++;
3380Sstevel@tonic-gate if ((strcmp(dirp->d_name, ".") == 0) ||
3390Sstevel@tonic-gate (strcmp(dirp->d_name, "..") == 0)) {
3400Sstevel@tonic-gate return (KEEPON);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
343392Sswilcox switch (statemap[dirp->d_ino] & ~(INDELAYD)) {
3440Sstevel@tonic-gate case DSTATE:
3450Sstevel@tonic-gate case DFOUND:
3460Sstevel@tonic-gate case FSTATE:
3470Sstevel@tonic-gate /*
348392Sswilcox * Accept DSTATE and DFOUND so we can handle normal
349392Sswilcox * directories as well as xattr directories.
350392Sswilcox *
3510Sstevel@tonic-gate * For extended attribute directories .. may point
3520Sstevel@tonic-gate * to a file. In this situation we don't want
3530Sstevel@tonic-gate * to decrement link count as it was already
354392Sswilcox * decremented when the entry was seen and decremented
3550Sstevel@tonic-gate * in the directory it actually lives in.
3560Sstevel@tonic-gate */
3570Sstevel@tonic-gate dp = ginode(dirp->d_ino);
3580Sstevel@tonic-gate isattr = (dp->di_cflags & IXATTR);
359392Sswilcox inotype = (dp->di_mode & IFMT);
3600Sstevel@tonic-gate pdirp = ginode(idesc->id_number);
3610Sstevel@tonic-gate dirtype = (pdirp->di_mode & IFMT);
362392Sswilcox /*
363392Sswilcox * IXATTR indicates that an object is itself an extended
364392Sswilcox * attribute. An IFMT of IFATTRDIR means we are looking
365392Sswilcox * at a directory which contains files which should all
366392Sswilcox * have IXATTR set. The IFATTRDIR case was handled in
367392Sswilcox * pass 2b.
368392Sswilcox *
369392Sswilcox * Note that the following code actually handles
370392Sswilcox * anything that's marked as an extended attribute but
371392Sswilcox * in a regular directory, not just files.
372392Sswilcox */
3730Sstevel@tonic-gate if ((dirtype == IFDIR) && isattr) {
3740Sstevel@tonic-gate fileerror(idesc->id_number, dirp->d_ino,
375392Sswilcox "%s I=%d should NOT be marked as extended attribute\n",
376392Sswilcox (inotype == IFDIR) ? "Directory" : "File",
377392Sswilcox dirp->d_ino);
3780Sstevel@tonic-gate dp = ginode(dirp->d_ino);
3790Sstevel@tonic-gate dp->di_cflags &= ~IXATTR;
3800Sstevel@tonic-gate if ((n = reply("FIX")) == 1) {
3810Sstevel@tonic-gate inodirty();
382392Sswilcox } else {
383392Sswilcox iscorrupt = 1;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate if (n != 0)
3860Sstevel@tonic-gate return (KEEPON | ALTERED);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate break;
3890Sstevel@tonic-gate default:
3900Sstevel@tonic-gate errexit("PASS3: BAD STATE %d FOR INODE I=%d",
3910Sstevel@tonic-gate statemap[dirp->d_ino], dirp->d_ino);
392392Sswilcox /* NOTREACHED */
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate if (n == 0)
3950Sstevel@tonic-gate return (ret|KEEPON);
3960Sstevel@tonic-gate return (ret|KEEPON|ALTERED);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate static void
setcurino(struct inodesc * idesc,struct dinode * dp,struct inoinfo * inp)400392Sswilcox setcurino(struct inodesc *idesc, struct dinode *dp, struct inoinfo *inp)
401392Sswilcox {
402392Sswilcox (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0],
403392Sswilcox inp->i_blkssize);
404392Sswilcox
405392Sswilcox init_inodesc(idesc);
406392Sswilcox idesc->id_number = inp->i_number;
407392Sswilcox idesc->id_parent = inp->i_parent;
408392Sswilcox idesc->id_fix = DONTKNOW;
409392Sswilcox idesc->id_type = DATA;
410392Sswilcox idesc->id_func = pass3acheck;
411392Sswilcox }
412392Sswilcox
413392Sswilcox void
maybe_convert_attrdir_to_dir(fsck_ino_t orphan)414392Sswilcox maybe_convert_attrdir_to_dir(fsck_ino_t orphan)
4150Sstevel@tonic-gate {
416392Sswilcox struct dinode *dp = ginode(orphan);
417392Sswilcox struct inoinfo *inp = getinoinfo(orphan);
418392Sswilcox struct inodesc idesc;
419392Sswilcox
420392Sswilcox if (dp->di_cflags & IXATTR) {
421392Sswilcox dp->di_cflags &= ~IXATTR;
422392Sswilcox inodirty();
423392Sswilcox }
424392Sswilcox
425392Sswilcox if ((dp->di_mode & IFMT) == IFATTRDIR) {
426392Sswilcox dp->di_mode &= ~IFATTRDIR;
427392Sswilcox dp->di_mode |= IFDIR;
428392Sswilcox inodirty();
429392Sswilcox
430392Sswilcox setcurino(&idesc, dp, inp);
431392Sswilcox idesc.id_fix = FIX;
432392Sswilcox idesc.id_filesize = dp->di_size;
433392Sswilcox (void) ckinode(dp, &idesc, CKI_TRAVERSE);
434392Sswilcox }
4350Sstevel@tonic-gate }
436