diff options
| author | Chandra Seetharaman <sekharan@us.ibm.com> | 2008-11-13 18:39:14 -0500 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2008-11-13 18:39:14 -0500 |
| commit | 8a57dfc6f943c92b861c9a19b0c86ddcb2aba768 (patch) | |
| tree | 18090d42e647cda854c93aa304cf03fbad44f6c0 | |
| parent | d221d2e77696e70e94b13989ea15db2ba5b34f8e (diff) | |
dm: avoid destroying table in dm_any_congested
dm_any_congested() just checks for the DMF_BLOCK_IO and has no
code to make sure that suspend waits for dm_any_congested() to
complete. This patch adds such a check.
Without it, a race can occur with dm_table_put() attempting to
destroying the table in the wrong thread, the one running
dm_any_congested() which is meant to be quick and return
immediately.
Two examples of problems:
1. Sleeping functions called from congested code, the caller
of which holds a spin lock.
2. An ABBA deadlock between pdflush and multipathd. The two locks
in contention are inode lock and kernel lock.
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
| -rw-r--r-- | drivers/md/dm.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index dc25d8a07bc7..c99e4728ff41 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -937,16 +937,24 @@ static void dm_unplug_all(struct request_queue *q) | |||
| 937 | 937 | ||
| 938 | static int dm_any_congested(void *congested_data, int bdi_bits) | 938 | static int dm_any_congested(void *congested_data, int bdi_bits) |
| 939 | { | 939 | { |
| 940 | int r; | 940 | int r = bdi_bits; |
| 941 | struct mapped_device *md = (struct mapped_device *) congested_data; | 941 | struct mapped_device *md = congested_data; |
| 942 | struct dm_table *map = dm_get_table(md); | 942 | struct dm_table *map; |
| 943 | 943 | ||
| 944 | if (!map || test_bit(DMF_BLOCK_IO, &md->flags)) | 944 | atomic_inc(&md->pending); |
| 945 | r = bdi_bits; | 945 | |
| 946 | else | 946 | if (!test_bit(DMF_BLOCK_IO, &md->flags)) { |
| 947 | r = dm_table_any_congested(map, bdi_bits); | 947 | map = dm_get_table(md); |
| 948 | if (map) { | ||
| 949 | r = dm_table_any_congested(map, bdi_bits); | ||
| 950 | dm_table_put(map); | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 954 | if (!atomic_dec_return(&md->pending)) | ||
| 955 | /* nudge anyone waiting on suspend queue */ | ||
| 956 | wake_up(&md->wait); | ||
| 948 | 957 | ||
| 949 | dm_table_put(map); | ||
| 950 | return r; | 958 | return r; |
| 951 | } | 959 | } |
| 952 | 960 | ||
