All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <djwong@kernel.org>
To: djwong@kernel.org
Cc: allison.henderson@oracle.com, catherine.hoang@oracle.com,
	linux-xfs@vger.kernel.org, hch@lst.de
Subject: [PATCH 01/23] xfs: check dirents have parent pointers
Date: Mon, 18 Mar 2024 14:48:15 -0700	[thread overview]
Message-ID: <171079802711.3808642.9840816764752307950.stgit@frogsfrogsfrogs> (raw)
In-Reply-To: <171079802637.3808642.13167687091088855153.stgit@frogsfrogsfrogs>

From: Darrick J. Wong <djwong@kernel.org>

If the fs has parent pointers, we need to check that each child dirent
points to a file that has a parent pointer pointing back at us.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_parent.c |   54 +++++++++++++++++++
 fs/xfs/libxfs/xfs_parent.h |   10 ++++
 fs/xfs/scrub/dir.c         |  122 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index 48a2dfcc465fa..09495eb368e2b 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -366,3 +366,57 @@ xfs_parent_irec_hashname(
 
 	irec->p_namehash = xfs_dir2_hashname(mp, &dname);
 }
+
+static inline void
+xfs_parent_scratch_init(
+	struct xfs_trans		*tp,
+	struct xfs_inode		*ip,
+	const struct xfs_parent_name_irec *pptr,
+	struct xfs_parent_scratch	*scr)
+{
+	memset(&scr->args, 0, sizeof(struct xfs_da_args));
+	scr->args.attr_filter	= XFS_ATTR_PARENT;
+	scr->args.dp		= ip;
+	scr->args.geo		= ip->i_mount->m_attr_geo;
+	scr->args.name		= (const unsigned char *)&scr->rec;
+	scr->args.namelen	= sizeof(struct xfs_parent_name_rec);
+	scr->args.op_flags	= XFS_DA_OP_NVLOOKUP;
+	scr->args.trans		= tp;
+	scr->args.value		= (void *)pptr->p_name;
+	scr->args.valuelen	= pptr->p_namelen;
+	scr->args.whichfork	= XFS_ATTR_FORK;
+	scr->args.hashval	= xfs_da_hashname((const void *)&scr->rec,
+					sizeof(struct xfs_parent_name_rec));
+}
+
+/*
+ * Look up the @name associated with the parent pointer (@pptr) of @ip.
+ * Caller must hold at least ILOCK_SHARED.  Returns 0 if the pointer is found,
+ * -ENOATTR if there is no match, or a negative errno.  The scratchpad need not
+ * be initialized.
+ */
+int
+xfs_parent_lookup(
+	struct xfs_trans		*tp,
+	struct xfs_inode		*ip,
+	const struct xfs_parent_name_irec *pptr,
+	struct xfs_parent_scratch	*scr)
+{
+	int				error;
+
+	/*
+	 * Make sure the attr fork iext tree is loaded in transaction context
+	 * before we start down the rest of the call path.
+	 */
+	if (xfs_inode_hasattr(ip)) {
+		error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);
+		if (error)
+			return error;
+	}
+
+	xfs_parent_irec_to_disk(&scr->rec, pptr);
+	xfs_parent_scratch_init(tp, ip, pptr, scr);
+	scr->args.op_flags |= XFS_DA_OP_OKNOENT;
+
+	return xfs_attr_get_ilocked(&scr->args);
+}
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
index e43ae5a7df826..e4443da1d86f2 100644
--- a/fs/xfs/libxfs/xfs_parent.h
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -152,4 +152,14 @@ void xfs_parent_irec_hashname(struct xfs_mount *mp,
 bool xfs_parent_verify_irec(struct xfs_mount *mp,
 		const struct xfs_parent_name_irec *irec);
 
+/* Scratchpad memory so that raw parent operations don't burn stack space. */
+struct xfs_parent_scratch {
+	struct xfs_parent_name_rec	rec;
+	struct xfs_da_args		args;
+};
+
+int xfs_parent_lookup(struct xfs_trans *tp, struct xfs_inode *ip,
+		const struct xfs_parent_name_irec *pptr,
+		struct xfs_parent_scratch *scratch);
+
 #endif	/* __XFS_PARENT_H__ */
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 3fe6ffcf9c062..88370804025c4 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -16,6 +16,8 @@
 #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"
@@ -41,6 +43,20 @@ xchk_setup_directory(
 
 /* Directories */
 
+struct xchk_dir {
+	struct xfs_scrub	*sc;
+
+	/* Scratch buffer for scanning pptr xattrs */
+	struct xfs_parent_name_irec pptr;
+
+	/* xattr key and da args for parent pointer validation. */
+	struct xfs_parent_scratch pptr_scratch;
+
+	/* Name buffer for dirent revalidation. */
+	uint8_t			namebuf[MAXNAMELEN];
+
+};
+
 /* Scrub a directory entry. */
 
 /* Check that an inode's mode matches a given XFS_DIR3_FT_* type. */
@@ -63,6 +79,94 @@ 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;
+
+	sd->pptr.p_ino = sc->ip->i_ino;
+	sd->pptr.p_gen = VFS_I(sc->ip)->i_generation;
+	sd->pptr.p_namelen = name->len;
+	memcpy(sd->pptr.p_name, name->name, name->len);
+	xfs_parent_irec_hashname(sc->mp, &sd->pptr);
+
+	error = xfs_parent_lookup(sc->tp, ip, &sd->pptr, &sd->pptr_scratch);
+	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) {
+		xchk_set_incomplete(sc);
+		return -ECANCELED;
+	}
+
+	error = xchk_dir_parent_pointer(sd, name, ip);
+	xfs_iunlock(ip, lockmode);
+	return error;
+}
+
 /*
  * Scrub a single directory entry.
  *
@@ -80,6 +184,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 +251,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)
@@ -767,6 +880,7 @@ int
 xchk_directory(
 	struct xfs_scrub	*sc)
 {
+	struct xchk_dir		*sd;
 	int			error;
 
 	if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
@@ -799,8 +913,14 @@ 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;
+
 	/* Look up every name in this directory by hash. */
-	error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, NULL);
+	error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, sd);
+	kvfree(sd);
 	if (error && error != -ECANCELED)
 		return error;
 


  reply	other threads:[~2024-03-18 21:48 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-18 21:39 [PATCHBOMB v13] xfs: parent pointers Darrick J. Wong
2024-03-18 21:41 ` [PATCHSET v13.0 1/2] xfs: Parent Pointers Darrick J. Wong
2024-03-18 21:42   ` [PATCH 01/23] xfs: Expose init_xattrs in xfs_create_tmpfile Darrick J. Wong
2024-03-18 21:42   ` [PATCH 02/23] xfs: add parent pointer support to attribute code Darrick J. Wong
2024-03-18 21:42   ` [PATCH 03/23] xfs: define parent pointer ondisk extended attribute format Darrick J. Wong
2024-03-18 21:43   ` [PATCH 04/23] xfs: add parent pointer validator functions Darrick J. Wong
2024-03-18 21:43   ` [PATCH 05/23] xfs: extend transaction reservations for parent attributes Darrick J. Wong
2024-03-18 21:43   ` [PATCH 06/23] xfs: parent pointer attribute creation Darrick J. Wong
2024-03-18 21:43   ` [PATCH 07/23] xfs: add parent attributes to link Darrick J. Wong
2024-03-18 21:44   ` [PATCH 08/23] xfs: add parent attributes to symlink Darrick J. Wong
2024-03-18 21:44   ` [PATCH 09/23] xfs: remove parent pointers in unlink Darrick J. Wong
2024-03-18 21:44   ` [PATCH 10/23] xfs: Add parent pointers to rename Darrick J. Wong
2024-03-18 21:44   ` [PATCH 11/23] xfs: Add parent pointers to xfs_cross_rename Darrick J. Wong
2024-03-18 21:45   ` [PATCH 12/23] xfs: Filter XFS_ATTR_PARENT for getfattr Darrick J. Wong
2024-03-18 21:45   ` [PATCH 13/23] xfs: pass the attr value to put_listent when possible Darrick J. Wong
2024-03-18 21:45   ` [PATCH 14/23] xfs: add a libxfs header file for staging new ioctls Darrick J. Wong
2024-03-18 21:45   ` [PATCH 15/23] xfs: Add parent pointer ioctl Darrick J. Wong
2024-03-18 21:46   ` [PATCH 16/23] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res Darrick J. Wong
2024-03-18 21:46   ` [PATCH 17/23] xfs: drop compatibility minimum log size computations for reflink Darrick J. Wong
2024-03-18 21:46   ` [PATCH 18/23] xfs: don't remove the attr fork when parent pointers are enabled Darrick J. Wong
2024-03-18 21:46   ` [PATCH 19/23] xfs: Add the parent pointer support to the superblock version 5 Darrick J. Wong
2024-03-18 21:47   ` [PATCH 20/23] xfs: only clear some log incompat bits at unmount Darrick J. Wong
2024-03-18 21:47   ` [PATCH 21/23] xfs: allow adding multiple log incompat feature bits Darrick J. Wong
2024-03-18 21:47   ` [PATCH 22/23] xfs: make XFS_SB_FEAT_INCOMPAT_LOG_XATTRS sticky for parent pointers Darrick J. Wong
2024-03-18 21:47   ` [PATCH 23/23] xfs: make XFS_SB_FEAT_INCOMPAT_LOG_EXCHMAPS " Darrick J. Wong
2024-03-18 21:41 ` [PATCHSET v13.0 2/2] xfs: fsck " Darrick J. Wong
2024-03-18 21:48   ` Darrick J. Wong [this message]
2024-03-18 21:48   ` [PATCH 02/23] xfs: deferred scrub of dirents Darrick J. Wong
2024-03-18 21:48   ` [PATCH 03/23] xfs: create a parent pointer walk function for scrubbers Darrick J. Wong
2024-03-18 21:49   ` [PATCH 04/23] xfs: scrub parent pointers Darrick J. Wong
2024-03-18 21:49   ` [PATCH 05/23] xfs: deferred scrub of " Darrick J. Wong
2024-03-18 21:49   ` [PATCH 06/23] xfs: walk directory parent pointers to determine backref count Darrick J. Wong
2024-03-18 21:49   ` [PATCH 07/23] xfs: add raw parent pointer apis to support repair Darrick J. Wong
2024-03-18 21:50   ` [PATCH 08/23] xfs: set child file owner in xfs_da_args when changing parent pointers Darrick J. Wong
2024-03-18 21:50   ` [PATCH 09/23] xfs: check parent pointer xattrs when scrubbing Darrick J. Wong
2024-03-18 21:50   ` [PATCH 10/23] xfs: salvage parent pointers when rebuilding xattr structures Darrick J. Wong
2024-03-18 21:50   ` [PATCH 11/23] xfs: replace namebuf with parent pointer in directory repair Darrick J. Wong
2024-03-18 21:51   ` [PATCH 12/23] xfs: repair directories by scanning directory parent pointers Darrick J. Wong
2024-03-18 21:51   ` [PATCH 13/23] xfs: implement live updates for directory repairs Darrick J. Wong
2024-03-18 21:51   ` [PATCH 14/23] xfs: replay unlocked parent pointer updates that accrue during xattr repair Darrick J. Wong
2024-03-18 21:51   ` [PATCH 15/23] xfs: replace namebuf with parent pointer in parent pointer repair Darrick J. Wong
2024-03-18 21:52   ` [PATCH 16/23] xfs: repair directory parent pointers by scanning for dirents Darrick J. Wong
2024-03-18 21:52   ` [PATCH 17/23] xfs: implement live updates for parent pointer repairs Darrick J. Wong
2024-03-18 21:52   ` [PATCH 18/23] xfs: remove pointless unlocked assertion Darrick J. Wong
2024-03-18 21:52   ` [PATCH 19/23] xfs: split xfs_bmap_add_attrfork into two pieces Darrick J. Wong
2024-03-18 21:53   ` [PATCH 20/23] xfs: actually rebuild the parent pointer xattrs Darrick J. Wong
2024-03-18 21:53   ` [PATCH 21/23] xfs: adapt the orphanage code to handle parent pointers Darrick J. Wong
2024-03-18 21:53   ` [PATCH 22/23] xfs: repair link count of nondirectories after rebuilding " Darrick J. Wong
2024-03-18 21:53   ` [PATCH 23/23] xfs: inode repair should ensure there's an attr fork to store " Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=171079802711.3808642.9840816764752307950.stgit@frogsfrogsfrogs \
    --to=djwong@kernel.org \
    --cc=allison.henderson@oracle.com \
    --cc=catherine.hoang@oracle.com \
    --cc=hch@lst.de \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.