aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_defer.c146
-rw-r--r--fs/xfs/libxfs/xfs_defer.h1
-rw-r--r--fs/xfs/xfs_trace.h5
-rw-r--r--fs/xfs/xfs_trans.c2
-rw-r--r--fs/xfs/xfs_trans.h1
5 files changed, 71 insertions, 84 deletions
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
index b656a399cd71..1cbddcf539da 100644
--- a/fs/xfs/libxfs/xfs_defer.c
+++ b/fs/xfs/libxfs/xfs_defer.c
@@ -180,7 +180,7 @@ static const struct xfs_defer_op_type *defer_op_types[XFS_DEFER_OPS_TYPE_MAX];
180 * the pending list. 180 * the pending list.
181 */ 181 */
182STATIC void 182STATIC void
183xfs_defer_intake_work( 183xfs_defer_create_intents(
184 struct xfs_trans *tp) 184 struct xfs_trans *tp)
185{ 185{
186 struct xfs_defer_ops *dop = tp->t_dfops; 186 struct xfs_defer_ops *dop = tp->t_dfops;
@@ -190,21 +190,19 @@ xfs_defer_intake_work(
190 list_for_each_entry(dfp, &dop->dop_intake, dfp_list) { 190 list_for_each_entry(dfp, &dop->dop_intake, dfp_list) {
191 dfp->dfp_intent = dfp->dfp_type->create_intent(tp, 191 dfp->dfp_intent = dfp->dfp_type->create_intent(tp,
192 dfp->dfp_count); 192 dfp->dfp_count);
193 trace_xfs_defer_intake_work(tp->t_mountp, dfp); 193 trace_xfs_defer_create_intent(tp->t_mountp, dfp);
194 list_sort(tp->t_mountp, &dfp->dfp_work, 194 list_sort(tp->t_mountp, &dfp->dfp_work,
195 dfp->dfp_type->diff_items); 195 dfp->dfp_type->diff_items);
196 list_for_each(li, &dfp->dfp_work) 196 list_for_each(li, &dfp->dfp_work)
197 dfp->dfp_type->log_item(tp, dfp->dfp_intent, li); 197 dfp->dfp_type->log_item(tp, dfp->dfp_intent, li);
198 } 198 }
199
200 list_splice_tail_init(&dop->dop_intake, &dop->dop_pending);
201} 199}
202 200
203/* Abort all the intents that were committed. */ 201/* Abort all the intents that were committed. */
204STATIC void 202STATIC void
205xfs_defer_trans_abort( 203xfs_defer_trans_abort(
206 struct xfs_trans *tp, 204 struct xfs_trans *tp,
207 int error) 205 struct list_head *dop_pending)
208{ 206{
209 struct xfs_defer_ops *dop = tp->t_dfops; 207 struct xfs_defer_ops *dop = tp->t_dfops;
210 struct xfs_defer_pending *dfp; 208 struct xfs_defer_pending *dfp;
@@ -212,24 +210,21 @@ xfs_defer_trans_abort(
212 trace_xfs_defer_trans_abort(tp->t_mountp, dop, _RET_IP_); 210 trace_xfs_defer_trans_abort(tp->t_mountp, dop, _RET_IP_);
213 211
214 /* Abort intent items that don't have a done item. */ 212 /* Abort intent items that don't have a done item. */
215 list_for_each_entry(dfp, &dop->dop_pending, dfp_list) { 213 list_for_each_entry(dfp, dop_pending, dfp_list) {
216 trace_xfs_defer_pending_abort(tp->t_mountp, dfp); 214 trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
217 if (dfp->dfp_intent && !dfp->dfp_done) { 215 if (dfp->dfp_intent && !dfp->dfp_done) {
218 dfp->dfp_type->abort_intent(dfp->dfp_intent); 216 dfp->dfp_type->abort_intent(dfp->dfp_intent);
219 dfp->dfp_intent = NULL; 217 dfp->dfp_intent = NULL;
220 } 218 }
221 } 219 }
222
223 /* Shut down FS. */
224 xfs_force_shutdown(tp->t_mountp, (error == -EFSCORRUPTED) ?
225 SHUTDOWN_CORRUPT_INCORE : SHUTDOWN_META_IO_ERROR);
226} 220}
227 221
228/* Roll a transaction so we can do some deferred op processing. */ 222/* Roll a transaction so we can do some deferred op processing. */
229STATIC int 223STATIC int
230xfs_defer_trans_roll( 224xfs_defer_trans_roll(
231 struct xfs_trans **tp) 225 struct xfs_trans **tpp)
232{ 226{
227 struct xfs_trans *tp = *tpp;
233 struct xfs_buf_log_item *bli; 228 struct xfs_buf_log_item *bli;
234 struct xfs_inode_log_item *ili; 229 struct xfs_inode_log_item *ili;
235 struct xfs_log_item *lip; 230 struct xfs_log_item *lip;
@@ -239,7 +234,7 @@ xfs_defer_trans_roll(
239 int i; 234 int i;
240 int error; 235 int error;
241 236
242 list_for_each_entry(lip, &(*tp)->t_items, li_trans) { 237 list_for_each_entry(lip, &tp->t_items, li_trans) {
243 switch (lip->li_type) { 238 switch (lip->li_type) {
244 case XFS_LI_BUF: 239 case XFS_LI_BUF:
245 bli = container_of(lip, struct xfs_buf_log_item, 240 bli = container_of(lip, struct xfs_buf_log_item,
@@ -249,7 +244,7 @@ xfs_defer_trans_roll(
249 ASSERT(0); 244 ASSERT(0);
250 return -EFSCORRUPTED; 245 return -EFSCORRUPTED;
251 } 246 }
252 xfs_trans_dirty_buf(*tp, bli->bli_buf); 247 xfs_trans_dirty_buf(tp, bli->bli_buf);
253 bplist[bpcount++] = bli->bli_buf; 248 bplist[bpcount++] = bli->bli_buf;
254 } 249 }
255 break; 250 break;
@@ -261,7 +256,7 @@ xfs_defer_trans_roll(
261 ASSERT(0); 256 ASSERT(0);
262 return -EFSCORRUPTED; 257 return -EFSCORRUPTED;
263 } 258 }
264 xfs_trans_log_inode(*tp, ili->ili_inode, 259 xfs_trans_log_inode(tp, ili->ili_inode,
265 XFS_ILOG_CORE); 260 XFS_ILOG_CORE);
266 iplist[ipcount++] = ili->ili_inode; 261 iplist[ipcount++] = ili->ili_inode;
267 } 262 }
@@ -271,39 +266,30 @@ xfs_defer_trans_roll(
271 } 266 }
272 } 267 }
273 268
274 trace_xfs_defer_trans_roll((*tp)->t_mountp, (*tp)->t_dfops, _RET_IP_); 269 trace_xfs_defer_trans_roll(tp->t_mountp, tp->t_dfops, _RET_IP_);
275 270
276 /* Roll the transaction. */ 271 /* Roll the transaction. */
277 error = xfs_trans_roll(tp); 272 error = xfs_trans_roll(tpp);
273 tp = *tpp;
278 if (error) { 274 if (error) {
279 trace_xfs_defer_trans_roll_error((*tp)->t_mountp, 275 trace_xfs_defer_trans_roll_error(tp->t_mountp,
280 (*tp)->t_dfops, error); 276 tp->t_dfops, error);
281 xfs_defer_trans_abort(*tp, error);
282 return error; 277 return error;
283 } 278 }
284 279
285 /* Rejoin the joined inodes. */ 280 /* Rejoin the joined inodes. */
286 for (i = 0; i < ipcount; i++) 281 for (i = 0; i < ipcount; i++)
287 xfs_trans_ijoin(*tp, iplist[i], 0); 282 xfs_trans_ijoin(tp, iplist[i], 0);
288 283
289 /* Rejoin the buffers and dirty them so the log moves forward. */ 284 /* Rejoin the buffers and dirty them so the log moves forward. */
290 for (i = 0; i < bpcount; i++) { 285 for (i = 0; i < bpcount; i++) {
291 xfs_trans_bjoin(*tp, bplist[i]); 286 xfs_trans_bjoin(tp, bplist[i]);
292 xfs_trans_bhold(*tp, bplist[i]); 287 xfs_trans_bhold(tp, bplist[i]);
293 } 288 }
294 289
295 return error; 290 return error;
296} 291}
297 292
298/* Do we have any work items to finish? */
299bool
300xfs_defer_has_unfinished_work(
301 struct xfs_trans *tp)
302{
303 return !list_empty(&tp->t_dfops->dop_pending) ||
304 !list_empty(&tp->t_dfops->dop_intake);
305}
306
307/* 293/*
308 * Reset an already used dfops after finish. 294 * Reset an already used dfops after finish.
309 */ 295 */
@@ -311,7 +297,7 @@ static void
311xfs_defer_reset( 297xfs_defer_reset(
312 struct xfs_trans *tp) 298 struct xfs_trans *tp)
313{ 299{
314 ASSERT(!xfs_defer_has_unfinished_work(tp)); 300 ASSERT(list_empty(&tp->t_dfops->dop_intake));
315 301
316 /* 302 /*
317 * Low mode state transfers across transaction rolls to mirror dfops 303 * Low mode state transfers across transaction rolls to mirror dfops
@@ -321,6 +307,36 @@ xfs_defer_reset(
321} 307}
322 308
323/* 309/*
310 * Free up any items left in the list.
311 */
312static void
313xfs_defer_cancel_list(
314 struct xfs_mount *mp,
315 struct list_head *dop_list)
316{
317 struct xfs_defer_pending *dfp;
318 struct xfs_defer_pending *pli;
319 struct list_head *pwi;
320 struct list_head *n;
321
322 /*
323 * Free the pending items. Caller should already have arranged
324 * for the intent items to be released.
325 */
326 list_for_each_entry_safe(dfp, pli, dop_list, dfp_list) {
327 trace_xfs_defer_cancel_list(mp, dfp);
328 list_del(&dfp->dfp_list);
329 list_for_each_safe(pwi, n, &dfp->dfp_work) {
330 list_del(pwi);
331 dfp->dfp_count--;
332 dfp->dfp_type->cancel_item(pwi);
333 }
334 ASSERT(dfp->dfp_count == 0);
335 kmem_free(dfp);
336 }
337}
338
339/*
324 * Finish all the pending work. This involves logging intent items for 340 * Finish all the pending work. This involves logging intent items for
325 * any work items that wandered in since the last transaction roll (if 341 * any work items that wandered in since the last transaction roll (if
326 * one has even happened), rolling the transaction, and finishing the 342 * one has even happened), rolling the transaction, and finishing the
@@ -338,15 +354,19 @@ xfs_defer_finish_noroll(
338 void *state; 354 void *state;
339 int error = 0; 355 int error = 0;
340 void (*cleanup_fn)(struct xfs_trans *, void *, int); 356 void (*cleanup_fn)(struct xfs_trans *, void *, int);
357 LIST_HEAD(dop_pending);
341 358
342 ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); 359 ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
343 360
344 trace_xfs_defer_finish((*tp)->t_mountp, (*tp)->t_dfops, _RET_IP_); 361 trace_xfs_defer_finish((*tp)->t_mountp, (*tp)->t_dfops, _RET_IP_);
345 362
346 /* Until we run out of pending work to finish... */ 363 /* Until we run out of pending work to finish... */
347 while (xfs_defer_has_unfinished_work(*tp)) { 364 while (!list_empty(&dop_pending) ||
348 /* Log intents for work items sitting in the intake. */ 365 !list_empty(&(*tp)->t_dfops->dop_intake)) {
349 xfs_defer_intake_work(*tp); 366 /* log intents and pull in intake items */
367 xfs_defer_create_intents(*tp);
368 list_splice_tail_init(&(*tp)->t_dfops->dop_intake,
369 &dop_pending);
350 370
351 /* 371 /*
352 * Roll the transaction. 372 * Roll the transaction.
@@ -356,8 +376,8 @@ xfs_defer_finish_noroll(
356 goto out; 376 goto out;
357 377
358 /* Log an intent-done item for the first pending item. */ 378 /* Log an intent-done item for the first pending item. */
359 dfp = list_first_entry(&(*tp)->t_dfops->dop_pending, 379 dfp = list_first_entry(&dop_pending, struct xfs_defer_pending,
360 struct xfs_defer_pending, dfp_list); 380 dfp_list);
361 trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp); 381 trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp);
362 dfp->dfp_done = dfp->dfp_type->create_done(*tp, dfp->dfp_intent, 382 dfp->dfp_done = dfp->dfp_type->create_done(*tp, dfp->dfp_intent,
363 dfp->dfp_count); 383 dfp->dfp_count);
@@ -387,7 +407,6 @@ xfs_defer_finish_noroll(
387 */ 407 */
388 if (cleanup_fn) 408 if (cleanup_fn)
389 cleanup_fn(*tp, state, error); 409 cleanup_fn(*tp, state, error);
390 xfs_defer_trans_abort(*tp, error);
391 goto out; 410 goto out;
392 } 411 }
393 } 412 }
@@ -417,8 +436,11 @@ xfs_defer_finish_noroll(
417 436
418out: 437out:
419 if (error) { 438 if (error) {
439 xfs_defer_trans_abort(*tp, &dop_pending);
440 xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE);
420 trace_xfs_defer_finish_error((*tp)->t_mountp, (*tp)->t_dfops, 441 trace_xfs_defer_finish_error((*tp)->t_mountp, (*tp)->t_dfops,
421 error); 442 error);
443 xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending);
422 xfs_defer_cancel(*tp); 444 xfs_defer_cancel(*tp);
423 return error; 445 return error;
424 } 446 }
@@ -442,54 +464,24 @@ xfs_defer_finish(
442 return error; 464 return error;
443 if ((*tp)->t_flags & XFS_TRANS_DIRTY) { 465 if ((*tp)->t_flags & XFS_TRANS_DIRTY) {
444 error = xfs_defer_trans_roll(tp); 466 error = xfs_defer_trans_roll(tp);
445 if (error) 467 if (error) {
468 xfs_force_shutdown((*tp)->t_mountp,
469 SHUTDOWN_CORRUPT_INCORE);
446 return error; 470 return error;
471 }
447 } 472 }
448 xfs_defer_reset(*tp); 473 xfs_defer_reset(*tp);
449 return 0; 474 return 0;
450} 475}
451 476
452/*
453 * Free up any items left in the list.
454 */
455void 477void
456xfs_defer_cancel( 478xfs_defer_cancel(
457 struct xfs_trans *tp) 479 struct xfs_trans *tp)
458{ 480{
459 struct xfs_defer_ops *dop = tp->t_dfops; 481 struct xfs_mount *mp = tp->t_mountp;
460 struct xfs_defer_pending *dfp;
461 struct xfs_defer_pending *pli;
462 struct list_head *pwi;
463 struct list_head *n;
464 482
465 trace_xfs_defer_cancel(NULL, dop, _RET_IP_); 483 trace_xfs_defer_cancel(mp, tp->t_dfops, _RET_IP_);
466 484 xfs_defer_cancel_list(mp, &tp->t_dfops->dop_intake);
467 /*
468 * Free the pending items. Caller should already have arranged
469 * for the intent items to be released.
470 */
471 list_for_each_entry_safe(dfp, pli, &dop->dop_intake, dfp_list) {
472 trace_xfs_defer_intake_cancel(NULL, dfp);
473 list_del(&dfp->dfp_list);
474 list_for_each_safe(pwi, n, &dfp->dfp_work) {
475 list_del(pwi);
476 dfp->dfp_count--;
477 dfp->dfp_type->cancel_item(pwi);
478 }
479 ASSERT(dfp->dfp_count == 0);
480 kmem_free(dfp);
481 }
482 list_for_each_entry_safe(dfp, pli, &dop->dop_pending, dfp_list) {
483 trace_xfs_defer_pending_cancel(NULL, dfp);
484 list_del(&dfp->dfp_list);
485 list_for_each_safe(pwi, n, &dfp->dfp_work) {
486 list_del(pwi);
487 dfp->dfp_count--;
488 dfp->dfp_type->cancel_item(pwi);
489 }
490 ASSERT(dfp->dfp_count == 0);
491 kmem_free(dfp);
492 }
493} 485}
494 486
495/* Add an item for later deferred processing. */ 487/* Add an item for later deferred processing. */
@@ -547,7 +539,6 @@ xfs_defer_init(
547 539
548 memset(dop, 0, sizeof(struct xfs_defer_ops)); 540 memset(dop, 0, sizeof(struct xfs_defer_ops));
549 INIT_LIST_HEAD(&dop->dop_intake); 541 INIT_LIST_HEAD(&dop->dop_intake);
550 INIT_LIST_HEAD(&dop->dop_pending);
551 if (tp) { 542 if (tp) {
552 ASSERT(tp->t_firstblock == NULLFSBLOCK); 543 ASSERT(tp->t_firstblock == NULLFSBLOCK);
553 tp->t_dfops = dop; 544 tp->t_dfops = dop;
@@ -571,7 +562,6 @@ xfs_defer_move(
571 ASSERT(dst != src); 562 ASSERT(dst != src);
572 563
573 list_splice_init(&src->dop_intake, &dst->dop_intake); 564 list_splice_init(&src->dop_intake, &dst->dop_intake);
574 list_splice_init(&src->dop_pending, &dst->dop_pending);
575 565
576 /* 566 /*
577 * Low free space mode was historically controlled by a dfops field. 567 * Low free space mode was historically controlled by a dfops field.
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index f051c8056141..f091bf3abeaf 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/libxfs/xfs_defer.h
@@ -41,7 +41,6 @@ int xfs_defer_finish_noroll(struct xfs_trans **tp);
41int xfs_defer_finish(struct xfs_trans **tp); 41int xfs_defer_finish(struct xfs_trans **tp);
42void xfs_defer_cancel(struct xfs_trans *); 42void xfs_defer_cancel(struct xfs_trans *);
43void xfs_defer_init(struct xfs_trans *tp, struct xfs_defer_ops *dop); 43void xfs_defer_init(struct xfs_trans *tp, struct xfs_defer_ops *dop);
44bool xfs_defer_has_unfinished_work(struct xfs_trans *tp);
45void xfs_defer_move(struct xfs_trans *dtp, struct xfs_trans *stp); 44void xfs_defer_move(struct xfs_trans *dtp, struct xfs_trans *stp);
46 45
47/* Description of a deferred type. */ 46/* Description of a deferred type. */
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 8807f1bb814a..fec9cfe3dfb4 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2392,9 +2392,8 @@ DEFINE_DEFER_EVENT(xfs_defer_finish_done);
2392DEFINE_DEFER_ERROR_EVENT(xfs_defer_trans_roll_error); 2392DEFINE_DEFER_ERROR_EVENT(xfs_defer_trans_roll_error);
2393DEFINE_DEFER_ERROR_EVENT(xfs_defer_finish_error); 2393DEFINE_DEFER_ERROR_EVENT(xfs_defer_finish_error);
2394 2394
2395DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_work); 2395DEFINE_DEFER_PENDING_EVENT(xfs_defer_create_intent);
2396DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_cancel); 2396DEFINE_DEFER_PENDING_EVENT(xfs_defer_cancel_list);
2397DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_cancel);
2398DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish); 2397DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish);
2399DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort); 2398DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort);
2400 2399
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index b050663c2a70..413e4138357f 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -929,7 +929,7 @@ __xfs_trans_commit(
929 * Finish deferred items on final commit. Only permanent transactions 929 * Finish deferred items on final commit. Only permanent transactions
930 * should ever have deferred ops. 930 * should ever have deferred ops.
931 */ 931 */
932 WARN_ON_ONCE(xfs_defer_has_unfinished_work(tp) && 932 WARN_ON_ONCE(!list_empty(&tp->t_dfops->dop_intake) &&
933 !(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); 933 !(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
934 if (!regrant && (tp->t_flags & XFS_TRANS_PERM_LOG_RES)) { 934 if (!regrant && (tp->t_flags & XFS_TRANS_PERM_LOG_RES)) {
935 error = xfs_defer_finish_noroll(&tp); 935 error = xfs_defer_finish_noroll(&tp);
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 299656dbf324..1cdc7c0ebeac 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -96,7 +96,6 @@ void xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *item,
96#define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */ 96#define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */
97struct xfs_defer_ops { 97struct xfs_defer_ops {
98 struct list_head dop_intake; /* unlogged pending work */ 98 struct list_head dop_intake; /* unlogged pending work */
99 struct list_head dop_pending; /* logged pending work */
100}; 99};
101 100
102/* 101/*