aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_extfree_item.c81
-rw-r--r--fs/xfs/xfs_extfree_item.h10
-rw-r--r--fs/xfs/xfs_log_recover.c9
-rw-r--r--fs/xfs/xfs_trans_extfree.c8
4 files changed, 59 insertions, 49 deletions
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 5997efae05dc..75f2ef60e579 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -48,6 +48,28 @@ xfs_efi_item_free(
48} 48}
49 49
50/* 50/*
51 * Freeing the efi requires that we remove it from the AIL if it has already
52 * been placed there. However, the EFI may not yet have been placed in the AIL
53 * when called by xfs_efi_release() from EFD processing due to the ordering of
54 * committed vs unpin operations in bulk insert operations. Hence the
55 * test_and_clear_bit(XFS_EFI_COMMITTED) to ensure only the last caller frees
56 * the EFI.
57 */
58STATIC void
59__xfs_efi_release(
60 struct xfs_efi_log_item *efip)
61{
62 struct xfs_ail *ailp = efip->efi_item.li_ailp;
63
64 if (!test_and_clear_bit(XFS_EFI_COMMITTED, &efip->efi_flags)) {
65 spin_lock(&ailp->xa_lock);
66 /* xfs_trans_ail_delete() drops the AIL lock. */
67 xfs_trans_ail_delete(ailp, &efip->efi_item);
68 xfs_efi_item_free(efip);
69 }
70}
71
72/*
51 * This returns the number of iovecs needed to log the given efi item. 73 * This returns the number of iovecs needed to log the given efi item.
52 * We only need 1 iovec for an efi item. It just logs the efi_log_format 74 * We only need 1 iovec for an efi item. It just logs the efi_log_format
53 * structure. 75 * structure.
@@ -74,7 +96,8 @@ xfs_efi_item_format(
74 struct xfs_efi_log_item *efip = EFI_ITEM(lip); 96 struct xfs_efi_log_item *efip = EFI_ITEM(lip);
75 uint size; 97 uint size;
76 98
77 ASSERT(efip->efi_next_extent == efip->efi_format.efi_nextents); 99 ASSERT(atomic_read(&efip->efi_next_extent) ==
100 efip->efi_format.efi_nextents);
78 101
79 efip->efi_format.efi_type = XFS_LI_EFI; 102 efip->efi_format.efi_type = XFS_LI_EFI;
80 103
@@ -103,7 +126,8 @@ xfs_efi_item_pin(
103 * which the EFI is manipulated during a transaction. If we are being asked to 126 * which the EFI is manipulated during a transaction. If we are being asked to
104 * remove the EFI it's because the transaction has been cancelled and by 127 * remove the EFI it's because the transaction has been cancelled and by
105 * definition that means the EFI cannot be in the AIL so remove it from the 128 * definition that means the EFI cannot be in the AIL so remove it from the
106 * transaction and free it. 129 * transaction and free it. Otherwise coordinate with xfs_efi_release() (via
130 * XFS_EFI_COMMITTED) to determine who gets to free the EFI.
107 */ 131 */
108STATIC void 132STATIC void
109xfs_efi_item_unpin( 133xfs_efi_item_unpin(
@@ -111,17 +135,14 @@ xfs_efi_item_unpin(
111 int remove) 135 int remove)
112{ 136{
113 struct xfs_efi_log_item *efip = EFI_ITEM(lip); 137 struct xfs_efi_log_item *efip = EFI_ITEM(lip);
114 struct xfs_ail *ailp = lip->li_ailp;
115 138
116 spin_lock(&ailp->xa_lock);
117 if (remove) { 139 if (remove) {
118 ASSERT(!(lip->li_flags & XFS_LI_IN_AIL)); 140 ASSERT(!(lip->li_flags & XFS_LI_IN_AIL));
119 xfs_trans_del_item(lip); 141 xfs_trans_del_item(lip);
120 xfs_efi_item_free(efip); 142 xfs_efi_item_free(efip);
121 } else { 143 return;
122 efip->efi_flags |= XFS_EFI_COMMITTED;
123 } 144 }
124 spin_unlock(&ailp->xa_lock); 145 __xfs_efi_release(efip);
125} 146}
126 147
127/* 148/*
@@ -150,16 +171,20 @@ xfs_efi_item_unlock(
150} 171}
151 172
152/* 173/*
153 * The EFI is logged only once and cannot be moved in the log, so 174 * The EFI is logged only once and cannot be moved in the log, so simply return
154 * simply return the lsn at which it's been logged. The canceled 175 * the lsn at which it's been logged. For bulk transaction committed
155 * flag is not paid any attention here. Checking for that is delayed 176 * processing, the EFI may be processed but not yet unpinned prior to the EFD
156 * until the EFI is unpinned. 177 * being processed. Set the XFS_EFI_COMMITTED flag so this case can be detected
178 * when processing the EFD.
157 */ 179 */
158STATIC xfs_lsn_t 180STATIC xfs_lsn_t
159xfs_efi_item_committed( 181xfs_efi_item_committed(
160 struct xfs_log_item *lip, 182 struct xfs_log_item *lip,
161 xfs_lsn_t lsn) 183 xfs_lsn_t lsn)
162{ 184{
185 struct xfs_efi_log_item *efip = EFI_ITEM(lip);
186
187 set_bit(XFS_EFI_COMMITTED, &efip->efi_flags);
163 return lsn; 188 return lsn;
164} 189}
165 190
@@ -228,6 +253,7 @@ xfs_efi_init(
228 xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops); 253 xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops);
229 efip->efi_format.efi_nextents = nextents; 254 efip->efi_format.efi_nextents = nextents;
230 efip->efi_format.efi_id = (__psint_t)(void*)efip; 255 efip->efi_format.efi_id = (__psint_t)(void*)efip;
256 atomic_set(&efip->efi_next_extent, 0);
231 257
232 return efip; 258 return efip;
233} 259}
@@ -287,37 +313,18 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
287} 313}
288 314
289/* 315/*
290 * This is called by the efd item code below to release references to 316 * This is called by the efd item code below to release references to the given
291 * the given efi item. Each efd calls this with the number of 317 * efi item. Each efd calls this with the number of extents that it has
292 * extents that it has logged, and when the sum of these reaches 318 * logged, and when the sum of these reaches the total number of extents logged
293 * the total number of extents logged by this efi item we can free 319 * by this efi item we can free the efi item.
294 * the efi item.
295 *
296 * Freeing the efi item requires that we remove it from the AIL.
297 * We'll use the AIL lock to protect our counters as well as
298 * the removal from the AIL.
299 */ 320 */
300void 321void
301xfs_efi_release(xfs_efi_log_item_t *efip, 322xfs_efi_release(xfs_efi_log_item_t *efip,
302 uint nextents) 323 uint nextents)
303{ 324{
304 struct xfs_ail *ailp = efip->efi_item.li_ailp; 325 ASSERT(atomic_read(&efip->efi_next_extent) >= nextents);
305 int extents_left; 326 if (atomic_sub_and_test(nextents, &efip->efi_next_extent))
306 327 __xfs_efi_release(efip);
307 ASSERT(efip->efi_next_extent > 0);
308 ASSERT(efip->efi_flags & XFS_EFI_COMMITTED);
309
310 spin_lock(&ailp->xa_lock);
311 ASSERT(efip->efi_next_extent >= nextents);
312 efip->efi_next_extent -= nextents;
313 extents_left = efip->efi_next_extent;
314 if (extents_left == 0) {
315 /* xfs_trans_ail_delete() drops the AIL lock. */
316 xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
317 xfs_efi_item_free(efip);
318 } else {
319 spin_unlock(&ailp->xa_lock);
320 }
321} 328}
322 329
323static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip) 330static 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 f7834ec8efad..375f68e42531 100644
--- a/fs/xfs/xfs_extfree_item.h
+++ b/fs/xfs/xfs_extfree_item.h
@@ -111,10 +111,10 @@ typedef struct xfs_efd_log_format_64 {
111#define XFS_EFI_MAX_FAST_EXTENTS 16 111#define XFS_EFI_MAX_FAST_EXTENTS 16
112 112
113/* 113/*
114 * Define EFI flags. 114 * Define EFI flag bits. Manipulated by set/clear/test_bit operators.
115 */ 115 */
116#define XFS_EFI_RECOVERED 0x1 116#define XFS_EFI_RECOVERED 1
117#define XFS_EFI_COMMITTED 0x2 117#define XFS_EFI_COMMITTED 2
118 118
119/* 119/*
120 * This is the "extent free intention" log item. It is used 120 * This is the "extent free intention" log item. It is used
@@ -124,8 +124,8 @@ typedef struct xfs_efd_log_format_64 {
124 */ 124 */
125typedef struct xfs_efi_log_item { 125typedef struct xfs_efi_log_item {
126 xfs_log_item_t efi_item; 126 xfs_log_item_t efi_item;
127 uint efi_flags; /* misc flags */ 127 atomic_t efi_next_extent;
128 uint efi_next_extent; 128 unsigned long efi_flags; /* misc flags */
129 xfs_efi_log_format_t efi_format; 129 xfs_efi_log_format_t efi_format;
130} xfs_efi_log_item_t; 130} xfs_efi_log_item_t;
131 131
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 4ab4f6ff48aa..d7219e29d9ab 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2567,8 +2567,7 @@ xlog_recover_efi_pass2(
2567 xfs_efi_item_free(efip); 2567 xfs_efi_item_free(efip);
2568 return error; 2568 return error;
2569 } 2569 }
2570 efip->efi_next_extent = efi_formatp->efi_nextents; 2570 atomic_set(&efip->efi_next_extent, efi_formatp->efi_nextents);
2571 efip->efi_flags |= XFS_EFI_COMMITTED;
2572 2571
2573 spin_lock(&log->l_ailp->xa_lock); 2572 spin_lock(&log->l_ailp->xa_lock);
2574 /* 2573 /*
@@ -2878,7 +2877,7 @@ xlog_recover_process_efi(
2878 xfs_extent_t *extp; 2877 xfs_extent_t *extp;
2879 xfs_fsblock_t startblock_fsb; 2878 xfs_fsblock_t startblock_fsb;
2880 2879
2881 ASSERT(!(efip->efi_flags & XFS_EFI_RECOVERED)); 2880 ASSERT(!test_bit(XFS_EFI_RECOVERED, &efip->efi_flags));
2882 2881
2883 /* 2882 /*
2884 * First check the validity of the extents described by the 2883 * First check the validity of the extents described by the
@@ -2917,7 +2916,7 @@ xlog_recover_process_efi(
2917 extp->ext_len); 2916 extp->ext_len);
2918 } 2917 }
2919 2918
2920 efip->efi_flags |= XFS_EFI_RECOVERED; 2919 set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
2921 error = xfs_trans_commit(tp, 0); 2920 error = xfs_trans_commit(tp, 0);
2922 return error; 2921 return error;
2923 2922
@@ -2974,7 +2973,7 @@ xlog_recover_process_efis(
2974 * Skip EFIs that we've already processed. 2973 * Skip EFIs that we've already processed.
2975 */ 2974 */
2976 efip = (xfs_efi_log_item_t *)lip; 2975 efip = (xfs_efi_log_item_t *)lip;
2977 if (efip->efi_flags & XFS_EFI_RECOVERED) { 2976 if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) {
2978 lip = xfs_trans_ail_cursor_next(ailp, &cur); 2977 lip = xfs_trans_ail_cursor_next(ailp, &cur);
2979 continue; 2978 continue;
2980 } 2979 }
diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c
index f783d5e9fa70..f7590f5badea 100644
--- a/fs/xfs/xfs_trans_extfree.c
+++ b/fs/xfs/xfs_trans_extfree.c
@@ -69,12 +69,16 @@ xfs_trans_log_efi_extent(xfs_trans_t *tp,
69 tp->t_flags |= XFS_TRANS_DIRTY; 69 tp->t_flags |= XFS_TRANS_DIRTY;
70 efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY; 70 efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
71 71
72 next_extent = efip->efi_next_extent; 72 /*
73 * atomic_inc_return gives us the value after the increment;
74 * we want to use it as an array index so we need to subtract 1 from
75 * it.
76 */
77 next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
73 ASSERT(next_extent < efip->efi_format.efi_nextents); 78 ASSERT(next_extent < efip->efi_format.efi_nextents);
74 extp = &(efip->efi_format.efi_extents[next_extent]); 79 extp = &(efip->efi_format.efi_extents[next_extent]);
75 extp->ext_start = start_block; 80 extp->ext_start = start_block;
76 extp->ext_len = ext_len; 81 extp->ext_len = ext_len;
77 efip->efi_next_extent++;
78} 82}
79 83
80 84