aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2005-07-12 18:53:03 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-12 19:19:10 -0400
commit436d41087d047b61f8ab0604dc74fff3240a8933 (patch)
tree46bab3a0cf02a7514b4faa5470a76326e6f8bc72
parenta044d016896d2717694003f00d31a98194077511 (diff)
[PATCH] device-mapper multipath: Avoid possible suspension deadlock
To avoid deadlock when suspending a multipath device after all its paths have failed, stop queueing any I/O that is about to fail *before* calling freeze_bdev instead of after. Instead of setting a multipath 'suspended' flag which would have to be reset if an error occurs during the process, save the previous queueing state and leave userspace to restore if it wishes. Signed-off-by: Alasdair G Kergon <agk@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/md/dm-mpath.c25
-rw-r--r--drivers/md/dm.c12
2 files changed, 20 insertions, 17 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index fa72f0153206..98da8eee2d2c 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -72,7 +72,7 @@ struct multipath {
72 72
73 unsigned queue_io; /* Must we queue all I/O? */ 73 unsigned queue_io; /* Must we queue all I/O? */
74 unsigned queue_if_no_path; /* Queue I/O if last path fails? */ 74 unsigned queue_if_no_path; /* Queue I/O if last path fails? */
75 unsigned suspended; /* Has dm core suspended our I/O? */ 75 unsigned saved_queue_if_no_path;/* Saved state during suspension */
76 76
77 struct work_struct process_queued_ios; 77 struct work_struct process_queued_ios;
78 struct bio_list queued_ios; 78 struct bio_list queued_ios;
@@ -304,7 +304,7 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
304 m->queue_size--; 304 m->queue_size--;
305 305
306 if ((pgpath && m->queue_io) || 306 if ((pgpath && m->queue_io) ||
307 (!pgpath && m->queue_if_no_path && !m->suspended)) { 307 (!pgpath && m->queue_if_no_path)) {
308 /* Queue for the daemon to resubmit */ 308 /* Queue for the daemon to resubmit */
309 bio_list_add(&m->queued_ios, bio); 309 bio_list_add(&m->queued_ios, bio);
310 m->queue_size++; 310 m->queue_size++;
@@ -333,6 +333,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path)
333 333
334 spin_lock_irqsave(&m->lock, flags); 334 spin_lock_irqsave(&m->lock, flags);
335 335
336 m->saved_queue_if_no_path = m->queue_if_no_path;
336 m->queue_if_no_path = queue_if_no_path; 337 m->queue_if_no_path = queue_if_no_path;
337 if (!m->queue_if_no_path) 338 if (!m->queue_if_no_path)
338 queue_work(kmultipathd, &m->process_queued_ios); 339 queue_work(kmultipathd, &m->process_queued_ios);
@@ -391,7 +392,7 @@ static void process_queued_ios(void *data)
391 pgpath = m->current_pgpath; 392 pgpath = m->current_pgpath;
392 393
393 if ((pgpath && m->queue_io) || 394 if ((pgpath && m->queue_io) ||
394 (!pgpath && m->queue_if_no_path && !m->suspended)) 395 (!pgpath && m->queue_if_no_path))
395 must_queue = 1; 396 must_queue = 1;
396 397
397 init_required = m->pg_init_required; 398 init_required = m->pg_init_required;
@@ -998,7 +999,7 @@ static int do_end_io(struct multipath *m, struct bio *bio,
998 999
999 spin_lock(&m->lock); 1000 spin_lock(&m->lock);
1000 if (!m->nr_valid_paths) { 1001 if (!m->nr_valid_paths) {
1001 if (!m->queue_if_no_path || m->suspended) { 1002 if (!m->queue_if_no_path) {
1002 spin_unlock(&m->lock); 1003 spin_unlock(&m->lock);
1003 return -EIO; 1004 return -EIO;
1004 } else { 1005 } else {
@@ -1059,27 +1060,27 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio,
1059 1060
1060/* 1061/*
1061 * Suspend can't complete until all the I/O is processed so if 1062 * Suspend can't complete until all the I/O is processed so if
1062 * the last path failed we will now error any queued I/O. 1063 * the last path fails we must error any remaining I/O.
1064 * Note that if the freeze_bdev fails while suspending, the
1065 * queue_if_no_path state is lost - userspace should reset it.
1063 */ 1066 */
1064static void multipath_presuspend(struct dm_target *ti) 1067static void multipath_presuspend(struct dm_target *ti)
1065{ 1068{
1066 struct multipath *m = (struct multipath *) ti->private; 1069 struct multipath *m = (struct multipath *) ti->private;
1067 unsigned long flags;
1068 1070
1069 spin_lock_irqsave(&m->lock, flags); 1071 queue_if_no_path(m, 0);
1070 m->suspended = 1;
1071 if (m->queue_if_no_path)
1072 queue_work(kmultipathd, &m->process_queued_ios);
1073 spin_unlock_irqrestore(&m->lock, flags);
1074} 1072}
1075 1073
1074/*
1075 * Restore the queue_if_no_path setting.
1076 */
1076static void multipath_resume(struct dm_target *ti) 1077static void multipath_resume(struct dm_target *ti)
1077{ 1078{
1078 struct multipath *m = (struct multipath *) ti->private; 1079 struct multipath *m = (struct multipath *) ti->private;
1079 unsigned long flags; 1080 unsigned long flags;
1080 1081
1081 spin_lock_irqsave(&m->lock, flags); 1082 spin_lock_irqsave(&m->lock, flags);
1082 m->suspended = 0; 1083 m->queue_if_no_path = m->saved_queue_if_no_path;
1083 spin_unlock_irqrestore(&m->lock, flags); 1084 spin_unlock_irqrestore(&m->lock, flags);
1084} 1085}
1085 1086
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5d40555b42ba..bb3ad79c14d7 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1055,14 +1055,17 @@ int dm_suspend(struct mapped_device *md)
1055 if (test_bit(DMF_BLOCK_IO, &md->flags)) 1055 if (test_bit(DMF_BLOCK_IO, &md->flags))
1056 goto out_read_unlock; 1056 goto out_read_unlock;
1057 1057
1058 error = __lock_fs(md);
1059 if (error)
1060 goto out_read_unlock;
1061
1062 map = dm_get_table(md); 1058 map = dm_get_table(md);
1063 if (map) 1059 if (map)
1060 /* This does not get reverted if there's an error later. */
1064 dm_table_presuspend_targets(map); 1061 dm_table_presuspend_targets(map);
1065 1062
1063 error = __lock_fs(md);
1064 if (error) {
1065 dm_table_put(map);
1066 goto out_read_unlock;
1067 }
1068
1066 up_read(&md->lock); 1069 up_read(&md->lock);
1067 1070
1068 /* 1071 /*
@@ -1121,7 +1124,6 @@ int dm_suspend(struct mapped_device *md)
1121 return 0; 1124 return 0;
1122 1125
1123out_unfreeze: 1126out_unfreeze:
1124 /* FIXME Undo dm_table_presuspend_targets */
1125 __unlock_fs(md); 1127 __unlock_fs(md);
1126 clear_bit(DMF_BLOCK_IO, &md->flags); 1128 clear_bit(DMF_BLOCK_IO, &md->flags);
1127out_write_unlock: 1129out_write_unlock: