aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log_cil.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_log_cil.c')
-rw-r--r--fs/xfs/xfs_log_cil.c75
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
185next:
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 */