xfs: add parent attributes to symlink
authorAllison Henderson <allison.henderson@oracle.com>
Mon, 22 Apr 2024 16:47:49 +0000 (09:47 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 23 Apr 2024 14:46:58 +0000 (07:46 -0700)
This patch modifies xfs_symlink to add a parent pointer to the inode.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: minor rebase fixups]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_trans_space.c
fs/xfs/libxfs/xfs_trans_space.h
fs/xfs/scrub/symlink_repair.c
fs/xfs/xfs_symlink.c

index cf775750120e8d133812486b875ae8b1dc2c087f..c8adda82debe08eed957c682e9cb1ddd18c36672 100644 (file)
@@ -64,3 +64,20 @@ xfs_link_space_res(
 
        return ret;
 }
+
+unsigned int
+xfs_symlink_space_res(
+       struct xfs_mount        *mp,
+       unsigned int            namelen,
+       unsigned int            fsblocks)
+{
+       unsigned int            ret;
+
+       ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) +
+                       fsblocks;
+
+       if (xfs_has_parent(mp))
+               ret += xfs_parent_calc_space_res(mp, namelen);
+
+       return ret;
+}
index 5539634009fb2b8e7d32032838088969569a477f..354ad1d6e18d6c584d927eb0ae1edf35434cf677 100644 (file)
@@ -95,8 +95,6 @@
        XFS_DIRREMOVE_SPACE_RES(mp)
 #define        XFS_RENAME_SPACE_RES(mp,nl)     \
        (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
-#define        XFS_SYMLINK_SPACE_RES(mp,nl,b)  \
-       (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
 #define XFS_IFREE_SPACE_RES(mp)                \
        (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0)
 
@@ -106,5 +104,7 @@ unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp,
 unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen);
 unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen);
 unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen);
+unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen,
+               unsigned int fsblocks);
 
 #endif /* __XFS_TRANS_SPACE_H__ */
index 178304959535a600bfabee0b4221f125827f41d2..c8b5a5b878ac9fb52539c7e8dd524a977ba7600a 100644 (file)
@@ -421,7 +421,7 @@ xrep_symlink_rebuild(
         * unlikely.
         */
        fs_blocks = xfs_symlink_blocks(sc->mp, target_len);
-       resblks = XFS_SYMLINK_SPACE_RES(sc->mp, target_len, fs_blocks);
+       resblks = xfs_symlink_space_res(sc->mp, target_len, fs_blocks);
        error = xfs_trans_reserve_quota_nblks(sc->tp, sc->tempip, resblks, 0,
                        true);
        if (error)
index 85ef56fdd7dfe8e1868c965b2f29ec7a71c02a05..17aee806ec2e1c7296f255cd274326ca1015e88b 100644 (file)
@@ -25,6 +25,8 @@
 #include "xfs_error.h"
 #include "xfs_health.h"
 #include "xfs_symlink_remote.h"
+#include "xfs_parent.h"
+#include "xfs_defer.h"
 
 int
 xfs_readlink(
@@ -100,6 +102,7 @@ xfs_symlink(
        struct xfs_dquot        *pdqp = NULL;
        uint                    resblks;
        xfs_ino_t               ino;
+       struct xfs_parent_args  *ppargs;
 
        *ipp = NULL;
 
@@ -130,18 +133,24 @@ xfs_symlink(
 
        /*
         * The symlink will fit into the inode data fork?
-        * There can't be any attributes so we get the whole variable part.
+        * If there are no parent pointers, then there wont't be any attributes.
+        * So we get the whole variable part, and do not need to reserve extra
+        * blocks.  Otherwise, we need to reserve the blocks.
         */
-       if (pathlen <= XFS_LITINO(mp))
+       if (pathlen <= XFS_LITINO(mp) && !xfs_has_parent(mp))
                fs_blocks = 0;
        else
                fs_blocks = xfs_symlink_blocks(mp, pathlen);
-       resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
+       resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks);
+
+       error = xfs_parent_start(mp, &ppargs);
+       if (error)
+               goto out_release_dquots;
 
        error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp,
                        pdqp, resblks, &tp);
        if (error)
-               goto out_release_dquots;
+               goto out_parent;
 
        xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
        unlock_dp_on_error = true;
@@ -161,7 +170,7 @@ xfs_symlink(
        if (!error)
                error = xfs_init_new_inode(idmap, tp, dp, ino,
                                S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
-                               false, &ip);
+                               xfs_has_parent(mp), &ip);
        if (error)
                goto out_trans_cancel;
 
@@ -195,6 +204,14 @@ xfs_symlink(
                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);
 
        /*
@@ -216,6 +233,7 @@ xfs_symlink(
        *ipp = ip;
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       xfs_parent_finish(mp, ppargs);
        return 0;
 
 out_trans_cancel:
@@ -231,6 +249,8 @@ out_release_inode:
                xfs_finish_inode_setup(ip);
                xfs_irele(ip);
        }
+out_parent:
+       xfs_parent_finish(mp, ppargs);
 out_release_dquots:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);