diff options
Diffstat (limited to 'fs/xfs/xfs_log_cil.c')
-rw-r--r-- | fs/xfs/xfs_log_cil.c | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index d0833b54e55d..02b9cf3f8252 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c | |||
@@ -127,6 +127,7 @@ xlog_cil_prepare_log_vecs( | |||
127 | int index; | 127 | int index; |
128 | int len = 0; | 128 | int len = 0; |
129 | uint niovecs; | 129 | uint niovecs; |
130 | bool ordered = false; | ||
130 | 131 | ||
131 | /* Skip items which aren't dirty in this transaction. */ | 132 | /* Skip items which aren't dirty in this transaction. */ |
132 | if (!(lidp->lid_flags & XFS_LID_DIRTY)) | 133 | if (!(lidp->lid_flags & XFS_LID_DIRTY)) |
@@ -137,14 +138,30 @@ xlog_cil_prepare_log_vecs( | |||
137 | if (!niovecs) | 138 | if (!niovecs) |
138 | continue; | 139 | continue; |
139 | 140 | ||
141 | /* | ||
142 | * Ordered items need to be tracked but we do not wish to write | ||
143 | * them. We need a logvec to track the object, but we do not | ||
144 | * need an iovec or buffer to be allocated for copying data. | ||
145 | */ | ||
146 | if (niovecs == XFS_LOG_VEC_ORDERED) { | ||
147 | ordered = true; | ||
148 | niovecs = 0; | ||
149 | } | ||
150 | |||
140 | new_lv = kmem_zalloc(sizeof(*new_lv) + | 151 | new_lv = kmem_zalloc(sizeof(*new_lv) + |
141 | niovecs * sizeof(struct xfs_log_iovec), | 152 | niovecs * sizeof(struct xfs_log_iovec), |
142 | KM_SLEEP|KM_NOFS); | 153 | KM_SLEEP|KM_NOFS); |
143 | 154 | ||
155 | new_lv->lv_item = lidp->lid_item; | ||
156 | new_lv->lv_niovecs = niovecs; | ||
157 | if (ordered) { | ||
158 | /* track as an ordered logvec */ | ||
159 | new_lv->lv_buf_len = XFS_LOG_VEC_ORDERED; | ||
160 | goto next; | ||
161 | } | ||
162 | |||
144 | /* The allocated iovec region lies beyond the log vector. */ | 163 | /* The allocated iovec region lies beyond the log vector. */ |
145 | new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1]; | 164 | new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1]; |
146 | new_lv->lv_niovecs = niovecs; | ||
147 | new_lv->lv_item = lidp->lid_item; | ||
148 | 165 | ||
149 | /* build the vector array and calculate it's length */ | 166 | /* build the vector array and calculate it's length */ |
150 | IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp); | 167 | IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp); |
@@ -165,6 +182,7 @@ xlog_cil_prepare_log_vecs( | |||
165 | } | 182 | } |
166 | ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len); | 183 | ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len); |
167 | 184 | ||
185 | next: | ||
168 | if (!ret_lv) | 186 | if (!ret_lv) |
169 | ret_lv = new_lv; | 187 | ret_lv = new_lv; |
170 | else | 188 | else |
@@ -191,8 +209,18 @@ xfs_cil_prepare_item( | |||
191 | 209 | ||
192 | if (old) { | 210 | if (old) { |
193 | /* existing lv on log item, space used is a delta */ | 211 | /* existing lv on log item, space used is a delta */ |
194 | ASSERT(!list_empty(&lv->lv_item->li_cil)); | 212 | ASSERT((old->lv_buf && old->lv_buf_len && old->lv_niovecs) || |
195 | ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs); | 213 | old->lv_buf_len == XFS_LOG_VEC_ORDERED); |
214 | |||
215 | /* | ||
216 | * If the new item is ordered, keep the old one that is already | ||
217 | * tracking dirty or ordered regions | ||
218 | */ | ||
219 | if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED) { | ||
220 | ASSERT(!lv->lv_buf); | ||
221 | kmem_free(lv); | ||
222 | return; | ||
223 | } | ||
196 | 224 | ||
197 | *len += lv->lv_buf_len - old->lv_buf_len; | 225 | *len += lv->lv_buf_len - old->lv_buf_len; |
198 | *diff_iovecs += lv->lv_niovecs - old->lv_niovecs; | 226 | *diff_iovecs += lv->lv_niovecs - old->lv_niovecs; |
@@ -201,10 +229,11 @@ xfs_cil_prepare_item( | |||
201 | } else { | 229 | } else { |
202 | /* new lv, must pin the log item */ | 230 | /* new lv, must pin the log item */ |
203 | ASSERT(!lv->lv_item->li_lv); | 231 | ASSERT(!lv->lv_item->li_lv); |
204 | ASSERT(list_empty(&lv->lv_item->li_cil)); | ||
205 | 232 | ||
206 | *len += lv->lv_buf_len; | 233 | if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { |
207 | *diff_iovecs += lv->lv_niovecs; | 234 | *len += lv->lv_buf_len; |
235 | *diff_iovecs += lv->lv_niovecs; | ||
236 | } | ||
208 | IOP_PIN(lv->lv_item); | 237 | IOP_PIN(lv->lv_item); |
209 | 238 | ||
210 | } | 239 | } |
@@ -259,18 +288,24 @@ xlog_cil_insert_items( | |||
259 | * We can do this safely because the context can't checkpoint until we | 288 | * We can do this safely because the context can't checkpoint until we |
260 | * are done so it doesn't matter exactly how we update the CIL. | 289 | * are done so it doesn't matter exactly how we update the CIL. |
261 | */ | 290 | */ |
262 | for (lv = log_vector; lv; lv = lv->lv_next) | ||
263 | xfs_cil_prepare_item(log, lv, &len, &diff_iovecs); | ||
264 | |||
265 | /* account for space used by new iovec headers */ | ||
266 | len += diff_iovecs * sizeof(xlog_op_header_t); | ||
267 | |||
268 | spin_lock(&cil->xc_cil_lock); | 291 | spin_lock(&cil->xc_cil_lock); |
292 | for (lv = log_vector; lv; ) { | ||
293 | struct xfs_log_vec *next = lv->lv_next; | ||
269 | 294 | ||
270 | /* move the items to the tail of the CIL */ | 295 | ASSERT(lv->lv_item->li_lv || list_empty(&lv->lv_item->li_cil)); |
271 | for (lv = log_vector; lv; lv = lv->lv_next) | 296 | lv->lv_next = NULL; |
297 | |||
298 | /* | ||
299 | * xfs_cil_prepare_item() may free the lv, so move the item on | ||
300 | * the CIL first. | ||
301 | */ | ||
272 | list_move_tail(&lv->lv_item->li_cil, &cil->xc_cil); | 302 | list_move_tail(&lv->lv_item->li_cil, &cil->xc_cil); |
303 | xfs_cil_prepare_item(log, lv, &len, &diff_iovecs); | ||
304 | lv = next; | ||
305 | } | ||
273 | 306 | ||
307 | /* account for space used by new iovec headers */ | ||
308 | len += diff_iovecs * sizeof(xlog_op_header_t); | ||
274 | ctx->nvecs += diff_iovecs; | 309 | ctx->nvecs += diff_iovecs; |
275 | 310 | ||
276 | /* | 311 | /* |
@@ -381,9 +416,7 @@ xlog_cil_push( | |||
381 | struct xfs_cil_ctx *new_ctx; | 416 | struct xfs_cil_ctx *new_ctx; |
382 | struct xlog_in_core *commit_iclog; | 417 | struct xlog_in_core *commit_iclog; |
383 | struct xlog_ticket *tic; | 418 | struct xlog_ticket *tic; |
384 | int num_lv; | ||
385 | int num_iovecs; | 419 | int num_iovecs; |
386 | int len; | ||
387 | int error = 0; | 420 | int error = 0; |
388 | struct xfs_trans_header thdr; | 421 | struct xfs_trans_header thdr; |
389 | struct xfs_log_iovec lhdr; | 422 | struct xfs_log_iovec lhdr; |
@@ -428,12 +461,9 @@ xlog_cil_push( | |||
428 | * side which is currently locked out by the flush lock. | 461 | * side which is currently locked out by the flush lock. |
429 | */ | 462 | */ |
430 | lv = NULL; | 463 | lv = NULL; |
431 | num_lv = 0; | ||
432 | num_iovecs = 0; | 464 | num_iovecs = 0; |
433 | len = 0; | ||
434 | while (!list_empty(&cil->xc_cil)) { | 465 | while (!list_empty(&cil->xc_cil)) { |
435 | struct xfs_log_item *item; | 466 | struct xfs_log_item *item; |
436 | int i; | ||
437 | 467 | ||
438 | item = list_first_entry(&cil->xc_cil, | 468 | item = list_first_entry(&cil->xc_cil, |
439 | struct xfs_log_item, li_cil); | 469 | struct xfs_log_item, li_cil); |
@@ -444,11 +474,7 @@ xlog_cil_push( | |||
444 | lv->lv_next = item->li_lv; | 474 | lv->lv_next = item->li_lv; |
445 | lv = item->li_lv; | 475 | lv = item->li_lv; |
446 | item->li_lv = NULL; | 476 | item->li_lv = NULL; |
447 | |||
448 | num_lv++; | ||
449 | num_iovecs += lv->lv_niovecs; | 477 | num_iovecs += lv->lv_niovecs; |
450 | for (i = 0; i < lv->lv_niovecs; i++) | ||
451 | len += lv->lv_iovecp[i].i_len; | ||
452 | } | 478 | } |
453 | 479 | ||
454 | /* | 480 | /* |
@@ -701,6 +727,7 @@ xfs_log_commit_cil( | |||
701 | if (commit_lsn) | 727 | if (commit_lsn) |
702 | *commit_lsn = log->l_cilp->xc_ctx->sequence; | 728 | *commit_lsn = log->l_cilp->xc_ctx->sequence; |
703 | 729 | ||
730 | /* xlog_cil_insert_items() destroys log_vector list */ | ||
704 | xlog_cil_insert_items(log, log_vector, tp->t_ticket); | 731 | xlog_cil_insert_items(log, log_vector, tp->t_ticket); |
705 | 732 | ||
706 | /* check we didn't blow the reservation */ | 733 | /* check we didn't blow the reservation */ |