mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 15:40:03 +02:00
xfs: report nonexistent parents as a filesystem corruption
LOLLM noticed that when the directory tree scrubber tries to walk up a
parent pointer but the parent inumber doesn't point to an allocated
inode, we allow the EINVAL/ENOENT error code to bubble up to userspace.
That's not right, we should be reporting that as a cross-referencing
error so that someone runs the parent pointer checker.
Also add a termination check to xchk_dirpath_step_up because it's a loop
body function.
Cc: stable@vger.kernel.org # v6.10
Fixes: 928b721a11 ("xfs: teach online scrub to find directory tree structure problems")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
295f2cfd3e
commit
014c1aff60
|
|
@ -368,12 +368,38 @@ xchk_dirpath_step_up(
|
|||
struct xfs_inode *dp;
|
||||
xfs_ino_t parent_ino = be64_to_cpu(dl->pptr_rec.p_ino);
|
||||
unsigned int lock_mode;
|
||||
int error;
|
||||
int error = 0;
|
||||
|
||||
if (xchk_should_terminate(sc, &error))
|
||||
return error;
|
||||
|
||||
/* Grab and lock the parent directory. */
|
||||
error = xchk_iget(sc, parent_ino, &dp);
|
||||
if (error)
|
||||
switch (error) {
|
||||
case -EINVAL:
|
||||
case -ENOENT:
|
||||
mutex_lock(&dl->lock);
|
||||
|
||||
if (dl->stale) {
|
||||
/* live update detected a change in this path */
|
||||
error = -ESTALE;
|
||||
} else {
|
||||
/* inode doesn't exist, path invalid */
|
||||
error = -EFSCORRUPTED;
|
||||
|
||||
trace_xchk_dirpath_badino(dl->sc, path->path_nr,
|
||||
path->nr_steps, &dl->xname,
|
||||
&dl->pptr_rec);
|
||||
}
|
||||
|
||||
mutex_unlock(&dl->lock);
|
||||
return error;
|
||||
case 0:
|
||||
/* keep going */
|
||||
break;
|
||||
default:
|
||||
return error;
|
||||
}
|
||||
|
||||
lock_mode = xfs_ilock_attr_map_shared(dp);
|
||||
mutex_lock(&dl->lock);
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,39 @@ DEFINE_EVENT(xchk_dirtree_class, name, \
|
|||
DEFINE_XCHK_DIRTREE_EVENT(xchk_dirtree_create_path);
|
||||
DEFINE_XCHK_DIRTREE_EVENT(xchk_dirpath_walk_upwards);
|
||||
|
||||
TRACE_EVENT(xchk_dirpath_badino,
|
||||
TP_PROTO(struct xfs_scrub *sc, unsigned int path_nr,
|
||||
unsigned int step_nr, const struct xfs_name *name,
|
||||
const struct xfs_parent_rec *pptr),
|
||||
TP_ARGS(sc, path_nr, step_nr, name, pptr),
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(unsigned int, path_nr)
|
||||
__field(unsigned int, step_nr)
|
||||
__field(xfs_ino_t, parent_ino)
|
||||
__field(unsigned int, parent_gen)
|
||||
__field(unsigned int, namelen)
|
||||
__dynamic_array(char, name, name->len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->dev = sc->mp->m_super->s_dev;
|
||||
__entry->path_nr = path_nr;
|
||||
__entry->step_nr = step_nr;
|
||||
__entry->parent_ino = be64_to_cpu(pptr->p_ino);
|
||||
__entry->parent_gen = be32_to_cpu(pptr->p_gen);
|
||||
__entry->namelen = name->len;
|
||||
memcpy(__get_str(name), name->name, name->len);
|
||||
),
|
||||
TP_printk("dev %d:%d path %u step %u parent_ino 0x%llx parent_gen 0x%x name '%.*s'",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->path_nr,
|
||||
__entry->step_nr,
|
||||
__entry->parent_ino,
|
||||
__entry->parent_gen,
|
||||
__entry->namelen,
|
||||
__get_str(name))
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(xchk_dirpath_class,
|
||||
TP_PROTO(struct xfs_scrub *sc, struct xfs_inode *ip,
|
||||
unsigned int path_nr, unsigned int step_nr,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user