diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index dce971dbdfa3..e81345a1d08f 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -93,6 +93,10 @@ struct multipath { | |||
93 | * can resubmit bios on error. | 93 | * can resubmit bios on error. |
94 | */ | 94 | */ |
95 | mempool_t *mpio_pool; | 95 | mempool_t *mpio_pool; |
96 | |||
97 | struct mutex work_mutex; | ||
98 | |||
99 | unsigned suspended; /* Don't create new I/O internally when set. */ | ||
96 | }; | 100 | }; |
97 | 101 | ||
98 | /* | 102 | /* |
@@ -198,6 +202,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) | |||
198 | m->queue_io = 1; | 202 | m->queue_io = 1; |
199 | INIT_WORK(&m->process_queued_ios, process_queued_ios); | 203 | INIT_WORK(&m->process_queued_ios, process_queued_ios); |
200 | INIT_WORK(&m->trigger_event, trigger_event); | 204 | INIT_WORK(&m->trigger_event, trigger_event); |
205 | mutex_init(&m->work_mutex); | ||
201 | m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); | 206 | m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); |
202 | if (!m->mpio_pool) { | 207 | if (!m->mpio_pool) { |
203 | kfree(m); | 208 | kfree(m); |
@@ -885,13 +890,18 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
885 | return r; | 890 | return r; |
886 | } | 891 | } |
887 | 892 | ||
888 | static void multipath_dtr(struct dm_target *ti) | 893 | static void flush_multipath_work(void) |
889 | { | 894 | { |
890 | struct multipath *m = (struct multipath *) ti->private; | ||
891 | |||
892 | flush_workqueue(kmpath_handlerd); | 895 | flush_workqueue(kmpath_handlerd); |
893 | flush_workqueue(kmultipathd); | 896 | flush_workqueue(kmultipathd); |
894 | flush_scheduled_work(); | 897 | flush_scheduled_work(); |
898 | } | ||
899 | |||
900 | static void multipath_dtr(struct dm_target *ti) | ||
901 | { | ||
902 | struct multipath *m = ti->private; | ||
903 | |||
904 | flush_multipath_work(); | ||
895 | free_multipath(m); | 905 | free_multipath(m); |
896 | } | 906 | } |
897 | 907 | ||
@@ -1261,6 +1271,16 @@ static void multipath_presuspend(struct dm_target *ti) | |||
1261 | queue_if_no_path(m, 0, 1); | 1271 | queue_if_no_path(m, 0, 1); |
1262 | } | 1272 | } |
1263 | 1273 | ||
1274 | static void multipath_postsuspend(struct dm_target *ti) | ||
1275 | { | ||
1276 | struct multipath *m = ti->private; | ||
1277 | |||
1278 | mutex_lock(&m->work_mutex); | ||
1279 | m->suspended = 1; | ||
1280 | flush_multipath_work(); | ||
1281 | mutex_unlock(&m->work_mutex); | ||
1282 | } | ||
1283 | |||
1264 | /* | 1284 | /* |
1265 | * Restore the queue_if_no_path setting. | 1285 | * Restore the queue_if_no_path setting. |
1266 | */ | 1286 | */ |
@@ -1269,6 +1289,10 @@ static void multipath_resume(struct dm_target *ti) | |||
1269 | struct multipath *m = (struct multipath *) ti->private; | 1289 | struct multipath *m = (struct multipath *) ti->private; |
1270 | unsigned long flags; | 1290 | unsigned long flags; |
1271 | 1291 | ||
1292 | mutex_lock(&m->work_mutex); | ||
1293 | m->suspended = 0; | ||
1294 | mutex_unlock(&m->work_mutex); | ||
1295 | |||
1272 | spin_lock_irqsave(&m->lock, flags); | 1296 | spin_lock_irqsave(&m->lock, flags); |
1273 | m->queue_if_no_path = m->saved_queue_if_no_path; | 1297 | m->queue_if_no_path = m->saved_queue_if_no_path; |
1274 | spin_unlock_irqrestore(&m->lock, flags); | 1298 | spin_unlock_irqrestore(&m->lock, flags); |
@@ -1397,51 +1421,71 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1397 | 1421 | ||
1398 | static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) | 1422 | static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) |
1399 | { | 1423 | { |
1400 | int r; | 1424 | int r = -EINVAL; |
1401 | struct dm_dev *dev; | 1425 | struct dm_dev *dev; |
1402 | struct multipath *m = (struct multipath *) ti->private; | 1426 | struct multipath *m = (struct multipath *) ti->private; |
1403 | action_fn action; | 1427 | action_fn action; |
1404 | 1428 | ||
1429 | mutex_lock(&m->work_mutex); | ||
1430 | |||
1431 | if (m->suspended) { | ||
1432 | r = -EBUSY; | ||
1433 | goto out; | ||
1434 | } | ||
1435 | |||
1436 | if (dm_suspended(ti)) { | ||
1437 | r = -EBUSY; | ||
1438 | goto out; | ||
1439 | } | ||
1440 | |||
1405 | if (argc == 1) { | 1441 | if (argc == 1) { |
1406 | if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) | 1442 | if (!strnicmp(argv[0], MESG_STR("queue_if_no_path"))) { |
1407 | return queue_if_no_path(m, 1, 0); | 1443 | r = queue_if_no_path(m, 1, 0); |
1408 | else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) | 1444 | goto out; |
1409 | return queue_if_no_path(m, 0, 0); | 1445 | } else if (!strnicmp(argv[0], MESG_STR("fail_if_no_path"))) { |
1446 | r = queue_if_no_path(m, 0, 0); | ||
1447 | goto out; | ||
1448 | } | ||
1410 | } | 1449 | } |
1411 | 1450 | ||
1412 | if (argc != 2) | 1451 | if (argc != 2) { |
1413 | goto error; | 1452 | DMWARN("Unrecognised multipath message received."); |
1453 | goto out; | ||
1454 | } | ||
1414 | 1455 | ||
1415 | if (!strnicmp(argv[0], MESG_STR("disable_group"))) | 1456 | if (!strnicmp(argv[0], MESG_STR("disable_group"))) { |
1416 | return bypass_pg_num(m, argv[1], 1); | 1457 | r = bypass_pg_num(m, argv[1], 1); |
1417 | else if (!strnicmp(argv[0], MESG_STR("enable_group"))) | 1458 | goto out; |
1418 | return bypass_pg_num(m, argv[1], 0); | 1459 | } else if (!strnicmp(argv[0], MESG_STR("enable_group"))) { |
1419 | else if (!strnicmp(argv[0], MESG_STR("switch_group"))) | 1460 | r = bypass_pg_num(m, argv[1], 0); |
1420 | return switch_pg_num(m, argv[1]); | 1461 | goto out; |
1421 | else if (!strnicmp(argv[0], MESG_STR("reinstate_path"))) | 1462 | } else if (!strnicmp(argv[0], MESG_STR("switch_group"))) { |
1463 | r = switch_pg_num(m, argv[1]); | ||
1464 | goto out; | ||
1465 | } else if (!strnicmp(argv[0], MESG_STR("reinstate_path"))) | ||
1422 | action = reinstate_path; | 1466 | action = reinstate_path; |
1423 | else if (!strnicmp(argv[0], MESG_STR("fail_path"))) | 1467 | else if (!strnicmp(argv[0], MESG_STR("fail_path"))) |
1424 | action = fail_path; | 1468 | action = fail_path; |
1425 | else | 1469 | else { |
1426 | goto error; | 1470 | DMWARN("Unrecognised multipath message received."); |
1471 | goto out; | ||
1472 | } | ||
1427 | 1473 | ||
1428 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, | 1474 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, |
1429 | dm_table_get_mode(ti->table), &dev); | 1475 | dm_table_get_mode(ti->table), &dev); |
1430 | if (r) { | 1476 | if (r) { |
1431 | DMWARN("message: error getting device %s", | 1477 | DMWARN("message: error getting device %s", |
1432 | argv[1]); | 1478 | argv[1]); |
1433 | return -EINVAL; | 1479 | goto out; |
1434 | } | 1480 | } |
1435 | 1481 | ||
1436 | r = action_dev(m, dev, action); | 1482 | r = action_dev(m, dev, action); |
1437 | 1483 | ||
1438 | dm_put_device(ti, dev); | 1484 | dm_put_device(ti, dev); |
1439 | 1485 | ||
1486 | out: | ||
1487 | mutex_unlock(&m->work_mutex); | ||
1440 | return r; | 1488 | return r; |
1441 | |||
1442 | error: | ||
1443 | DMWARN("Unrecognised multipath message received."); | ||
1444 | return -EINVAL; | ||
1445 | } | 1489 | } |
1446 | 1490 | ||
1447 | static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, | 1491 | static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, |
@@ -1567,13 +1611,14 @@ out: | |||
1567 | *---------------------------------------------------------------*/ | 1611 | *---------------------------------------------------------------*/ |
1568 | static struct target_type multipath_target = { | 1612 | static struct target_type multipath_target = { |
1569 | .name = "multipath", | 1613 | .name = "multipath", |
1570 | .version = {1, 1, 0}, | 1614 | .version = {1, 1, 1}, |
1571 | .module = THIS_MODULE, | 1615 | .module = THIS_MODULE, |
1572 | .ctr = multipath_ctr, | 1616 | .ctr = multipath_ctr, |
1573 | .dtr = multipath_dtr, | 1617 | .dtr = multipath_dtr, |
1574 | .map_rq = multipath_map, | 1618 | .map_rq = multipath_map, |
1575 | .rq_end_io = multipath_end_io, | 1619 | .rq_end_io = multipath_end_io, |
1576 | .presuspend = multipath_presuspend, | 1620 | .presuspend = multipath_presuspend, |
1621 | .postsuspend = multipath_postsuspend, | ||
1577 | .resume = multipath_resume, | 1622 | .resume = multipath_resume, |
1578 | .status = multipath_status, | 1623 | .status = multipath_status, |
1579 | .message = multipath_message, | 1624 | .message = multipath_message, |