Commit 0d2dd382 authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'scrub-pptrs-6.10_2024-04-23' of...

Merge tag 'scrub-pptrs-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeC

xfs: scrubbing for parent pointers

Teach online fsck to use parent pointers to assist in checking
directories, parent pointers, extended attributes, and link counts.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'scrub-pptrs-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: check parent pointer xattrs when scrubbing
  xfs: walk directory parent pointers to determine backref count
  xfs: deferred scrub of parent pointers
  xfs: scrub parent pointers
  xfs: deferred scrub of dirents
  xfs: check dirents have parent pointers
  xfs: revert commit 44af6c7e
parents 47d83c19 59a2af90
......@@ -177,6 +177,7 @@ xfs-y += $(addprefix scrub/, \
scrub.o \
symlink.o \
xfarray.o \
xfblob.o \
xfile.o \
)
......@@ -218,7 +219,6 @@ xfs-y += $(addprefix scrub/, \
rmap_repair.o \
symlink_repair.o \
tempfile.o \
xfblob.o \
)
xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \
......
......@@ -291,3 +291,25 @@ xfs_parent_from_attr(
*parent_gen = be32_to_cpu(rec->p_gen);
return 0;
}
/*
* Look up a parent pointer record (@parent_name -> @pptr) of @ip.
*
* Caller must hold at least ILOCK_SHARED. The scratchpad need not be
* initialized.
*
* Returns 0 if the pointer is found, -ENOATTR if there is no match, or a
* negative errno.
*/
int
xfs_parent_lookup(
struct xfs_trans *tp,
struct xfs_inode *ip,
const struct xfs_name *parent_name,
struct xfs_parent_rec *pptr,
struct xfs_da_args *scratch)
{
memset(scratch, 0, sizeof(struct xfs_da_args));
xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name);
return xfs_attr_get_ilocked(scratch);
}
......@@ -96,4 +96,9 @@ int xfs_parent_from_attr(struct xfs_mount *mp, unsigned int attr_flags,
const void *value, unsigned int valuelen,
xfs_ino_t *parent_ino, uint32_t *parent_gen);
/* Repair functions */
int xfs_parent_lookup(struct xfs_trans *tp, struct xfs_inode *ip,
const struct xfs_name *name, struct xfs_parent_rec *pptr,
struct xfs_da_args *scratch);
#endif /* __XFS_PARENT_H__ */
......@@ -17,6 +17,7 @@
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
#include "xfs_attr_sf.h"
#include "xfs_parent.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/dabtree.h"
......@@ -208,13 +209,12 @@ xchk_xattr_actor(
return -ECANCELED;
}
/*
* Local and shortform xattr values are stored in the attr leaf block,
* so we don't need to retrieve the value from a remote block to detect
* corruption problems.
*/
if (value)
return 0;
/* Check parent pointer record. */
if ((attr_flags & XFS_ATTR_PARENT) &&
!xfs_parent_valuecheck(sc->mp, value, valuelen)) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
return -ECANCELED;
}
/*
* Try to allocate enough memory to extract the attr value. If that
......@@ -227,8 +227,21 @@ xchk_xattr_actor(
if (error)
return error;
/*
* Parent pointers are matched on attr name and value, so we must
* supply the xfs_parent_rec here when confirming that the dabtree
* indexing works correctly.
*/
if (attr_flags & XFS_ATTR_PARENT)
memcpy(ab->value, value, valuelen);
args.value = ab->value;
/*
* Get the attr value to ensure that lookup can find this attribute
* through the dabtree indexing and that remote value retrieval also
* works correctly.
*/
xfs_attr_sethash(&args);
error = xfs_attr_get_ilocked(&args);
/* ENODATA means the hash lookup failed and the attr is bad */
......
......@@ -212,6 +212,7 @@ static inline bool xchk_skip_xref(struct xfs_scrub_metadata *sm)
}
bool xchk_dir_looks_zapped(struct xfs_inode *dp);
bool xchk_pptr_looks_zapped(struct xfs_inode *ip);
#ifdef CONFIG_XFS_ONLINE_REPAIR
/* Decide if a repair is required. */
......
......@@ -16,12 +16,18 @@
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_health.h"
#include "xfs_attr.h"
#include "xfs_parent.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/dabtree.h"
#include "scrub/readdir.h"
#include "scrub/health.h"
#include "scrub/repair.h"
#include "scrub/trace.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
#include "scrub/xfblob.h"
/* Set us up to scrub directories. */
int
......@@ -41,6 +47,39 @@ xchk_setup_directory(
/* Directories */
/* Deferred directory entry that we saved for later. */
struct xchk_dirent {
/* Cookie for retrieval of the dirent name. */
xfblob_cookie name_cookie;
/* Child inode number. */
xfs_ino_t ino;
/* Length of the pptr name. */
uint8_t namelen;
};
struct xchk_dir {
struct xfs_scrub *sc;
/* information for parent pointer validation. */
struct xfs_parent_rec pptr_rec;
struct xfs_da_args pptr_args;
/* Fixed-size array of xchk_dirent structures. */
struct xfarray *dir_entries;
/* Blobs containing dirent names. */
struct xfblob *dir_names;
/* If we've cycled the ILOCK, we must revalidate deferred dirents. */
bool need_revalidate;
/* Name buffer for dirent revalidation. */
struct xfs_name xname;
uint8_t namebuf[MAXNAMELEN];
};
/* Scrub a directory entry. */
/* Check that an inode's mode matches a given XFS_DIR3_FT_* type. */
......@@ -63,6 +102,108 @@ xchk_dir_check_ftype(
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
}
/*
* Try to lock a child file for checking parent pointers. Returns the inode
* flags for the locks we now hold, or zero if we failed.
*/
STATIC unsigned int
xchk_dir_lock_child(
struct xfs_scrub *sc,
struct xfs_inode *ip)
{
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
return 0;
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
return 0;
}
if (!xfs_inode_has_attr_fork(ip) || !xfs_need_iread_extents(&ip->i_af))
return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
return 0;
}
return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
}
/* Check the backwards link (parent pointer) associated with this dirent. */
STATIC int
xchk_dir_parent_pointer(
struct xchk_dir *sd,
const struct xfs_name *name,
struct xfs_inode *ip)
{
struct xfs_scrub *sc = sd->sc;
int error;
xfs_inode_to_parent_rec(&sd->pptr_rec, sc->ip);
error = xfs_parent_lookup(sc->tp, ip, name, &sd->pptr_rec,
&sd->pptr_args);
if (error == -ENOATTR)
xchk_fblock_xref_set_corrupt(sc, XFS_DATA_FORK, 0);
return 0;
}
/* Look for a parent pointer matching this dirent, if the child isn't busy. */
STATIC int
xchk_dir_check_pptr_fast(
struct xchk_dir *sd,
xfs_dir2_dataptr_t dapos,
const struct xfs_name *name,
struct xfs_inode *ip)
{
struct xfs_scrub *sc = sd->sc;
unsigned int lockmode;
int error;
/* dot and dotdot entries do not have parent pointers */
if (xfs_dir2_samename(name, &xfs_name_dot) ||
xfs_dir2_samename(name, &xfs_name_dotdot))
return 0;
/* No self-referential non-dot or dotdot dirents. */
if (ip == sc->ip) {
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
return -ECANCELED;
}
/* Try to lock the inode. */
lockmode = xchk_dir_lock_child(sc, ip);
if (!lockmode) {
struct xchk_dirent save_de = {
.namelen = name->len,
.ino = ip->i_ino,
};
/* Couldn't lock the inode, so save the dirent for later. */
trace_xchk_dir_defer(sc->ip, name, ip->i_ino);
error = xfblob_storename(sd->dir_names, &save_de.name_cookie,
name);
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,
&error))
return error;
error = xfarray_append(sd->dir_entries, &save_de);
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,
&error))
return error;
return 0;
}
error = xchk_dir_parent_pointer(sd, name, ip);
xfs_iunlock(ip, lockmode);
return error;
}
/*
* Scrub a single directory entry.
*
......@@ -80,6 +221,7 @@ xchk_dir_actor(
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_inode *ip;
struct xchk_dir *sd = priv;
xfs_ino_t lookup_ino;
xfs_dablk_t offset;
int error = 0;
......@@ -146,6 +288,14 @@ xchk_dir_actor(
goto out;
xchk_dir_check_ftype(sc, offset, ip, name->type);
if (xfs_has_parent(mp)) {
error = xchk_dir_check_pptr_fast(sd, dapos, name, ip);
if (error)
goto out_rele;
}
out_rele:
xchk_irele(sc, ip);
out:
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
......@@ -762,11 +912,148 @@ xchk_directory_blocks(
return error;
}
/*
* Revalidate a dirent that we collected in the past but couldn't check because
* of lock contention. Returns 0 if the dirent is still valid, -ENOENT if it
* has gone away on us, or a negative errno.
*/
STATIC int
xchk_dir_revalidate_dirent(
struct xchk_dir *sd,
const struct xfs_name *xname,
xfs_ino_t ino)
{
struct xfs_scrub *sc = sd->sc;
xfs_ino_t child_ino;
int error;
/*
* Look up the directory entry. If we get -ENOENT, the directory entry
* went away and there's nothing to revalidate. Return any other
* error.
*/
error = xchk_dir_lookup(sc, sc->ip, xname, &child_ino);
if (error)
return error;
/* The inode number changed, nothing to revalidate. */
if (ino != child_ino)
return -ENOENT;
return 0;
}
/*
* Check a directory entry's parent pointers the slow way, which means we cycle
* locks a bunch and put up with revalidation until we get it done.
*/
STATIC int
xchk_dir_slow_dirent(
struct xchk_dir *sd,
struct xchk_dirent *dirent,
const struct xfs_name *xname)
{
struct xfs_scrub *sc = sd->sc;
struct xfs_inode *ip;
unsigned int lockmode;
int error;
/* Check that the deferred dirent still exists. */
if (sd->need_revalidate) {
error = xchk_dir_revalidate_dirent(sd, xname, dirent->ino);
if (error == -ENOENT)
return 0;
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,
&error))
return error;
}
error = xchk_iget(sc, dirent->ino, &ip);
if (error == -EINVAL || error == -ENOENT) {
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
return 0;
}
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
return error;
/*
* If we can grab both IOLOCK and ILOCK of the alleged child, we can
* proceed with the validation.
*/
lockmode = xchk_dir_lock_child(sc, ip);
if (lockmode) {
trace_xchk_dir_slowpath(sc->ip, xname, ip->i_ino);
goto check_pptr;
}
/*
* We couldn't lock the child file. Drop all the locks and try to
* get them again, one at a time.
*/
xchk_iunlock(sc, sc->ilock_flags);
sd->need_revalidate = true;
trace_xchk_dir_ultraslowpath(sc->ip, xname, ip->i_ino);
error = xchk_dir_trylock_for_pptrs(sc, ip, &lockmode);
if (error)
goto out_rele;
/* Revalidate, since we just cycled the locks. */
error = xchk_dir_revalidate_dirent(sd, xname, dirent->ino);
if (error == -ENOENT) {
error = 0;
goto out_unlock;
}
if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
goto out_unlock;
check_pptr:
error = xchk_dir_parent_pointer(sd, xname, ip);
out_unlock:
xfs_iunlock(ip, lockmode);
out_rele:
xchk_irele(sc, ip);
return error;
}
/* Check all the dirents that we deferred the first time around. */
STATIC int
xchk_dir_finish_slow_dirents(
struct xchk_dir *sd)
{
xfarray_idx_t array_cur;
int error;
foreach_xfarray_idx(sd->dir_entries, array_cur) {
struct xchk_dirent dirent;
if (sd->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return 0;
error = xfarray_load(sd->dir_entries, array_cur, &dirent);
if (error)
return error;
error = xfblob_loadname(sd->dir_names, dirent.name_cookie,
&sd->xname, dirent.namelen);
if (error)
return error;
error = xchk_dir_slow_dirent(sd, &dirent, &sd->xname);
if (error)
return error;
}
return 0;
}
/* Scrub a whole directory. */
int
xchk_directory(
struct xfs_scrub *sc)
{
struct xchk_dir *sd;
int error;
if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
......@@ -799,9 +1086,60 @@ xchk_directory(
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
return 0;
sd = kvzalloc(sizeof(struct xchk_dir), XCHK_GFP_FLAGS);
if (!sd)
return -ENOMEM;
sd->sc = sc;
sd->xname.name = sd->namebuf;
if (xfs_has_parent(sc->mp)) {
char *descr;
/*
* Set up some staging memory for dirents that we can't check
* due to locking contention.
*/
descr = xchk_xfile_ino_descr(sc, "slow directory entries");
error = xfarray_create(descr, 0, sizeof(struct xchk_dirent),
&sd->dir_entries);
kfree(descr);
if (error)
goto out_sd;
descr = xchk_xfile_ino_descr(sc, "slow directory entry names");
error = xfblob_create(descr, &sd->dir_names);
kfree(descr);
if (error)
goto out_entries;
}
/* Look up every name in this directory by hash. */
error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, NULL);
if (error && error != -ECANCELED)
error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, sd);
if (error == -ECANCELED)
error = 0;
if (error)
goto out_names;
if (xfs_has_parent(sc->mp)) {
error = xchk_dir_finish_slow_dirents(sd);
if (error == -ETIMEDOUT) {
/* Couldn't grab a lock, scrub was marked incomplete */
error = 0;
goto out_names;
}
if (error)
goto out_names;
}
out_names:
if (sd->dir_names)
xfblob_destroy(sd->dir_names);
out_entries:
if (sd->dir_entries)
xfarray_destroy(sd->dir_entries);
out_sd:
kvfree(sd);
if (error)
return error;
/* If the dir is clean, it is clearly not zapped. */
......
......@@ -18,6 +18,7 @@
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_ag.h"
#include "xfs_parent.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
......@@ -29,6 +30,7 @@
#include "scrub/trace.h"
#include "scrub/readdir.h"
#include "scrub/tempfile.h"
#include "scrub/listxattr.h"
/*
* Live Inode Link Count Checking
......@@ -272,12 +274,17 @@ xchk_nlinks_collect_dirent(
* number of parents of the root directory.
*
* Otherwise, increment the number of backrefs pointing back to ino.
*
* If the filesystem has parent pointers, we walk the pptrs to
* determine the backref count.
*/
if (dotdot) {
if (dp == sc->mp->m_rootip)
error = xchk_nlinks_update_incore(xnc, ino, 1, 0, 0);
else
else if (!xfs_has_parent(sc->mp))
error = xchk_nlinks_update_incore(xnc, ino, 0, 1, 0);
else
error = 0;
if (error)
goto out_unlock;
}
......@@ -314,6 +321,61 @@ xchk_nlinks_collect_dirent(
return error;
}
/* Bump the backref count for the inode referenced by this parent pointer. */
STATIC int
xchk_nlinks_collect_pptr(
struct xfs_scrub *sc,
struct xfs_inode *ip,
unsigned int attr_flags,
const unsigned char *name,
unsigned int namelen,
const void *value,
unsigned int valuelen,
void *priv)
{
struct xfs_name xname = {
.name = name,
.len = namelen,
};
struct xchk_nlink_ctrs *xnc = priv;
const struct xfs_parent_rec *pptr_rec = value;
xfs_ino_t parent_ino;
int error;
/* Update the shadow link counts if we haven't already failed. */
if (xchk_iscan_aborted(&xnc->collect_iscan)) {
error = -ECANCELED;
goto out_incomplete;
}
if (!(attr_flags & XFS_ATTR_PARENT))
return 0;
error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,
valuelen, &parent_ino, NULL);
if (error)
return error;
trace_xchk_nlinks_collect_pptr(sc->mp, ip, &xname, pptr_rec);
mutex_lock(&xnc->lock);
error = xchk_nlinks_update_incore(xnc, parent_ino, 0, 1, 0);
if (error)
goto out_unlock;
mutex_unlock(&xnc->lock);
return 0;
out_unlock:
mutex_unlock(&xnc->lock);
xchk_iscan_abort(&xnc->collect_iscan);
out_incomplete:
xchk_set_incomplete(sc);
return error;
}
/* Walk a directory to bump the observed link counts of the children. */
STATIC int
xchk_nlinks_collect_dir(
......@@ -360,6 +422,27 @@ xchk_nlinks_collect_dir(
if (error)
goto out_abort;
/* Walk the parent pointers to get real backref counts. */
if (xfs_has_parent(sc->mp)) {
/*
* If the extended attributes look as though they has been
* zapped by the inode record repair code, we cannot scan for
* parent pointers.
*/
if (xchk_pptr_looks_zapped(dp)) {
error = -EBUSY;
goto out_unlock;
}
error = xchk_xattr_walk(sc, dp, xchk_nlinks_collect_pptr, xnc);
if (error == -ECANCELED) {
error = 0;
goto out_unlock;
}
if (error)
goto out_abort;
}
xchk_iscan_mark_visited(&xnc->collect_iscan, dp);
goto out_unlock;
......
......@@ -18,6 +18,8 @@
#include "xfs_ialloc.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_parent.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
......
This diff is collapsed.
......@@ -18,6 +18,7 @@
#include "xfs_trans.h"
#include "xfs_error.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/readdir.h"
/* Call a function for every entry in a shortform directory. */
......@@ -380,3 +381,80 @@ xchk_dir_lookup(
*ino = args.inumber;
return error;
}
/*
* Try to grab the IOLOCK and ILOCK of sc->ip and ip, returning @ip's lock
* state. The caller may have a transaction, so we must use trylock for both
* IOLOCKs.
*/
static inline unsigned int
xchk_dir_trylock_both(
struct xfs_scrub *sc,
struct xfs_inode *ip)
{
if (!xchk_ilock_nowait(sc, XFS_IOLOCK_EXCL))
return 0;
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
goto parent_iolock;
xchk_ilock(sc, XFS_ILOCK_EXCL);
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
goto parent_ilock;
return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
parent_ilock:
xchk_iunlock(sc, XFS_ILOCK_EXCL);
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
parent_iolock:
xchk_iunlock(sc, XFS_IOLOCK_EXCL);
return 0;
}
/*
* Try for a limited time to grab the IOLOCK and ILOCK of both the scrub target
* (@sc->ip) and the inode at the other end (@ip) of a directory or parent
* pointer link so that we can check that link.
*
* We do not know ahead of time that the directory tree is /not/ corrupt, so we
* cannot use the "lock two inode" functions because we do not know that there
* is not a racing thread trying to take the locks in opposite order. First
* take IOLOCK_EXCL of the scrub target, and then try to take IOLOCK_SHARED
* of @ip to synchronize with the VFS. Next, take ILOCK_EXCL of the scrub
* target and @ip to synchronize with XFS.
*
* If the trylocks succeed, *lockmode will be set to the locks held for @ip;
* @sc->ilock_flags will be set for the locks held for @sc->ip; and zero will
* be returned. If not, returns -EDEADLOCK to try again; or -ETIMEDOUT if
* XCHK_TRY_HARDER was set. Returns -EINTR if the process has been killed.
*/
int
xchk_dir_trylock_for_pptrs(
struct xfs_scrub *sc,
struct xfs_inode *ip,
unsigned int *lockmode)
{
unsigned int nr;
int error = 0;
ASSERT(sc->ilock_flags == 0);
for (nr = 0; nr < HZ; nr++) {
*lockmode = xchk_dir_trylock_both(sc, ip);
if (*lockmode)
return 0;
if (xchk_should_terminate(sc, &error))
return error;
delay(1);
}
if (sc->flags & XCHK_TRY_HARDER) {
xchk_set_incomplete(sc);
return -ETIMEDOUT;
}
return -EDEADLOCK;
}
......@@ -16,4 +16,7 @@ int xchk_dir_walk(struct xfs_scrub *sc, struct xfs_inode *dp,
int xchk_dir_lookup(struct xfs_scrub *sc, struct xfs_inode *dp,
const struct xfs_name *name, xfs_ino_t *ino);
int xchk_dir_trylock_for_pptrs(struct xfs_scrub *sc, struct xfs_inode *ip,
unsigned int *lockmode);
#endif /* __XFS_SCRUB_READDIR_H__ */
......@@ -19,6 +19,7 @@
#include "xfs_da_format.h"
#include "xfs_dir2.h"
#include "xfs_rmap.h"
#include "xfs_parent.h"
#include "scrub/scrub.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
......
......@@ -26,6 +26,7 @@ struct xchk_iscan;
struct xchk_nlink;
struct xchk_fscounters;
struct xfs_rmap_update_params;
struct xfs_parent_rec;
/*
* ftrace's __print_symbolic requires that all enum values be wrapped in the
......@@ -1363,6 +1364,33 @@ TRACE_EVENT(xchk_nlinks_collect_dirent,
__get_str(name))
);
TRACE_EVENT(xchk_nlinks_collect_pptr,
TP_PROTO(struct xfs_mount *mp, struct xfs_inode *dp,
const struct xfs_name *name,
const struct xfs_parent_rec *pptr),
TP_ARGS(mp, dp, name, pptr),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, dir)
__field(xfs_ino_t, ino)
__field(unsigned int, namelen)
__dynamic_array(char, name, name->len)
),
TP_fast_assign(
__entry->dev = mp->m_super->s_dev;
__entry->dir = dp->i_ino;
__entry->ino = be64_to_cpu(pptr->p_ino);
__entry->namelen = name->len;
memcpy(__get_str(name), name->name, name->len);
),
TP_printk("dev %d:%d dir 0x%llx -> ino 0x%llx name '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->dir,
__entry->ino,
__entry->namelen,
__get_str(name))
);
TRACE_EVENT(xchk_nlinks_collect_metafile,
TP_PROTO(struct xfs_mount *mp, xfs_ino_t ino),
TP_ARGS(mp, ino),
......@@ -1511,6 +1539,43 @@ DEFINE_EVENT(xchk_nlinks_diff_class, name, \
TP_ARGS(mp, ip, live))
DEFINE_SCRUB_NLINKS_DIFF_EVENT(xchk_nlinks_compare_inode);
DECLARE_EVENT_CLASS(xchk_pptr_class,
TP_PROTO(struct xfs_inode *ip, const struct xfs_name *name,
xfs_ino_t far_ino),
TP_ARGS(ip, name, far_ino),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(unsigned int, namelen)
__dynamic_array(char, name, name->len)
__field(xfs_ino_t, far_ino)
),
TP_fast_assign(
__entry->dev = ip->i_mount->m_super->s_dev;
__entry->ino = ip->i_ino;
__entry->namelen = name->len;
memcpy(__get_str(name), name, name->len);
__entry->far_ino = far_ino;
),
TP_printk("dev %d:%d ino 0x%llx name '%.*s' far_ino 0x%llx",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->namelen,
__get_str(name),
__entry->far_ino)
)
#define DEFINE_XCHK_PPTR_EVENT(name) \
DEFINE_EVENT(xchk_pptr_class, name, \
TP_PROTO(struct xfs_inode *ip, const struct xfs_name *name, \
xfs_ino_t far_ino), \
TP_ARGS(ip, name, far_ino))
DEFINE_XCHK_PPTR_EVENT(xchk_dir_defer);
DEFINE_XCHK_PPTR_EVENT(xchk_dir_slowpath);
DEFINE_XCHK_PPTR_EVENT(xchk_dir_ultraslowpath);
DEFINE_XCHK_PPTR_EVENT(xchk_parent_defer);
DEFINE_XCHK_PPTR_EVENT(xchk_parent_slowpath);
DEFINE_XCHK_PPTR_EVENT(xchk_parent_ultraslowpath);
/* repair tracepoints */
#if IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment