[PATCH v1 11/17] xfs: add parent attributes to link

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch modifies xfs_link to add a parent pointer to the inode.

[bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
           fixed null pointer bugs]

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx>
---
 fs/xfs/xfs_inode.c | 78 ++++++++++++++++++++++++++++++++++++----------
 fs/xfs/xfs_trans.c |  7 +++--
 fs/xfs/xfs_trans.h |  2 +-
 3 files changed, 67 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 6b1e4cb11b5c..41c58df8e568 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1254,14 +1254,28 @@ xfs_create_tmpfile(
 
 int
 xfs_link(
-	xfs_inode_t		*tdp,
-	xfs_inode_t		*sip,
-	struct xfs_name		*target_name)
-{
-	xfs_mount_t		*mp = tdp->i_mount;
-	xfs_trans_t		*tp;
-	int			error, nospace_error = 0;
-	int			resblks;
+	xfs_inode_t			*tdp,
+	xfs_inode_t			*sip,
+	struct xfs_name			*target_name)
+{
+	xfs_mount_t			*mp = tdp->i_mount;
+	xfs_trans_t			*tp;
+	int				error, nospace_error = 0;
+	int				resblks;
+	struct xfs_parent_name_rec	rec;
+	xfs_dir2_dataptr_t		diroffset;
+
+	struct xfs_da_args		args = {
+		.dp		= sip,
+		.geo		= mp->m_attr_geo,
+		.whichfork	= XFS_ATTR_FORK,
+		.attr_filter	= XFS_ATTR_PARENT,
+		.op_flags	= XFS_DA_OP_OKNOENT,
+		.name		= (const uint8_t *)&rec,
+		.namelen	= sizeof(rec),
+		.value		= (void *)target_name->name,
+		.valuelen	= target_name->len,
+	};
 
 	trace_xfs_link(tdp, target_name);
 
@@ -1278,11 +1292,17 @@ xfs_link(
 	if (error)
 		goto std_return;
 
+	if (xfs_has_larp(mp)) {
+		error = xfs_attr_grab_log_assist(mp);
+		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);
+			&tp, &nospace_error, 0);
 	if (error)
-		goto std_return;
+		goto drop_incompat;
 
 	/*
 	 * If we are using project inheritance, we only allow hard link
@@ -1315,14 +1335,30 @@ xfs_link(
 	}
 
 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-				   resblks, NULL);
+				   resblks, &diroffset);
 	if (error)
-		goto error_return;
+		goto out_defer_cancel;
 	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 (xfs_sb_version_hasparent(&mp->m_sb)) {
+		args.trans = tp;
+		xfs_init_parent_name_rec(&rec, tdp, diroffset);
+		args.hashval = xfs_da_hashname(args.name,
+					       args.namelen);
+		error = xfs_attr_defer_add(&args);
+		if (error)
+			goto out_defer_cancel;
+	}
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * link transaction goes to disk before returning to
@@ -1331,11 +1367,21 @@ xfs_link(
 	if (xfs_has_wsync(mp) || xfs_has_dirsync(mp))
 		xfs_trans_set_sync(tp);
 
-	return xfs_trans_commit(tp);
+	error = xfs_trans_commit(tp);
+	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+	xfs_iunlock(sip, XFS_ILOCK_EXCL);
+	return error;
 
- error_return:
+out_defer_cancel:
+	xfs_defer_cancel(tp);
+error_return:
 	xfs_trans_cancel(tp);
- std_return:
+	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+	xfs_iunlock(sip, XFS_ILOCK_EXCL);
+drop_incompat:
+	if (xfs_has_larp(mp))
+		xlog_drop_incompat_feat(mp->m_log);
+std_return:
 	if (error == -ENOSPC && nospace_error)
 		error = nospace_error;
 	return error;
@@ -2819,7 +2865,7 @@ xfs_remove(
 	 */
 	resblks = XFS_REMOVE_SPACE_RES(mp);
 	error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks,
-			&tp, &dontcare);
+			&tp, &dontcare, XFS_ILOCK_EXCL);
 	if (error) {
 		ASSERT(error != -ENOSPC);
 		goto std_return;
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 82cf0189c0db..544097004b06 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1273,7 +1273,8 @@ xfs_trans_alloc_dir(
 	struct xfs_inode	*ip,
 	unsigned int		*dblocks,
 	struct xfs_trans	**tpp,
-	int			*nospace_error)
+	int			*nospace_error,
+	int			join_flags)
 {
 	struct xfs_trans	*tp;
 	struct xfs_mount	*mp = ip->i_mount;
@@ -1295,8 +1296,8 @@ xfs_trans_alloc_dir(
 
 	xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
 
-	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, dp, join_flags);
+	xfs_trans_ijoin(tp, ip, join_flags);
 
 	error = xfs_qm_dqattach_locked(dp, false);
 	if (error) {
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 9561f193e7e1..4ac175f7ee69 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -266,7 +266,7 @@ int xfs_trans_alloc_ichange(struct xfs_inode *ip, struct xfs_dquot *udqp,
 		struct xfs_trans **tpp);
 int xfs_trans_alloc_dir(struct xfs_inode *dp, struct xfs_trans_res *resv,
 		struct xfs_inode *ip, unsigned int *dblocks,
-		struct xfs_trans **tpp, int *nospace_error);
+		struct xfs_trans **tpp, int *nospace_error, int join_flags);
 
 static inline void
 xfs_trans_set_context(
-- 
2.25.1




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux