pass3.c revision b9a41fd39fb451c441a90e8959cb2dc2db84b497
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Use is subject to license terms.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* All Rights Reserved */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Redistribution and use in source and binary forms are permitted
03831d35f7499c87d51205817c93e9a8d42c4baestevel * provided that: (1) source distributions retain this entire copyright
03831d35f7499c87d51205817c93e9a8d42c4baestevel * notice and comment, and (2) distributions including binaries display
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the following acknowledgement: ``This product includes software
03831d35f7499c87d51205817c93e9a8d42c4baestevel * developed by the University of California, Berkeley and its contributors''
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in the documentation or other materials provided with the distribution
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and in all advertising materials mentioning features or use of this
03831d35f7499c87d51205817c93e9a8d42c4baestevel * software. Neither the name of the University nor the names of its
03831d35f7499c87d51205817c93e9a8d42c4baestevel * contributors may be used to endorse or promote products derived
03831d35f7499c87d51205817c93e9a8d42c4baestevel * from this software without specific prior written permission.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
03831d35f7499c87d51205817c93e9a8d42c4baestevel * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
03831d35f7499c87d51205817c93e9a8d42c4baestevel * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#pragma ident "%Z%%M% %I% %E% SMI"
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <stdio.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <stdlib.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <unistd.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <string.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/param.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/types.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/mntent.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/fs/ufs_fs.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/vnode.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/fs/ufs_inode.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define _KERNEL
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/fs/ufs_fsdir.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#undef _KERNEL
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include "fsck.h"
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pass3acheck(struct inodesc *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void setcurino(struct inodesc *, struct dinode *, struct inoinfo *);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelvoid
03831d35f7499c87d51205817c93e9a8d42c4baestevelpass3a(void)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel caddr_t flow;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct inoinfo **inpp, *inp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel fsck_ino_t orphan;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int loopcnt;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int state;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct shadowclientinfo *sci, *sci_victim, *sci_prev, **sci_rootp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct inodesc curino;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct dinode *dp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct inodesc idesc;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char namebuf[MAXNAMLEN + 1];
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp = *inpp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel state = statemap[inp->i_number];
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (inp->i_number == UFSROOTINO ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel (inp->i_parent != 0 && !S_IS_DUNFOUND(state)))
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (state == DCLEAR || state == USTATE || (state & INORPHAN))
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If we are running with logging and we come
03831d35f7499c87d51205817c93e9a8d42c4baestevel * across unreferenced directories, we just leave
03831d35f7499c87d51205817c93e9a8d42c4baestevel * them in DSTATE which will cause them to be pitched
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in pass 4.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (preen && !iscorrupt && islog && S_IS_DUNFOUND(state)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (inp->i_dotdot >= UFSROOTINO) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel LINK_RANGE(flow, lncntp[inp->i_dotdot], 1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (flow != NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp = ginode(inp->i_dotdot);
03831d35f7499c87d51205817c93e9a8d42c4baestevel LINK_CLEAR(flow, inp->i_dotdot,
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp->di_mode, &idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (statemap[inp->i_dotdot] == USTATE)
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel TRACK_LNCNTP(inp->i_dotdot,
03831d35f7499c87d51205817c93e9a8d42c4baestevel lncntp[inp->i_dotdot]++);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (loopcnt = 0; ; loopcnt++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel orphan = inp->i_number;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Skip out if we aren't connected to the name
03831d35f7499c87d51205817c93e9a8d42c4baestevel * space, or our parent is connected, or we've
03831d35f7499c87d51205817c93e9a8d42c4baestevel * looked at too many directories. Our parent
03831d35f7499c87d51205817c93e9a8d42c4baestevel * being connected means that orphan is the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * first ancestor of *inpp with questionable
03831d35f7499c87d51205817c93e9a8d42c4baestevel * antecedents.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (inp->i_parent == 0 ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel !INO_IS_DUNFOUND(inp->i_parent) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel loopcnt > numdirs)
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp = getinoinfo(inp->i_parent);
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Can't happen, because a non-zero parent's already
03831d35f7499c87d51205817c93e9a8d42c4baestevel * been seen and therefore cached.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (inp == NULL)
03831d35f7499c87d51205817c93e9a8d42c4baestevel errexit("pass3 could not find cached "
03831d35f7499c87d51205817c93e9a8d42c4baestevel "inode I=%d\n",
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_parent);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Already did this one. Don't bother the user
03831d35f7499c87d51205817c93e9a8d42c4baestevel * with redundant questions.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (statemap[orphan] & INORPHAN)
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * A link count of 0 with parent and .. inodes of 0
03831d35f7499c87d51205817c93e9a8d42c4baestevel * indicates a partly deleted directory.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Clear it.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp = ginode(orphan);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (dp->di_nlink == 0 && inp->i_dotdot == 0 &&
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_parent == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * clri() just uses curino.id_number; in other
03831d35f7499c87d51205817c93e9a8d42c4baestevel * words, it won't use the callback that setcurino()
03831d35f7499c87d51205817c93e9a8d42c4baestevel * puts in.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel setcurino(&curino, dp, inp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel clri(&curino, "UNREF", CLRI_VERBOSE, CLRI_NOP_OK);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If we didn't clear it, at least mark it so
03831d35f7499c87d51205817c93e9a8d42c4baestevel * we don't waste time on it again.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (statemap[orphan] != USTATE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[orphan] |= INORPHAN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We can call linkup() multiple times on the same directory
03831d35f7499c87d51205817c93e9a8d42c4baestevel * inode, if we were told not to reconnect it the first time.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This is because we find it as a disconnected parent of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * of its children (and mark it found), and then finally get
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to it in the inpsort array. This is better than in the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * past, where we'd call it every time we found it as a
03831d35f7499c87d51205817c93e9a8d42c4baestevel * child's parent. Ideally, we'd suppress even the second
03831d35f7499c87d51205817c93e9a8d42c4baestevel * query, but that confuses pass 4's interpretation of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the state flags.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (loopcnt <= countdirs) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (linkup(orphan, inp->i_dotdot, NULL)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Bookkeeping for any sort of relinked
03831d35f7499c87d51205817c93e9a8d42c4baestevel * directory.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_dotdot = lfdir;
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_parent = inp->i_dotdot;
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[orphan] &= ~(INORPHAN);
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[orphan] |= INORPHAN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel propagate();
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We visited more directories than exist in the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * filesystem. The only way to do that is if there's
03831d35f7499c87d51205817c93e9a8d42c4baestevel * a loop.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel pfatal("ORPHANED DIRECTORY LOOP DETECTED I=%d\n", orphan);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Can never get here with inp->i_parent zero, because
03831d35f7499c87d51205817c93e9a8d42c4baestevel * of the interactions between the for() and the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * if (loopcnt <= countdirs) above.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel init_inodesc(&idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_type = DATA;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_number = inp->i_parent;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_parent = orphan;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_func = findname;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_name = namebuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel namebuf[0] = '\0';
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Theoretically, this lookup via ckinode can't fail
03831d35f7499c87d51205817c93e9a8d42c4baestevel * (if orphan doesn't exist in i_parent, then i_parent
03831d35f7499c87d51205817c93e9a8d42c4baestevel * would not have been filled in by pass2check()).
03831d35f7499c87d51205817c93e9a8d42c4baestevel * However, if we're interactive, we want to at least
03831d35f7499c87d51205817c93e9a8d42c4baestevel * attempt to continue. The worst case is that it
03831d35f7499c87d51205817c93e9a8d42c4baestevel * gets reconnected as #nnn into lost+found instead of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to its old parent with its old name.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((ckinode(ginode(inp->i_parent),
03831d35f7499c87d51205817c93e9a8d42c4baestevel &idesc, CKI_TRAVERSE) & FOUND) == 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY");
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (linkup(orphan, inp->i_parent, namebuf)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (cleardirentry(inp->i_parent, orphan) & FOUND) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], 1,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel TRACK_LNCNTP(orphan, lncntp[orphan]++);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_parent = inp->i_dotdot = lfdir;
03831d35f7499c87d51205817c93e9a8d42c4baestevel LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], -1,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel TRACK_LNCNTP(lfdir, lncntp[lfdir]--);
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[orphan] = DFOUND;
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Represents a on-disk leak, not an inconsistency,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * so don't set iscorrupt. Such leaks are harmless
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in the context of discrepancies that the kernel
03831d35f7499c87d51205817c93e9a8d42c4baestevel * will panic over.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We don't care if tsearch() returns non-NULL
03831d35f7499c87d51205817c93e9a8d42c4baestevel * != orphan, since there's no dynamic memory
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to free here.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (tsearch((void *)orphan, &limbo_dirs,
03831d35f7499c87d51205817c93e9a8d42c4baestevel ino_t_cmp) == NULL)
03831d35f7499c87d51205817c93e9a8d42c4baestevel errexit("out of memory");
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[orphan] |= INORPHAN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel propagate();
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The essence of the inner loop is to update the inode of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * every shadow or attribute inode's lncntp[] by the number of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * links we've found to them in pass 2 and above. Logically,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * all that is needed is just the one line:
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * lncntp[sci->shadow] -= sci->totalclients;
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * However, there's the possibility of wrapping the link count
03831d35f7499c87d51205817c93e9a8d42c4baestevel * (this is especially true for shadows, which are expected to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * be shared amongst many files). This means that we have to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * range-check before changing anything, and if the check
03831d35f7499c87d51205817c93e9a8d42c4baestevel * fails, offer to clear the shadow or attribute. If we do
03831d35f7499c87d51205817c93e9a8d42c4baestevel * clear it, then we have to remove it from the linked list of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * all of the type of inodes that we're going through.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Just to make things a little more complicated, these are
03831d35f7499c87d51205817c93e9a8d42c4baestevel * singly-linked lists, so we have to do all the extra
03831d35f7499c87d51205817c93e9a8d42c4baestevel * bookkeeping that goes along with that as well.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The only connection between the shadowclientinfo and
03831d35f7499c87d51205817c93e9a8d42c4baestevel * attrclientinfo lists is that they use the same underlying
03831d35f7499c87d51205817c93e9a8d42c4baestevel * struct. Both need this scan, so the outer loop is just to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * pick which one we're working on at the moment. There is no
03831d35f7499c87d51205817c93e9a8d42c4baestevel * requirement as to which of these lists is scanned first.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (loopcnt = 0; loopcnt < 2; loopcnt++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (loopcnt == 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_rootp = &shadowclientinfo;
03831d35f7499c87d51205817c93e9a8d42c4baestevel else
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_rootp = &attrclientinfo;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci = *sci_rootp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_prev = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel while (sci != NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_victim = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel LINK_RANGE(flow, lncntp[sci->shadow],
03831d35f7499c87d51205817c93e9a8d42c4baestevel -(sci->totalClients));
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (flow != NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Overflowed the link count.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp = ginode(sci->shadow);
03831d35f7499c87d51205817c93e9a8d42c4baestevel LINK_CLEAR(flow, sci->shadow, dp->di_mode,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (statemap[sci->shadow] == USTATE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * It's been cleared, fix the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * lists.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sci_prev == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel *sci_rootp = sci->next;
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_prev->next = sci->next;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_victim = sci;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If we did not clear the shadow, then we
03831d35f7499c87d51205817c93e9a8d42c4baestevel * need to update the count and advance the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * previous pointer. Otherwise, finish the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * clean up once we're done with the struct.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sci_victim == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel TRACK_LNCNTP(sci->shadow,
03831d35f7499c87d51205817c93e9a8d42c4baestevel lncntp[sci->shadow] -= sci->totalClients);
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci_prev = sci;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel sci = sci->next;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sci_victim != NULL)
03831d35f7499c87d51205817c93e9a8d42c4baestevel deshadow(sci_victim, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This is used to verify the cflags of files
03831d35f7499c87d51205817c93e9a8d42c4baestevel * under a directory that used to be an attrdir.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpass3acheck(struct inodesc *idesc)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct direct *dirp = idesc->id_dirp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int n = 0, ret = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct dinode *dp, *pdirp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int isattr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int dirtype;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int inotype;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (dirp->d_ino == 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (KEEPON);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_entryno++;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((strcmp(dirp->d_name, ".") == 0) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel (strcmp(dirp->d_name, "..") == 0)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (KEEPON);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel switch (statemap[dirp->d_ino] & ~(INDELAYD)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DSTATE:
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DFOUND:
03831d35f7499c87d51205817c93e9a8d42c4baestevel case FSTATE:
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Accept DSTATE and DFOUND so we can handle normal
03831d35f7499c87d51205817c93e9a8d42c4baestevel * directories as well as xattr directories.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * For extended attribute directories .. may point
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to a file. In this situation we don't want
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to decrement link count as it was already
03831d35f7499c87d51205817c93e9a8d42c4baestevel * decremented when the entry was seen and decremented
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in the directory it actually lives in.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp = ginode(dirp->d_ino);
03831d35f7499c87d51205817c93e9a8d42c4baestevel isattr = (dp->di_cflags & IXATTR);
03831d35f7499c87d51205817c93e9a8d42c4baestevel inotype = (dp->di_mode & IFMT);
03831d35f7499c87d51205817c93e9a8d42c4baestevel pdirp = ginode(idesc->id_number);
03831d35f7499c87d51205817c93e9a8d42c4baestevel dirtype = (pdirp->di_mode & IFMT);
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * IXATTR indicates that an object is itself an extended
03831d35f7499c87d51205817c93e9a8d42c4baestevel * attribute. An IFMT of IFATTRDIR means we are looking
03831d35f7499c87d51205817c93e9a8d42c4baestevel * at a directory which contains files which should all
03831d35f7499c87d51205817c93e9a8d42c4baestevel * have IXATTR set. The IFATTRDIR case was handled in
03831d35f7499c87d51205817c93e9a8d42c4baestevel * pass 2b.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Note that the following code actually handles
03831d35f7499c87d51205817c93e9a8d42c4baestevel * anything that's marked as an extended attribute but
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in a regular directory, not just files.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((dirtype == IFDIR) && isattr) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel fileerror(idesc->id_number, dirp->d_ino,
03831d35f7499c87d51205817c93e9a8d42c4baestevel "%s I=%d should NOT be marked as extended attribute\n",
03831d35f7499c87d51205817c93e9a8d42c4baestevel (inotype == IFDIR) ? "Directory" : "File",
03831d35f7499c87d51205817c93e9a8d42c4baestevel dirp->d_ino);
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp = ginode(dirp->d_ino);
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp->di_cflags &= ~IXATTR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((n = reply("FIX")) == 1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel inodirty();
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel iscorrupt = 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (n != 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (KEEPON | ALTERED);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel default:
03831d35f7499c87d51205817c93e9a8d42c4baestevel errexit("PASS3: BAD STATE %d FOR INODE I=%d",
03831d35f7499c87d51205817c93e9a8d42c4baestevel statemap[dirp->d_ino], dirp->d_ino);
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* NOTREACHED */
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (n == 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ret|KEEPON);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ret|KEEPON|ALTERED);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void
03831d35f7499c87d51205817c93e9a8d42c4baestevelsetcurino(struct inodesc *idesc, struct dinode *dp, struct inoinfo *inp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0],
03831d35f7499c87d51205817c93e9a8d42c4baestevel inp->i_blkssize);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel init_inodesc(idesc);
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_number = inp->i_number;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_parent = inp->i_parent;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_fix = DONTKNOW;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_type = DATA;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc->id_func = pass3acheck;
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelvoid
03831d35f7499c87d51205817c93e9a8d42c4baestevelmaybe_convert_attrdir_to_dir(fsck_ino_t orphan)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct dinode *dp = ginode(orphan);
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct inoinfo *inp = getinoinfo(orphan);
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct inodesc idesc;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (dp->di_cflags & IXATTR) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp->di_cflags &= ~IXATTR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel inodirty();
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((dp->di_mode & IFMT) == IFATTRDIR) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp->di_mode &= ~IFATTRDIR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel dp->di_mode |= IFDIR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel inodirty();
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel setcurino(&idesc, dp, inp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_fix = FIX;
03831d35f7499c87d51205817c93e9a8d42c4baestevel idesc.id_filesize = dp->di_size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) ckinode(dp, &idesc, CKI_TRAVERSE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel