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: