]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: create libxfs helper to link a new inode into a directory
authorDarrick J. Wong <djwong@kernel.org>
Tue, 2 Jul 2024 18:22:42 +0000 (11:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 2 Jul 2024 18:36:58 +0000 (11:36 -0700)
Create a new libxfs function to link a newly created 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
fs/xfs/xfs_symlink.c

index 457f9a38f850456be9817ecf6fc693808807c6aa..bbed03441f5cca9e916cdc9955d788fed7a265d5 100644 (file)
@@ -19,6 +19,9 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_health.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans_space.h"
+#include "xfs_parent.h"
 
 const struct xfs_name xfs_name_dotdot = {
        .name   = (const unsigned char *)"..",
@@ -756,3 +759,53 @@ xfs_dir2_compname(
                return xfs_ascii_ci_compname(args, name, len);
        return xfs_da_compname(args, name, len);
 }
+
+/*
+ * Given a directory @dp, a newly allocated inode @ip, and a @name, link @ip
+ * into @dp under the given @name.  If @ip is a directory, it will be
+ * initialized.  Both inodes must have the ILOCK held and the transaction must
+ * have sufficient blocks reserved.
+ */
+int
+xfs_dir_create_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;
+       int                     error;
+
+       xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
+       xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);
+
+       error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks);
+       if (error) {
+               ASSERT(error != -ENOSPC);
+               return error;
+       }
+
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
+
+       if (S_ISDIR(VFS_I(ip)->i_mode)) {
+               error = xfs_dir_init(tp, ip, dp);
+               if (error)
+                       return error;
+
+               xfs_bumplink(tp, dp);
+       }
+
+       /*
+        * If we have parent pointers, we need to add the attribute containing
+        * the parent information now.
+        */
+       if (du->ppargs) {
+               error = xfs_parent_addname(tp, du->ppargs, dp, name, ip);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
index 6dbe6e9ecb491f69e87e2b8ba2dc54a73f59355a..a1ba6fd0a725fe20e3169bd60888d3acf12d1e3e 100644 (file)
@@ -309,4 +309,16 @@ static inline unsigned char xfs_ascii_ci_xfrm(unsigned char c)
        return c;
 }
 
+struct xfs_parent_args;
+
+struct xfs_dir_update {
+       struct xfs_inode        *dp;
+       const struct xfs_name   *name;
+       struct xfs_inode        *ip;
+       struct xfs_parent_args  *ppargs;
+};
+
+int xfs_dir_create_child(struct xfs_trans *tp, unsigned int resblks,
+               struct xfs_dir_update *du);
+
 #endif /* __XFS_DIR2_H__ */
index 0062ba92bcc8878017cff7abe4adff56231cd1ac..e80548ac2b278378e98c1c75bd02f3b67ca02b65 100644 (file)
@@ -714,14 +714,16 @@ xfs_create(
        struct xfs_inode        **ipp)
 {
        struct xfs_inode        *dp = args->pip;
+       struct xfs_dir_update   du = {
+               .dp             = dp,
+               .name           = name,
+       };
        struct xfs_mount        *mp = dp->i_mount;
-       struct xfs_inode        *ip = NULL;
        struct xfs_trans        *tp = NULL;
        struct xfs_dquot        *udqp;
        struct xfs_dquot        *gdqp;
        struct xfs_dquot        *pdqp;
        struct xfs_trans_res    *tres;
-       struct xfs_parent_args  *ppargs;
        xfs_ino_t               ino;
        bool                    unlock_dp_on_error = false;
        bool                    is_dir = S_ISDIR(args->mode);
@@ -748,7 +750,7 @@ xfs_create(
                tres = &M_RES(mp)->tr_create;
        }
 
-       error = xfs_parent_start(mp, &ppargs);
+       error = xfs_parent_start(mp, &du.ppargs);
        if (error)
                goto out_release_dquots;
 
@@ -779,7 +781,7 @@ xfs_create(
         */
        error = xfs_dialloc(&tp, dp->i_ino, args->mode, &ino);
        if (!error)
-               error = xfs_icreate(tp, ino, args, &ip);
+               error = xfs_icreate(tp, ino, args, &du.ip);
        if (error)
                goto out_trans_cancel;
 
@@ -792,38 +794,15 @@ xfs_create(
         */
        xfs_trans_ijoin(tp, dp, 0);
 
-       error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-                                       resblks - XFS_IALLOC_SPACE_RES(mp));
-       if (error) {
-               ASSERT(error != -ENOSPC);
+       error = xfs_dir_create_child(tp, resblks, &du);
+       if (error)
                goto out_trans_cancel;
-       }
-       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-
-       if (is_dir) {
-               error = xfs_dir_init(tp, ip, dp);
-               if (error)
-                       goto out_trans_cancel;
-
-               xfs_bumplink(tp, dp);
-       }
-
-       /*
-        * If we have parent pointers, we need to add the attribute containing
-        * the parent information now.
-        */
-       if (ppargs) {
-               error = xfs_parent_addname(tp, ppargs, dp, name, ip);
-               if (error)
-                       goto out_trans_cancel;
-       }
 
        /*
         * Create ip with a reference from dp, and add '.' and '..' references
         * if it's a directory.
         */
-       xfs_dir_update_hook(dp, ip, 1, name);
+       xfs_dir_update_hook(dp, du.ip, 1, name);
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -838,7 +817,7 @@ xfs_create(
         * These ids of the inode couldn't have changed since the new
         * inode has been locked ever since it was created.
         */
-       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
+       xfs_qm_vop_create_dqattach(tp, du.ip, udqp, gdqp, pdqp);
 
        error = xfs_trans_commit(tp);
        if (error)
@@ -848,10 +827,10 @@ xfs_create(
        xfs_qm_dqrele(gdqp);
        xfs_qm_dqrele(pdqp);
 
-       *ipp = ip;
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       *ipp = du.ip;
+       xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
        return 0;
 
  out_trans_cancel:
@@ -862,13 +841,13 @@ xfs_create(
         * setup of the inode and release the inode.  This prevents recursive
         * transactions and deadlocks from xfs_inactive.
         */
-       if (ip) {
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               xfs_finish_inode_setup(ip);
-               xfs_irele(ip);
+       if (du.ip) {
+               xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
+               xfs_finish_inode_setup(du.ip);
+               xfs_irele(du.ip);
        }
  out_parent:
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
  out_release_dquots:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
index e471369f6b634eaa253cb5f82588c8cdf09d8554..c0f5c2e1f215b8283dff97cf8363ee9494dfdaa1 100644 (file)
@@ -95,8 +95,11 @@ xfs_symlink(
                .pip            = dp,
                .mode           = S_IFLNK | (mode & ~S_IFMT),
        };
+       struct xfs_dir_update   du = {
+               .dp             = dp,
+               .name           = link_name,
+       };
        struct xfs_trans        *tp = NULL;
-       struct xfs_inode        *ip = NULL;
        int                     error = 0;
        int                     pathlen;
        bool                    unlock_dp_on_error = false;
@@ -106,7 +109,6 @@ xfs_symlink(
        struct xfs_dquot        *pdqp;
        uint                    resblks;
        xfs_ino_t               ino;
-       struct xfs_parent_args  *ppargs;
 
        *ipp = NULL;
 
@@ -140,7 +142,7 @@ xfs_symlink(
                fs_blocks = xfs_symlink_blocks(mp, pathlen);
        resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks);
 
-       error = xfs_parent_start(mp, &ppargs);
+       error = xfs_parent_start(mp, &du.ppargs);
        if (error)
                goto out_release_dquots;
 
@@ -165,7 +167,7 @@ xfs_symlink(
         */
        error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
        if (!error)
-               error = xfs_icreate(tp, ino, &args, &ip);
+               error = xfs_icreate(tp, ino, &args, &du.ip);
        if (error)
                goto out_trans_cancel;
 
@@ -181,33 +183,24 @@ xfs_symlink(
        /*
         * Also attach the dquot(s) to it, if applicable.
         */
-       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
+       xfs_qm_vop_create_dqattach(tp, du.ip, udqp, gdqp, pdqp);
 
        resblks -= XFS_IALLOC_SPACE_RES(mp);
-       error = xfs_symlink_write_target(tp, ip, ip->i_ino, target_path,
+       error = xfs_symlink_write_target(tp, du.ip, du.ip->i_ino, target_path,
                        pathlen, fs_blocks, resblks);
        if (error)
                goto out_trans_cancel;
        resblks -= fs_blocks;
-       i_size_write(VFS_I(ip), ip->i_disk_size);
+       i_size_write(VFS_I(du.ip), du.ip->i_disk_size);
 
        /*
         * Create the directory entry for the symlink.
         */
-       error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
+       error = xfs_dir_create_child(tp, resblks, &du);
        if (error)
                goto out_trans_cancel;
-       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-
-       /* Add parent pointer for the new symlink. */
-       if (ppargs) {
-               error = xfs_parent_addname(tp, ppargs, dp, link_name, ip);
-               if (error)
-                       goto out_trans_cancel;
-       }
 
-       xfs_dir_update_hook(dp, ip, 1, link_name);
+       xfs_dir_update_hook(dp, du.ip, 1, link_name);
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -225,10 +218,10 @@ xfs_symlink(
        xfs_qm_dqrele(gdqp);
        xfs_qm_dqrele(pdqp);
 
-       *ipp = ip;
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       *ipp = du.ip;
+       xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
        return 0;
 
 out_trans_cancel:
@@ -239,13 +232,13 @@ out_release_inode:
         * setup of the inode and release the inode.  This prevents recursive
         * transactions and deadlocks from xfs_inactive.
         */
-       if (ip) {
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               xfs_finish_inode_setup(ip);
-               xfs_irele(ip);
+       if (du.ip) {
+               xfs_iunlock(du.ip, XFS_ILOCK_EXCL);
+               xfs_finish_inode_setup(du.ip);
+               xfs_irele(du.ip);
        }
 out_parent:
-       xfs_parent_finish(mp, ppargs);
+       xfs_parent_finish(mp, du.ppargs);
 out_release_dquots:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);