dm thin: fix noflush suspend IO queueing

i) by the time DM core calls the postsuspend hook the dm_noflush flag
has been cleared. So the old thin_postsuspend did nothing. We need to
use the presuspend hook instead.

ii) There was a race between bios leaving DM core and arriving in the
deferred queue.

thin_presuspend now sets a 'requeue' flag causing all bios destined for
that thin to be requeued back to DM core. Then it requeues all held IO,
and all IO on the deferred queue (destined for that thin). Finally
postsuspend clears the 'requeue' flag.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Joe Thornber and committed by
Mike Snitzer
738211f7 18adc577

+72 -2
+72 -2
drivers/md/dm-thin.c
··· 226 226 227 227 struct pool *pool; 228 228 struct dm_thin_device *td; 229 + bool requeue_mode:1; 229 230 }; 230 231 231 232 /*----------------------------------------------------------------*/ ··· 1380 1379 struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); 1381 1380 struct thin_c *tc = h->tc; 1382 1381 1382 + if (tc->requeue_mode) { 1383 + bio_endio(bio, DM_ENDIO_REQUEUE); 1384 + continue; 1385 + } 1386 + 1383 1387 /* 1384 1388 * If we've got no free new_mapping structs, and processing 1385 1389 * this bio might require one, we pause until there are some ··· 1447 1441 struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker); 1448 1442 wake_worker(pool); 1449 1443 queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD); 1444 + } 1445 + 1446 + /*----------------------------------------------------------------*/ 1447 + 1448 + struct noflush_work { 1449 + struct work_struct worker; 1450 + struct thin_c *tc; 1451 + 1452 + atomic_t complete; 1453 + wait_queue_head_t wait; 1454 + }; 1455 + 1456 + static void complete_noflush_work(struct noflush_work *w) 1457 + { 1458 + atomic_set(&w->complete, 1); 1459 + wake_up(&w->wait); 1460 + } 1461 + 1462 + static void do_noflush_start(struct work_struct *ws) 1463 + { 1464 + struct noflush_work *w = container_of(ws, struct noflush_work, worker); 1465 + w->tc->requeue_mode = true; 1466 + requeue_io(w->tc); 1467 + complete_noflush_work(w); 1468 + } 1469 + 1470 + static void do_noflush_stop(struct work_struct *ws) 1471 + { 1472 + struct noflush_work *w = container_of(ws, struct noflush_work, worker); 1473 + w->tc->requeue_mode = false; 1474 + complete_noflush_work(w); 1475 + } 1476 + 1477 + static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *)) 1478 + { 1479 + struct noflush_work w; 1480 + 1481 + INIT_WORK(&w.worker, fn); 1482 + w.tc = tc; 1483 + atomic_set(&w.complete, 0); 1484 + init_waitqueue_head(&w.wait); 1485 + 1486 + queue_work(tc->pool->wq, &w.worker); 1487 + 1488 + wait_event(w.wait, atomic_read(&w.complete)); 1450 1489 } 1451 1490 1452 1491 /*----------------------------------------------------------------*/ ··· 1666 1615 struct dm_cell_key key; 1667 1616 1668 1617 thin_hook_bio(tc, bio); 1618 + 1619 + if (tc->requeue_mode) { 1620 + bio_endio(bio, DM_ENDIO_REQUEUE); 1621 + return DM_MAPIO_SUBMITTED; 1622 + } 1669 1623 1670 1624 if (get_pool_mode(tc->pool) == PM_FAIL) { 1671 1625 bio_io_error(bio); ··· 3149 3093 return 0; 3150 3094 } 3151 3095 3096 + static void thin_presuspend(struct dm_target *ti) 3097 + { 3098 + struct thin_c *tc = ti->private; 3099 + 3100 + if (dm_noflush_suspending(ti)) 3101 + noflush_work(tc, do_noflush_start); 3102 + } 3103 + 3152 3104 static void thin_postsuspend(struct dm_target *ti) 3153 3105 { 3154 - if (dm_noflush_suspending(ti)) 3155 - requeue_io((struct thin_c *)ti->private); 3106 + struct thin_c *tc = ti->private; 3107 + 3108 + /* 3109 + * The dm_noflush_suspending flag has been cleared by now, so 3110 + * unfortunately we must always run this. 3111 + */ 3112 + noflush_work(tc, do_noflush_stop); 3156 3113 } 3157 3114 3158 3115 /* ··· 3256 3187 .dtr = thin_dtr, 3257 3188 .map = thin_map, 3258 3189 .end_io = thin_endio, 3190 + .presuspend = thin_presuspend, 3259 3191 .postsuspend = thin_postsuspend, 3260 3192 .status = thin_status, 3261 3193 .iterate_devices = thin_iterate_devices,