aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2018-08-01 10:20:34 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-08-03 02:05:14 -0400
commit1ae093cbea3d1ef04e1344b9e3996a9e1763a91b (patch)
tree97ac8b95fb070cadc3f10df8dd1f5b82266a83dd /fs/xfs/libxfs
parent9b1f4e9831df29776031e86e112e68784f1fc079 (diff)
xfs: replace xfs_defer_ops ->dop_pending with on-stack list
The xfs_defer_ops ->dop_pending list is used to track active deferred operations once intents are logged. These items must be aborted in the event of an error. The list is populated as intents are logged and items are removed as they complete (or are aborted). Now that xfs_defer_finish() cancels on error, there is no need to ever access ->dop_pending outside of xfs_defer_finish(). The list is only ever populated after xfs_defer_finish() begins and is either completed or cancelled before it returns. Remove ->dop_pending from xfs_defer_ops and replace it with a local list in the xfs_defer_finish() path. Pass the local list to the various helpers now that it is not accessible via dfops. Note that we have to check for NULL in the abort case as the final tx roll occurs outside of the scope of the new local list (once the dfops has completed and thus drained the list). Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r--fs/xfs/libxfs/xfs_defer.c146
-rw-r--r--fs/xfs/libxfs/xfs_defer.h1
2 files changed, 68 insertions, 79 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. */