xfs: add parent attributes to link
authorAllison Henderson <allison.henderson@oracle.com>
Mon, 22 Apr 2024 16:47:48 +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_link to add a parent pointer to the inode.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: minor rebase fixes]
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/dir_repair.c
fs/xfs/scrub/orphanage.c
fs/xfs/xfs_inode.c

index 90532c3fa2053754c2bd9412d038ef6b0845f7ac..cf775750120e8d133812486b875ae8b1dc2c087f 100644 (file)
@@ -50,3 +50,17 @@ xfs_mkdir_space_res(
 {
        return xfs_create_space_res(mp, namelen);
 }
+
+unsigned int
+xfs_link_space_res(
+       struct xfs_mount        *mp,
+       unsigned int            namelen)
+{
+       unsigned int            ret;
+
+       ret = XFS_DIRENTER_SPACE_RES(mp, namelen);
+       if (xfs_has_parent(mp))
+               ret += xfs_parent_calc_space_res(mp, namelen);
+
+       return ret;
+}
index 6cda87153b38cf4580eaf3a4a076f6623b1a2613..5539634009fb2b8e7d32032838088969569a477f 100644 (file)
@@ -86,8 +86,6 @@
        (2 * (mp)->m_alloc_maxlevels)
 #define        XFS_GROWFSRT_SPACE_RES(mp,b)    \
        ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK))
-#define        XFS_LINK_SPACE_RES(mp,nl)       \
-       XFS_DIRENTER_SPACE_RES(mp,nl)
 #define        XFS_QM_DQALLOC_SPACE_RES(mp)    \
        (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \
         XFS_DQUOT_CLUSTER_SIZE_FSB)
@@ -107,5 +105,6 @@ 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);
 
 #endif /* __XFS_TRANS_SPACE_H__ */
index 38957da26b94aaf15dddfd019490338ad7c7c863..575397aef1f7a577f0694f2fda4d85d66e4df023 100644 (file)
@@ -704,7 +704,7 @@ xrep_dir_replay_update(
        uint                            resblks;
        int                             error;
 
-       resblks = XFS_LINK_SPACE_RES(mp, xname->len);
+       resblks = xfs_link_space_res(mp, xname->len);
        error = xchk_trans_alloc(rd->sc, resblks);
        if (error)
                return error;
index 885b7d478a0abd993e9e2579af7ef5c8f5ff1269..5e2c3546f2e95dbbd1bf8ac4e33b966774b57371 100644 (file)
@@ -326,7 +326,7 @@ xrep_adoption_trans_alloc(
 
        /* Compute the worst case space reservation that we need. */
        adopt->sc = sc;
-       adopt->orphanage_blkres = XFS_LINK_SPACE_RES(mp, MAXNAMELEN);
+       adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN);
        if (S_ISDIR(VFS_I(sc->ip)->i_mode))
                child_blkres = XFS_RENAME_SPACE_RES(mp, xfs_name_dotdot.len);
        adopt->child_blkres = child_blkres;
index 0dd4111a6773e79ae2eda98b4178633b6afb3f62..61a390f5e2ae69040db7a39e4210dc457f20d839 100644 (file)
@@ -1299,14 +1299,15 @@ xfs_create_tmpfile(
 
 int
 xfs_link(
-       xfs_inode_t             *tdp,
-       xfs_inode_t             *sip,
+       struct xfs_inode        *tdp,
+       struct xfs_inode        *sip,
        struct xfs_name         *target_name)
 {
-       xfs_mount_t             *mp = tdp->i_mount;
-       xfs_trans_t             *tp;
+       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);
 
@@ -1325,11 +1326,25 @@ xfs_link(
        if (error)
                goto std_return;
 
-       resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
+       error = xfs_parent_start(mp, &ppargs);
+       if (error)
+               goto std_return;
+
+       resblks = xfs_link_space_res(mp, target_name->len);
        error = xfs_trans_alloc_dir(tdp, &M_RES(mp)->tr_link, sip, &resblks,
                        &tp, &nospace_error);
        if (error)
-               goto std_return;
+               goto out_parent;
+
+       /*
+        * We don't allow reservationless or quotaless hardlinking when parent
+        * pointers are enabled because we can't back out if the xattrs must
+        * grow.
+        */
+       if (ppargs && nospace_error) {
+               error = nospace_error;
+               goto error_return;
+       }
 
        /*
         * If we are using project inheritance, we only allow hard link
@@ -1380,6 +1395,19 @@ xfs_link(
        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);
 
        /*
@@ -1393,12 +1421,15 @@ xfs_link(
        error = xfs_trans_commit(tp);
        xfs_iunlock(tdp, XFS_ILOCK_EXCL);
        xfs_iunlock(sip, XFS_ILOCK_EXCL);
+       xfs_parent_finish(mp, ppargs);
        return error;
 
  error_return:
        xfs_trans_cancel(tp);
        xfs_iunlock(tdp, XFS_ILOCK_EXCL);
        xfs_iunlock(sip, XFS_ILOCK_EXCL);
+ out_parent:
+       xfs_parent_finish(mp, ppargs);
  std_return:
        if (error == -ENOSPC && nospace_error)
                error = nospace_error;