[PATCH v9 11/28] xfs: Roll delayed attr operations by returning EAGAIN

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

 



This patch modifies xfs_attr_set_args to return -EAGAIN
when a transaction needs to be rolled.  All functions
currently calling xfs_attr_set_args are modified to use
the deferred attr operation, or handle the -EAGAIN return
code

Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx>
---
 fs/xfs/libxfs/xfs_attr.c | 43 ++++++++++++++++++++++++++++---------
 fs/xfs/libxfs/xfs_attr.h |  2 +-
 fs/xfs/xfs_attr_item.c   | 41 ++++++++++++++++++++++++++++++------
 fs/xfs/xfs_trans.h       |  2 ++
 fs/xfs/xfs_trans_attr.c  | 55 ++++++++++++++++++++++++++++--------------------
 5 files changed, 103 insertions(+), 40 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 318d71e..aa99dd2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -238,12 +238,20 @@ int
 xfs_attr_set_args(
 	struct xfs_da_args	*args,
 	struct xfs_buf          **leaf_bp,
+	xfs_attr_state_t	*state,
 	bool			roll_trans)
 {
 	struct xfs_inode	*dp = args->dp;
 	int			error = 0;
 	int			sf_size;
 
+	switch (*state) {
+	case (XFS_ATTR_STATE1):
+		goto state1;
+	case (XFS_ATTR_STATE2):
+		goto state2;
+	}
+
 	/*
 	 * New inodes setting the parent pointer attr will
 	 * not have an attribute fork yet. So set the attribute
@@ -264,7 +272,6 @@ xfs_attr_set_args(
 	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
 	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 	     dp->i_d.di_anextents == 0)) {
-
 		/*
 		 * Build initial attribute list (if required).
 		 */
@@ -278,6 +285,9 @@ xfs_attr_set_args(
 		if (error != -ENOSPC)
 			goto out;
 
+		*state = XFS_ATTR_STATE1;
+		return -EAGAIN;
+state1:
 		/*
 		 * It won't fit in the shortform, transform to a leaf block.
 		 * GROT: another possible req'mt for a double-split btree op.
@@ -286,14 +296,14 @@ xfs_attr_set_args(
 		if (error)
 			goto out;
 
-		if (roll_trans) {
-			/*
-			 * Prevent the leaf buffer from being unlocked so that a
-			 * concurrent AIL push cannot grab the half-baked leaf
-			 * buffer and run into problems with the write verifier.
-			 */
-			xfs_trans_bhold(args->trans, *leaf_bp);
+		/*
+		 * Prevent the leaf buffer from being unlocked so that a
+		 * concurrent AIL push cannot grab the half-baked leaf
+		 * buffer and run into problems with the write verifier.
+		 */
+		xfs_trans_bhold(args->trans, *leaf_bp);
 
+		if (roll_trans) {
 			error = xfs_defer_finish(&args->trans);
 			if (error)
 				goto out;
@@ -309,6 +319,12 @@ xfs_attr_set_args(
 			xfs_trans_bjoin(args->trans, *leaf_bp);
 			*leaf_bp = NULL;
 		}
+
+		*state = XFS_ATTR_STATE2;
+		return -EAGAIN;
+state2:
+		if (*leaf_bp != NULL)
+			xfs_trans_brelse(args->trans, *leaf_bp);
 	}
 
 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
@@ -441,7 +457,9 @@ xfs_attr_set(
 	}
 
 	xfs_trans_ijoin(args.trans, dp, 0);
-	error = xfs_attr_set_args(&args, &leaf_bp, true);
+
+	error = xfs_attr_set_deferred(dp, args.trans, name, strlen(name),
+			value, valuelen, flags);
 	if (error)
 		goto out;
 
@@ -571,8 +589,13 @@ xfs_attr_remove(
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
 
-	error = xfs_attr_remove_args(&args, true);
+	error = xfs_has_attr(&args);
+	if (error)
+		goto out;
+
 
+	error = xfs_attr_remove_deferred(dp, args.trans,
+			name, strlen(name), flags);
 	if (error)
 		goto out;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 38334e0..92960ab 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -178,7 +178,7 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
 		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args, struct xfs_buf **leaf_bp,
-		 bool roll_trans);
+		 xfs_attr_state_t *state, bool roll_trans);
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args, bool roll_trans);
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 56fc0b0..b8db2da 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -475,8 +475,11 @@ xfs_attri_recover(
 	struct xfs_attri_log_format	*attrp;
 	struct xfs_trans_res		tres;
 	int				local;
-	int				error = 0;
+	int				error, err2 = 0;
 	int				rsvd = 0;
+	xfs_attr_state_t		state = 0;
+	struct xfs_buf			*leaf_bp = NULL;
+
 
 	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
 
@@ -551,14 +554,40 @@ xfs_attri_recover(
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
 
 	xfs_trans_ijoin(args.trans, ip, 0);
-	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
-	if (error)
-		goto abort_error;
 
+	do {
+		leaf_bp = NULL;
+
+		error = xfs_trans_attr(&args, attrdp, &leaf_bp, &state,
+				attrp->alfi_op_flags);
+		if (error && error != -EAGAIN)
+			goto abort_error;
+
+		xfs_trans_log_inode(args.trans, ip,
+				XFS_ILOG_CORE | XFS_ILOG_ADATA);
+
+		err2 = xfs_trans_commit(args.trans);
+		if (err2) {
+			error = err2;
+			goto abort_error;
+		}
+
+		if (error == -EAGAIN) {
+			err2 = xfs_trans_alloc(mp, &tres, args.total, 0,
+				XFS_TRANS_PERM_LOG_RES, &args.trans);
+			if (err2) {
+				error = err2;
+				goto abort_error;
+			}
+			xfs_trans_ijoin(args.trans, ip, 0);
+		}
+
+	} while (error == -EAGAIN);
+
+	if (leaf_bp)
+		xfs_trans_brelse(args.trans, leaf_bp);
 
 	set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
-	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
-	error = xfs_trans_commit(args.trans);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return error;
 
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 433bada..cc38d45 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -240,6 +240,8 @@ xfs_trans_get_attrd(struct xfs_trans *tp,
 		    struct xfs_attri_log_item *attrip);
 int xfs_trans_attr(	struct xfs_da_args *args,
 			struct xfs_attrd_log_item *attrdp,
+			struct xfs_buf **leaf_bp,
+			void *state,
 			uint32_t attr_op_flags);
 
 int		xfs_trans_commit(struct xfs_trans *);
diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
index 87607b2..db6cb6d 100644
--- a/fs/xfs/xfs_trans_attr.c
+++ b/fs/xfs/xfs_trans_attr.c
@@ -67,10 +67,11 @@ int
 xfs_trans_attr(
 	struct xfs_da_args		*args,
 	struct xfs_attrd_log_item	*attrdp,
+	struct xfs_buf			**leaf_bp,
+	void				*state,
 	uint32_t			op_flags)
 {
 	int				error;
-	struct xfs_buf			*leaf_bp = NULL;
 
 	error = xfs_qm_dqattach_locked(args->dp, 0);
 	if (error)
@@ -79,7 +80,8 @@ xfs_trans_attr(
 	switch (op_flags) {
 		case XFS_ATTR_OP_FLAGS_SET:
 			args->op_flags |= XFS_DA_OP_ADDNAME;
-			error = xfs_attr_set_args(args,&leaf_bp, false);
+			error = xfs_attr_set_args(args, leaf_bp,
+					(xfs_attr_state_t *)state, false);
 			break;
 		case XFS_ATTR_OP_FLAGS_REMOVE:
 			ASSERT(XFS_IFORK_Q((args->dp)));
@@ -89,11 +91,6 @@ xfs_trans_attr(
 			error = -EFSCORRUPTED;
 	}
 
-	if (error) {
-		if (leaf_bp)
-			xfs_trans_brelse(args->trans, leaf_bp);
-	}
-
 	/*
 	 * Mark the transaction dirty, even on error. This ensures the
 	 * transaction is aborted, which:
@@ -195,27 +192,39 @@ xfs_attr_finish_item(
 	char				*name_value;
 	int				error;
 	int				local;
-	struct xfs_da_args		args;
+	struct xfs_da_args		*args;
 
 	attr = container_of(item, struct xfs_attr_item, xattri_list);
-	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
-
-	error = xfs_attr_args_init(&args, attr->xattri_ip, name_value,
-					attr->xattri_flags);
-	if (error)
-		goto out;
+	args = &attr->xattri_args;
+
+	if (attr->xattri_state == 0) {
+		/* Only need to initialize args context once */
+		name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+		error = xfs_attr_args_init(args, attr->xattri_ip, name_value,
+						attr->xattri_flags);
+		if (error)
+			goto out;
+
+		args->hashval = xfs_da_hashname(args->name, args->namelen);
+		args->value = &name_value[attr->xattri_name_len];
+		args->valuelen = attr->xattri_value_len;
+		args->op_flags = XFS_DA_OP_OKNOENT;
+		args->total = xfs_attr_calc_size(args, &local);
+		attr->xattri_leaf_bp = NULL;
+	}
 
-	args.hashval = xfs_da_hashname(args.name, args.namelen);
-	args.value = &name_value[attr->xattri_name_len];
-	args.valuelen = attr->xattri_value_len;
-	args.op_flags = XFS_DA_OP_OKNOENT;
-	args.total = xfs_attr_calc_size(&args, &local);
-	args.trans = tp;
+	/*
+	 * Always reset trans after EAGAIN cycle
+	 * since the transaction is new
+	 */
+	args->trans = tp;
 
-	error = xfs_trans_attr(&args, done_item,
-			attr->xattri_op_flags);
+	error = xfs_trans_attr(args, done_item, &attr->xattri_leaf_bp,
+			&attr->xattri_state, attr->xattri_op_flags);
 out:
-	kmem_free(attr);
+	if (error != -EAGAIN)
+		kmem_free(attr);
+
 	return error;
 }
 
-- 
2.7.4




[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