]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: create libxfs helper to link an existing inode into a directory
authorDarrick J. Wong <djwong@kernel.org>
Tue, 2 Jul 2024 18:22:43 +0000 (11:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 2 Jul 2024 18:36:59 +0000 (11:36 -0700)
Create a new libxfs function to link an existing inode into a directory.
The upcoming metadata directory feature will need this to create a
metadata directory tree.

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/xfs_inode.c

index bbed03441f5cca9e916cdc9955d788fed7a265d5..5a75f60e851867ff5b10dc86d4563b23eccc493c 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_trans_space.h"
 #include "xfs_parent.h"
+#include "xfs_ag.h"
 
 const struct xfs_name xfs_name_dotdot = {
        .name   = (const unsigned char *)"..",
@@ -587,9 +588,9 @@ xfs_dir_replace(
  */
 int
 xfs_dir_canenter(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *dp,
-       struct xfs_name *name)          /* name of entry to add */
+       struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
+       const struct xfs_name   *name)          /* name of entry to add */
 {
        return xfs_dir_createname(tp, dp, name, 0, 0);
 }
@@ -809,3 +810,67 @@ xfs_dir_create_child(
 
        return 0;
 }
+
+/*
+ * Given a directory @dp, an existing non-directory inode @ip, and a @name,
+ * link @ip into @dp under the given @name.  Both inodes must have the ILOCK
+ * held.
+ */
+int
+xfs_dir_add_child(
+       struct xfs_trans        *tp,
+       unsigned int            resblks,
+       struct xfs_dir_update   *du)
+{
+       struct xfs_inode        *dp = du->dp;
+       const struct xfs_name   *name = du->name;
+       struct xfs_inode        *ip = du->ip;
+       struct xfs_mount        *mp = tp->t_mountp;
+       int                     error;
+
+       xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
+       xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);
+       ASSERT(!S_ISDIR(VFS_I(ip)->i_mode));
+
+       if (!resblks) {
+               error = xfs_dir_canenter(tp, dp, name);
+               if (error)
+                       return error;
+       }
+
+       /*
+        * Handle initial link state of O_TMPFILE inode
+        */
+       if (VFS_I(ip)->i_nlink == 0) {
+               struct xfs_perag        *pag;
+
+               pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
+               error = xfs_iunlink_remove(tp, pag, ip);
+               xfs_perag_put(pag);
+               if (error)
+                       return error;
+       }
+
+       error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks);
+       if (error)
+               return error;
+
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
+
+       xfs_bumplink(tp, ip);
+
+       /*
+        * If we have parent pointers, we now need to add the parent record to
+        * the attribute fork of the inode. If this is the initial parent
+        * attribute, we need to create it correctly, otherwise we can just add
+        * the parent to the inode.
+        */
+       if (du->ppargs) {
+               error = xfs_parent_addname(tp, du->ppargs, dp, name, ip);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
index a1ba6fd0a725fe20e3169bd60888d3acf12d1e3e..4f9711509571a1ab73e3e370e2439b7aeb24dc66 100644 (file)
@@ -74,7 +74,7 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                const struct xfs_name *name, xfs_ino_t inum,
                                xfs_extlen_t tot);
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
-                               struct xfs_name *name);
+                               const struct xfs_name *name);
 
 int xfs_dir_lookup_args(struct xfs_da_args *args);
 int xfs_dir_createname_args(struct xfs_da_args *args);
@@ -320,5 +320,7 @@ struct xfs_dir_update {
 
 int xfs_dir_create_child(struct xfs_trans *tp, unsigned int resblks,
                struct xfs_dir_update *du);
+int xfs_dir_add_child(struct xfs_trans *tp, unsigned int resblks,
+               struct xfs_dir_update *du);
 
 #endif /* __XFS_DIR2_H__ */
index e80548ac2b278378e98c1c75bd02f3b67ca02b65..959fdaef840946a54e4a8abd1a270d7fb05c3934 100644 (file)
@@ -952,11 +952,15 @@ xfs_link(
        struct xfs_inode        *sip,
        struct xfs_name         *target_name)
 {
+       struct xfs_dir_update   du = {
+               .dp             = tdp,
+               .name           = target_name,
+               .ip             = sip,
+       };
        struct xfs_mount        *mp = tdp->i_mount;
        struct xfs_trans        *tp;
        int                     error, nospace_error = 0;
        int                     resblks;
-       struct xfs_parent_args  *ppargs;
 
        trace_xfs_link(tdp, target_name);
 
@@ -975,7 +979,7 @@ xfs_link(
        if (error)
                goto std_return;
 
-       error = xfs_parent_start(mp, &ppargs);
+       error = xfs_parent_start(mp, &du.ppargs);
        if (error)
                goto std_return;
 
@@ -990,7 +994,7 @@ xfs_link(
         * pointers are enabled because we can't back out if the xattrs must
         * grow.
         */
-       if (ppargs && nospace_error) {
+       if (du.ppargs && nospace_error) {
                error = nospace_error;
                goto error_return;
        }
@@ -1017,45 +1021,9 @@ xfs_link(
                }
        }
 
-       if (!resblks) {
-               error = xfs_dir_canenter(tp, tdp, target_name);
-               if (error)
-                       goto error_return;
-       }
-
-       /*
-        * Handle initial link state of O_TMPFILE inode
-        */
-       if (VFS_I(sip)->i_nlink == 0) {
-               struct xfs_perag        *pag;
-
-               pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sip->i_ino));
-               error = xfs_iunlink_remove(tp, pag, sip);
-               xfs_perag_put(pag);
-               if (error)
-                       goto error_return;
-       }
-
-       error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-                                  resblks);
+       error = xfs_dir_add_child(tp, resblks, &du);
        if (error)
                goto error_return;
-       xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
-
-       xfs_bumplink(tp, sip);
-
-       /*
-        * If we have parent pointers, we now need to add the parent record to
-        * the attribute fork of the inode. If this is the initial parent
-        * attribute, we need to create it correctly, otherwise we can just add
-        * the parent to the inode.
-        */
-       if (ppargs) {
-               error = xfs_parent_addname(tp, ppargs, tdp, target_name, sip);
-               if (error)
-                       goto error_return;
-       }
 
        xfs_dir_update_hook(tdp, sip, 1, target_name);
 
@@ -1070,7 +1038,7 @@ xfs_link(
        error = xfs_trans_commit(tp);
        xfs_iunlock(tdp, XFS_ILOCK_EXCL);
        xfs_iunlock(sip, XFS_ILOCK_EXCL);
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
        return error;
 
  error_return:
@@ -1078,7 +1046,7 @@ xfs_link(
        xfs_iunlock(tdp, XFS_ILOCK_EXCL);
        xfs_iunlock(sip, XFS_ILOCK_EXCL);
  out_parent:
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
  std_return:
        if (error == -ENOSPC && nospace_error)
                error = nospace_error;