aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_extfree_item.c27
-rw-r--r--fs/xfs/xfs_extfree_item.h14
-rw-r--r--fs/xfs/xfs_log_recover.c1
3 files changed, 23 insertions, 19 deletions
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index feb36d7551ae..c0f375087efc 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -50,9 +50,8 @@ xfs_efi_item_free(
50 * Freeing the efi requires that we remove it from the AIL if it has already 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 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 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 53 * committed vs unpin operations in bulk insert operations. Hence the reference
54 * test_and_clear_bit(XFS_EFI_COMMITTED) to ensure only the last caller frees 54 * count to ensure only the last caller frees the EFI.
55 * the EFI.
56 */ 55 */
57STATIC void 56STATIC void
58__xfs_efi_release( 57__xfs_efi_release(
@@ -60,7 +59,7 @@ __xfs_efi_release(
60{ 59{
61 struct xfs_ail *ailp = efip->efi_item.li_ailp; 60 struct xfs_ail *ailp = efip->efi_item.li_ailp;
62 61
63 if (!test_and_clear_bit(XFS_EFI_COMMITTED, &efip->efi_flags)) { 62 if (atomic_dec_and_test(&efip->efi_refcount)) {
64 spin_lock(&ailp->xa_lock); 63 spin_lock(&ailp->xa_lock);
65 /* xfs_trans_ail_delete() drops the AIL lock. */ 64 /* xfs_trans_ail_delete() drops the AIL lock. */
66 xfs_trans_ail_delete(ailp, &efip->efi_item, 65 xfs_trans_ail_delete(ailp, &efip->efi_item,
@@ -126,8 +125,8 @@ xfs_efi_item_pin(
126 * which the EFI is manipulated during a transaction. If we are being asked to 125 * which the EFI is manipulated during a transaction. If we are being asked to
127 * remove the EFI it's because the transaction has been cancelled and by 126 * remove the EFI it's because the transaction has been cancelled and by
128 * definition that means the EFI cannot be in the AIL so remove it from the 127 * definition that means the EFI cannot be in the AIL so remove it from the
129 * transaction and free it. Otherwise coordinate with xfs_efi_release() (via 128 * transaction and free it. Otherwise coordinate with xfs_efi_release()
130 * XFS_EFI_COMMITTED) to determine who gets to free the EFI. 129 * to determine who gets to free the EFI.
131 */ 130 */
132STATIC void 131STATIC void
133xfs_efi_item_unpin( 132xfs_efi_item_unpin(
@@ -171,19 +170,13 @@ xfs_efi_item_unlock(
171 170
172/* 171/*
173 * The EFI is logged only once and cannot be moved in the log, so simply return 172 * The EFI is logged only once and cannot be moved in the log, so simply return
174 * the lsn at which it's been logged. For bulk transaction committed 173 * the lsn at which it's been logged.
175 * processing, the EFI may be processed but not yet unpinned prior to the EFD
176 * being processed. Set the XFS_EFI_COMMITTED flag so this case can be detected
177 * when processing the EFD.
178 */ 174 */
179STATIC xfs_lsn_t 175STATIC xfs_lsn_t
180xfs_efi_item_committed( 176xfs_efi_item_committed(
181 struct xfs_log_item *lip, 177 struct xfs_log_item *lip,
182 xfs_lsn_t lsn) 178 xfs_lsn_t lsn)
183{ 179{
184 struct xfs_efi_log_item *efip = EFI_ITEM(lip);
185
186 set_bit(XFS_EFI_COMMITTED, &efip->efi_flags);
187 return lsn; 180 return lsn;
188} 181}
189 182
@@ -241,6 +234,7 @@ xfs_efi_init(
241 efip->efi_format.efi_nextents = nextents; 234 efip->efi_format.efi_nextents = nextents;
242 efip->efi_format.efi_id = (__psint_t)(void*)efip; 235 efip->efi_format.efi_id = (__psint_t)(void*)efip;
243 atomic_set(&efip->efi_next_extent, 0); 236 atomic_set(&efip->efi_next_extent, 0);
237 atomic_set(&efip->efi_refcount, 2);
244 238
245 return efip; 239 return efip;
246} 240}
@@ -310,8 +304,13 @@ xfs_efi_release(xfs_efi_log_item_t *efip,
310 uint nextents) 304 uint nextents)
311{ 305{
312 ASSERT(atomic_read(&efip->efi_next_extent) >= nextents); 306 ASSERT(atomic_read(&efip->efi_next_extent) >= nextents);
313 if (atomic_sub_and_test(nextents, &efip->efi_next_extent)) 307 if (atomic_sub_and_test(nextents, &efip->efi_next_extent)) {
314 __xfs_efi_release(efip); 308 __xfs_efi_release(efip);
309
310 /* recovery needs us to drop the EFI reference, too */
311 if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags))
312 __xfs_efi_release(efip);
313 }
315} 314}
316 315
317static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip) 316static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip)
diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h
index 375f68e42531..432222418c56 100644
--- a/fs/xfs/xfs_extfree_item.h
+++ b/fs/xfs/xfs_extfree_item.h
@@ -114,16 +114,20 @@ typedef struct xfs_efd_log_format_64 {
114 * Define EFI flag bits. Manipulated by set/clear/test_bit operators. 114 * Define EFI flag bits. Manipulated by set/clear/test_bit operators.
115 */ 115 */
116#define XFS_EFI_RECOVERED 1 116#define XFS_EFI_RECOVERED 1
117#define XFS_EFI_COMMITTED 2
118 117
119/* 118/*
120 * This is the "extent free intention" log item. It is used 119 * This is the "extent free intention" log item. It is used to log the fact
121 * to log the fact that some extents need to be free. It is 120 * that some extents need to be free. It is used in conjunction with the
122 * used in conjunction with the "extent free done" log item 121 * "extent free done" log item described below.
123 * described below. 122 *
123 * The EFI is reference counted so that it is not freed prior to both the EFI
124 * and EFD being committed and unpinned. This ensures that when the last
125 * reference goes away the EFI will always be in the AIL as it has been
126 * unpinned, regardless of whether the EFD is processed before or after the EFI.
124 */ 127 */
125typedef struct xfs_efi_log_item { 128typedef struct xfs_efi_log_item {
126 xfs_log_item_t efi_item; 129 xfs_log_item_t efi_item;
130 atomic_t efi_refcount;
127 atomic_t efi_next_extent; 131 atomic_t efi_next_extent;
128 unsigned long efi_flags; /* misc flags */ 132 unsigned long efi_flags; /* misc flags */
129 xfs_efi_log_format_t efi_format; 133 xfs_efi_log_format_t efi_format;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index d1dba7ce75ae..3ca3380c3afe 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2948,6 +2948,7 @@ xlog_recover_process_efi(
2948 * This will pull the EFI from the AIL and 2948 * This will pull the EFI from the AIL and
2949 * free the memory associated with it. 2949 * free the memory associated with it.
2950 */ 2950 */
2951 set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
2951 xfs_efi_release(efip, efip->efi_format.efi_nextents); 2952 xfs_efi_release(efip, efip->efi_format.efi_nextents);
2952 return XFS_ERROR(EIO); 2953 return XFS_ERROR(EIO);
2953 } 2954 }