/* Since this is the surviving path, set the dotdot entry to this value. */ STATICvoid
xrep_dirpath_retain_parent( struct xchk_dirtree *dl, struct xchk_dirpath *path)
{ struct xchk_dirpath_step step; int error;
error = xfarray_load(dl->path_steps, path->first_step, &step); if (error) return;
/* Find the one surviving path so we know how to set dotdot. */ STATICvoid
xrep_dirtree_find_surviving_path( struct xchk_dirtree *dl, struct xchk_dirtree_outcomes *oc)
{ struct xchk_dirpath *path; bool foundit = false;
xchk_dirtree_for_each_path(dl, path) { switch (path->outcome) { case XCHK_DIRPATH_CORRUPT: case XCHK_DIRPATH_LOOP: case XCHK_DIRPATH_OK: if (!foundit) {
xrep_dirpath_retain_parent(dl, path);
foundit = true; continue;
}
ASSERT(foundit == false); break; default: break;
}
}
ASSERT(oc->suspect + oc->good == 1);
}
/* Delete all paths except for the one good one. */ STATICvoid
xrep_dirtree_keep_one_good_path( struct xchk_dirtree *dl, struct xchk_dirtree_outcomes *oc)
{ struct xchk_dirpath *path; bool foundit = false;
xchk_dirtree_for_each_path(dl, path) { switch (path->outcome) { case XCHK_DIRPATH_CORRUPT: case XCHK_DIRPATH_LOOP:
oc->suspect--;
oc->bad++;
xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE); break; case XCHK_DIRPATH_OK: if (!foundit) {
xrep_dirpath_retain_parent(dl, path);
foundit = true; continue;
}
oc->good--;
oc->bad++;
xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE); break; default: break;
}
}
ASSERT(oc->suspect == 0);
ASSERT(oc->good < 2);
}
/* Delete all paths except for one suspect one. */ STATICvoid
xrep_dirtree_keep_one_suspect_path( struct xchk_dirtree *dl, struct xchk_dirtree_outcomes *oc)
{ struct xchk_dirpath *path; bool foundit = false;
xchk_dirtree_for_each_path(dl, path) { switch (path->outcome) { case XCHK_DIRPATH_CORRUPT: case XCHK_DIRPATH_LOOP: if (!foundit) {
xrep_dirpath_retain_parent(dl, path);
foundit = true; continue;
}
oc->suspect--;
oc->bad++;
xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE); break; case XCHK_DIRPATH_OK:
ASSERT(0); break; default: break;
}
}
/* Parentless directories should not have any paths at all. */ if (xchk_dirtree_parentless(dl)) {
xrep_dirtree_delete_all_paths(dl, oc); return;
}
/* One path is exactly the number of paths we want. */ if (oc->good + oc->suspect == 1) {
xrep_dirtree_find_surviving_path(dl, oc); return;
}
/* Zero paths means we should reattach the subdir to the orphanage. */ if (oc->good + oc->suspect == 0) { if (dl->sc->orphanage)
oc->needs_adoption = true; return;
}
/* Delete the VFS dentry for a removed child. */ STATICint
xrep_dirtree_purge_dentry( struct xchk_dirtree *dl, struct xfs_inode *dp, conststruct xfs_name *name)
{ struct qstr qname = QSTR_INIT(name->name, name->len); struct dentry *parent_dentry, *child_dentry; int error = 0;
/* *Findthedentryfortheparentdirectory.Ifthereisn'tone,we're *done.Calleralreadyholdsi_rwsemforparentandchild.
*/
parent_dentry = d_find_alias(VFS_I(dp)); if (!parent_dentry) return0;
/* The VFS thinks the parent is a directory, right? */ if (!d_is_dir(parent_dentry)) {
ASSERT(d_is_dir(parent_dentry));
error = -EFSCORRUPTED; goto out_dput_parent;
}
/* Child is not a directory? We're screwed. */ if (!d_is_dir(child_dentry)) {
ASSERT(d_is_dir(child_dentry));
error = -EFSCORRUPTED; goto out_dput_child;
}
/* Replace the child dentry with a negative one. */
d_delete(child_dentry);
/* Delete all the paths we don't want. */
xchk_dirtree_for_each_path(dl, path) { if (path->outcome != XCHK_DIRPATH_DELETE) continue;
error = xrep_dirtree_delete_path(dl, path); if (error) return error;
}
/* Reparent this directory to the orphanage. */ if (oc->needs_adoption) { if (xrep_orphanage_can_adopt(dl->sc)) return xrep_dirtree_move_to_orphanage(dl); return -EFSCORRUPTED;
}
return0;
}
/* Fix directory loops involving this directory. */ int
xrep_dirtree( struct xfs_scrub *sc)
{ struct xchk_dirtree *dl = sc->buf; struct xchk_dirtree_outcomes oc; int error;
/* *Preparetofixthedirectorytreebyretakingthescanlock.The *orderofresourceacquisitionisstillIOLOCK->transaction-> *ILOCK->scanlock.
*/
mutex_lock(&dl->lock); do { /* *Decidewhatwe'regoingtodo,thendoit.An-ESTALE *returnheremeansthescanresultsareinvalidandwehave *towalkagain.
*/ if (!dl->stale) {
xrep_dirtree_decide_fate(dl, &oc);
trace_xrep_dirtree_decided_fate(dl, &oc);
error = xrep_dirtree_fix_problems(dl, &oc); if (!error || error != -ESTALE) break;
}
error = xchk_dirtree_find_paths_to_root(dl); if (error == -ELNRNG || error == -ENOSR)
error = -EFSCORRUPTED;
} while (!error);
mutex_unlock(&dl->lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.