aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2015-08-18 19:52:21 -0400
committerDave Chinner <david@fromorbit.com>2015-08-18 19:52:21 -0400
commite32a1d1fbf6eb2bdc24aa0502e827ff4d2234604 (patch)
tree86f8a2fc5ac53c1db1a499d0ffe7213a09f9fd49
parent6bc43af3d5f507254b8de2058ea51f6ec998ae52 (diff)
xfs: use EFI refcount consistently in log recovery
The EFI is initialized with a reference count of 2. One for the EFI to ensure the item makes it to the AIL and one for the subsequently created EFD to release the EFI once the EFD is committed. Log recovery uses the EFI in a similar manner, but implements a hack to remove both references in one call once the EFD is handled. Update log recovery to use EFI reference counting in a manner consistent with the log. When an EFI is encountered during recovery, an EFI item is allocated and inserted to the AIL directly. Since the EFI reference is typically dropped when the EFI is unpinned and this is analogous with AIL insertion, drop the EFI reference at this point. When a corresponding EFD is encountered in the log, this indicates that the extents were freed, no processing is required and the EFI can be dropped. Update xlog_recover_efd_pass2() to simply drop the EFD reference at this point rather than open code the AIL removal and EFI free. Remaining EFIs (i.e., with no corresponding EFD) are processed in xlog_recover_finish(). An EFD transaction is allocated and the extents are freed, which transfers ownership of the EFI reference to the EFD item in the log. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_extfree_item.c57
-rw-r--r--fs/xfs/xfs_log_recover.c43
2 files changed, 43 insertions, 57 deletions
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 475b9f00ae23..ce1d4fb39c4d 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -47,34 +47,6 @@ xfs_efi_item_free(
47} 47}
48 48
49/* 49/*
50 * Freeing the efi requires that we remove it from the AIL if it has already
51 * been placed there. However, the EFI may not yet have been placed in the AIL
52 * when called by xfs_efi_release() from EFD processing due to the ordering of
53 * committed vs unpin operations in bulk insert operations. Hence the reference
54 * count to ensure only the last caller frees the EFI.
55 */
56STATIC void
57__xfs_efi_release(
58 struct xfs_efi_log_item *efip)
59{
60 struct xfs_ail *ailp = efip->efi_item.li_ailp;
61
62 if (atomic_dec_and_test(&efip->efi_refcount)) {
63 spin_lock(&ailp->xa_lock);
64 /*
65 * We don't know whether the EFI made it to the AIL. Remove it
66 * if so. Note that xfs_trans_ail_delete() drops the AIL lock.
67 */
68 if (efip->efi_item.li_flags & XFS_LI_IN_AIL)
69 xfs_trans_ail_delete(ailp, &efip->efi_item,
70 SHUTDOWN_LOG_IO_ERROR);
71 else
72 spin_unlock(&ailp->xa_lock);
73 xfs_efi_item_free(efip);
74 }
75}
76
77/*
78 * This returns the number of iovecs needed to log the given efi item. 50 * This returns the number of iovecs needed to log the given efi item.
79 * We only need 1 iovec for an efi item. It just logs the efi_log_format 51 * We only need 1 iovec for an efi item. It just logs the efi_log_format
80 * structure. 52 * structure.
@@ -304,21 +276,32 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
304} 276}
305 277
306/* 278/*
307 * This is called by the efd item code below to release references to the given 279 * Freeing the efi requires that we remove it from the AIL if it has already
308 * efi item. Each efd calls this with the number of extents that it has 280 * been placed there. However, the EFI may not yet have been placed in the AIL
309 * logged, and when the sum of these reaches the total number of extents logged 281 * when called by xfs_efi_release() from EFD processing due to the ordering of
310 * by this efi item we can free the efi item. 282 * committed vs unpin operations in bulk insert operations. Hence the reference
283 * count to ensure only the last caller frees the EFI.
311 */ 284 */
312void 285void
313xfs_efi_release( 286xfs_efi_release(
314 struct xfs_efi_log_item *efip) 287 struct xfs_efi_log_item *efip)
315{ 288{
316 /* recovery needs us to drop the EFI reference, too */ 289 struct xfs_ail *ailp = efip->efi_item.li_ailp;
317 if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags))
318 __xfs_efi_release(efip);
319 290
320 __xfs_efi_release(efip); 291 if (atomic_dec_and_test(&efip->efi_refcount)) {
321 /* efip may now have been freed, do not reference it again. */ 292 spin_lock(&ailp->xa_lock);
293 /*
294 * We don't know whether the EFI made it to the AIL. Remove it
295 * if so. Note that xfs_trans_ail_delete() drops the AIL lock.
296 */
297 if (efip->efi_item.li_flags & XFS_LI_IN_AIL)
298 xfs_trans_ail_delete(ailp, &efip->efi_item,
299 SHUTDOWN_LOG_IO_ERROR);
300 else
301 spin_unlock(&ailp->xa_lock);
302
303 xfs_efi_item_free(efip);
304 }
322} 305}
323 306
324static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip) 307static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 434ba2cdf6e8..05c0cc83f9a4 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2928,16 +2928,16 @@ xlog_recover_efi_pass2(
2928 struct xlog_recover_item *item, 2928 struct xlog_recover_item *item,
2929 xfs_lsn_t lsn) 2929 xfs_lsn_t lsn)
2930{ 2930{
2931 int error; 2931 int error;
2932 xfs_mount_t *mp = log->l_mp; 2932 struct xfs_mount *mp = log->l_mp;
2933 xfs_efi_log_item_t *efip; 2933 struct xfs_efi_log_item *efip;
2934 xfs_efi_log_format_t *efi_formatp; 2934 struct xfs_efi_log_format *efi_formatp;
2935 2935
2936 efi_formatp = item->ri_buf[0].i_addr; 2936 efi_formatp = item->ri_buf[0].i_addr;
2937 2937
2938 efip = xfs_efi_init(mp, efi_formatp->efi_nextents); 2938 efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
2939 if ((error = xfs_efi_copy_format(&(item->ri_buf[0]), 2939 error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format);
2940 &(efip->efi_format)))) { 2940 if (error) {
2941 xfs_efi_item_free(efip); 2941 xfs_efi_item_free(efip);
2942 return error; 2942 return error;
2943 } 2943 }
@@ -2945,20 +2945,23 @@ xlog_recover_efi_pass2(
2945 2945
2946 spin_lock(&log->l_ailp->xa_lock); 2946 spin_lock(&log->l_ailp->xa_lock);
2947 /* 2947 /*
2948 * xfs_trans_ail_update() drops the AIL lock. 2948 * The EFI has two references. One for the EFD and one for EFI to ensure
2949 * it makes it into the AIL. Insert the EFI into the AIL directly and
2950 * drop the EFI reference. Note that xfs_trans_ail_update() drops the
2951 * AIL lock.
2949 */ 2952 */
2950 xfs_trans_ail_update(log->l_ailp, &efip->efi_item, lsn); 2953 xfs_trans_ail_update(log->l_ailp, &efip->efi_item, lsn);
2954 xfs_efi_release(efip);
2951 return 0; 2955 return 0;
2952} 2956}
2953 2957
2954 2958
2955/* 2959/*
2956 * This routine is called when an efd format structure is found in 2960 * This routine is called when an EFD format structure is found in a committed
2957 * a committed transaction in the log. It's purpose is to cancel 2961 * transaction in the log. Its purpose is to cancel the corresponding EFI if it
2958 * the corresponding efi if it was still in the log. To do this 2962 * was still in the log. To do this it searches the AIL for the EFI with an id
2959 * it searches the AIL for the efi with an id equal to that in the 2963 * equal to that in the EFD format structure. If we find it we drop the EFD
2960 * efd format structure. If we find it, we remove the efi from the 2964 * reference, which removes the EFI from the AIL and frees it.
2961 * AIL and free it.
2962 */ 2965 */
2963STATIC int 2966STATIC int
2964xlog_recover_efd_pass2( 2967xlog_recover_efd_pass2(
@@ -2980,8 +2983,8 @@ xlog_recover_efd_pass2(
2980 efi_id = efd_formatp->efd_efi_id; 2983 efi_id = efd_formatp->efd_efi_id;
2981 2984
2982 /* 2985 /*
2983 * Search for the efi with the id in the efd format structure 2986 * Search for the EFI with the id in the EFD format structure in the
2984 * in the AIL. 2987 * AIL.
2985 */ 2988 */
2986 spin_lock(&ailp->xa_lock); 2989 spin_lock(&ailp->xa_lock);
2987 lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); 2990 lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
@@ -2990,18 +2993,18 @@ xlog_recover_efd_pass2(
2990 efip = (xfs_efi_log_item_t *)lip; 2993 efip = (xfs_efi_log_item_t *)lip;
2991 if (efip->efi_format.efi_id == efi_id) { 2994 if (efip->efi_format.efi_id == efi_id) {
2992 /* 2995 /*
2993 * xfs_trans_ail_delete() drops the 2996 * Drop the EFD reference to the EFI. This
2994 * AIL lock. 2997 * removes the EFI from the AIL and frees it.
2995 */ 2998 */
2996 xfs_trans_ail_delete(ailp, lip, 2999 spin_unlock(&ailp->xa_lock);
2997 SHUTDOWN_CORRUPT_INCORE); 3000 xfs_efi_release(efip);
2998 xfs_efi_item_free(efip);
2999 spin_lock(&ailp->xa_lock); 3001 spin_lock(&ailp->xa_lock);
3000 break; 3002 break;
3001 } 3003 }
3002 } 3004 }
3003 lip = xfs_trans_ail_cursor_next(ailp, &cur); 3005 lip = xfs_trans_ail_cursor_next(ailp, &cur);
3004 } 3006 }
3007
3005 xfs_trans_ail_cursor_done(&cur); 3008 xfs_trans_ail_cursor_done(&cur);
3006 spin_unlock(&ailp->xa_lock); 3009 spin_unlock(&ailp->xa_lock);
3007 3010