summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_attr_item.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_attr_item.c')
-rw-r--r--fs/xfs/xfs_attr_item.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 135d44133477..4f37fb251fe7 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -455,6 +455,8 @@ static inline void
xfs_attr_free_item(
struct xfs_attr_intent *attr)
{
+ ASSERT(attr->xattri_leaf_bp == NULL);
+
if (attr->xattri_da_state)
xfs_da_state_free(attr->xattri_da_state);
xfs_attri_log_nameval_put(attr->xattri_nameval);
@@ -509,6 +511,10 @@ xfs_attr_cancel_item(
struct xfs_attr_intent *attr;
attr = container_of(item, struct xfs_attr_intent, xattri_list);
+ if (attr->xattri_leaf_bp) {
+ xfs_buf_relse(attr->xattri_leaf_bp);
+ attr->xattri_leaf_bp = NULL;
+ }
xfs_attr_free_item(attr);
}
@@ -670,9 +676,21 @@ xfs_attri_item_recover(
error = xfs_defer_ops_capture_and_commit(tp, capture_list);
out_unlock:
- if (attr->xattri_leaf_bp)
+ if (attr->xattri_leaf_bp) {
xfs_buf_relse(attr->xattri_leaf_bp);
+ /*
+ * If there's more work to do to complete the attr intent, the
+ * defer capture structure will have taken its own reference to
+ * the attr leaf buffer and will give that to the continuation
+ * transaction. The attr intent struct drives the continuation
+ * work, so release our refcount on the attr leaf buffer but
+ * retain the pointer in the intent structure.
+ */
+ if (ret != -EAGAIN)
+ attr->xattri_leaf_bp = NULL;
+ }
+
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_irele(ip);
out: