xfs: add raw parent pointer apis to support repair
authorDarrick J. Wong <djwong@kernel.org>
Mon, 22 Apr 2024 16:48:09 +0000 (09:48 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 23 Apr 2024 14:47:04 +0000 (07:47 -0700)
Add a couple of utility functions to set or remove parent pointers from
a file.  These functions will be used by repair code, hence they skip
the xattr logging that regular parent pointer updates use.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_parent.c
fs/xfs/libxfs/xfs_parent.h

index 9da99fa20c7591cc268a504dddeab4b287cb2e53..7634344dc5153891cd7533ca180ecb3f20fabdc9 100644 (file)
@@ -434,7 +434,7 @@ int
 xfs_dir_removename(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
-       struct xfs_name         *name,
+       const struct xfs_name   *name,
        xfs_ino_t               ino,
        xfs_extlen_t            total)          /* bmap's total block count */
 {
index eb3a5c35025b56039cad7d47816737ffc73ff611..b580a78bcf4fc29d79cb429af634768d5f926228 100644 (file)
@@ -58,7 +58,7 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
                                const struct xfs_name *name, xfs_ino_t *inum,
                                struct xfs_name *ci_name);
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
-                               struct xfs_name *name, xfs_ino_t ino,
+                               const struct xfs_name *name, xfs_ino_t ino,
                                xfs_extlen_t tot);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                const struct xfs_name *name, xfs_ino_t inum,
index 1e53df5f83323c3fd44451d58096c788446c3ce0..69366c44a701599799481eb178f382bd0b7c4028 100644 (file)
@@ -313,3 +313,67 @@ xfs_parent_lookup(
        xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name);
        return xfs_attr_get_ilocked(scratch);
 }
+
+/* Sanity-check a parent pointer before we try to perform repairs. */
+static inline bool
+xfs_parent_sanity_check(
+       struct xfs_mount                *mp,
+       const struct xfs_name           *parent_name,
+       const struct xfs_parent_rec     *pptr)
+{
+       if (!xfs_parent_namecheck(XFS_ATTR_PARENT, parent_name->name,
+                               parent_name->len))
+               return false;
+
+       if (!xfs_parent_valuecheck(mp, pptr, sizeof(*pptr)))
+               return false;
+
+       return true;
+}
+
+
+/*
+ * Attach the parent pointer (@parent_name -> @pptr) to @ip immediately.
+ * Caller must not have a transaction or hold the ILOCK.  This is for
+ * specialized repair functions only.  The scratchpad need not be initialized.
+ */
+int
+xfs_parent_set(
+       struct xfs_inode        *ip,
+       xfs_ino_t               owner,
+       const struct xfs_name   *parent_name,
+       struct xfs_parent_rec   *pptr,
+       struct xfs_da_args      *scratch)
+{
+       if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
+               ASSERT(0);
+               return -EFSCORRUPTED;
+       }
+
+       memset(scratch, 0, sizeof(struct xfs_da_args));
+       xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
+       return xfs_attr_set(scratch, XFS_ATTRUPDATE_CREATE, false);
+}
+
+/*
+ * Remove the parent pointer (@parent_name -> @pptr) from @ip immediately.
+ * Caller must not have a transaction or hold the ILOCK.  This is for
+ * specialized repair functions only.  The scratchpad need not be initialized.
+ */
+int
+xfs_parent_unset(
+       struct xfs_inode                *ip,
+       xfs_ino_t                       owner,
+       const struct xfs_name           *parent_name,
+       struct xfs_parent_rec           *pptr,
+       struct xfs_da_args              *scratch)
+{
+       if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
+               ASSERT(0);
+               return -EFSCORRUPTED;
+       }
+
+       memset(scratch, 0, sizeof(struct xfs_da_args));
+       xfs_parent_da_args_init(scratch, NULL, pptr, ip, owner, parent_name);
+       return xfs_attr_set(scratch, XFS_ATTRUPDATE_REMOVE, false);
+}
index 97788582321a6fe0fe609b29e01d108381edc0d6..b8036527cdc73c9702f083bf32746d6064b0c21f 100644 (file)
@@ -100,5 +100,11 @@ int xfs_parent_from_attr(struct xfs_mount *mp, unsigned int attr_flags,
 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);
+int xfs_parent_set(struct xfs_inode *ip, xfs_ino_t owner,
+               const struct xfs_name *name, struct xfs_parent_rec *pptr,
+               struct xfs_da_args *scratch);
+int xfs_parent_unset(struct xfs_inode *ip, xfs_ino_t owner,
+               const struct xfs_name *name, struct xfs_parent_rec *pptr,
+               struct xfs_da_args *scratch);
 
 #endif /* __XFS_PARENT_H__ */