summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllison Henderson <allison.henderson@oracle.com>2024-04-22 19:47:49 +0300
committerDarrick J. Wong <djwong@kernel.org>2024-04-23 17:46:58 +0300
commit5d31a85dcc1fa4c5d4a925c6da67751653a700ba (patch)
treecb92c3db22fa16c1e6af4fa397506f01f3107750
parentf1097be220fa938de5114db57a1ddb5de2bf6046 (diff)
downloadlinux-5d31a85dcc1fa4c5d4a925c6da67751653a700ba.tar.xz
xfs: add parent attributes to symlink
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>
-rw-r--r--fs/xfs/libxfs/xfs_trans_space.c17
-rw-r--r--fs/xfs/libxfs/xfs_trans_space.h4
-rw-r--r--fs/xfs/scrub/symlink_repair.c2
-rw-r--r--fs/xfs/xfs_symlink.c30
4 files changed, 45 insertions, 8 deletions
diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c
index cf775750120e..c8adda82debe 100644
--- a/fs/xfs/libxfs/xfs_trans_space.c
+++ b/fs/xfs/libxfs/xfs_trans_space.c
@@ -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;
+}
diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h
index 5539634009fb..354ad1d6e18d 100644
--- a/fs/xfs/libxfs/xfs_trans_space.h
+++ b/fs/xfs/libxfs/xfs_trans_space.h
@@ -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__ */
diff --git a/fs/xfs/scrub/symlink_repair.c b/fs/xfs/scrub/symlink_repair.c
index 178304959535..c8b5a5b878ac 100644
--- a/fs/xfs/scrub/symlink_repair.c
+++ b/fs/xfs/scrub/symlink_repair.c
@@ -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)
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 85ef56fdd7df..17aee806ec2e 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -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);