diff options
author | Dan Williams <dan.j.williams@intel.com> | 2008-06-28 00:44:04 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2008-06-30 20:18:19 -0400 |
commit | b5470dc5fc18a8ff6517c3bb538d1479e58ecb02 (patch) | |
tree | 37b0eb3a4691bdbe58dc5c6c73b2dc8d3925b332 /drivers/md/raid1.c | |
parent | 1fe797e67fb07d605b82300934d0de67068a0aca (diff) |
md: resolve external metadata handling deadlock in md_allow_write
md_allow_write() marks the metadata dirty while holding mddev->lock and then
waits for the write to complete. For externally managed metadata this causes a
deadlock as userspace needs to take the lock to communicate that the metadata
update has completed.
Change md_allow_write() in the 'external' case to start the 'mark active'
operation and then return -EAGAIN. The expected side effects while waiting for
userspace to write 'active' to 'array_state' are holding off reshape (code
currently handles -ENOMEM), cause some 'stripe_cache_size' change requests to
fail, cause some GET_BITMAP_FILE ioctl requests to fall back to GFP_NOIO, and
cause updates to 'raid_disks' to fail. Except for 'stripe_cache_size' changes
these failures can be mitigated by coordinating with mdmon.
md_write_start() still prevents writes from occurring until the metadata
handler has had a chance to take action as it unconditionally waits for
MD_CHANGE_CLEAN to be cleared.
[neilb@suse.de: return -EAGAIN, try GFP_NOIO]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/md/raid1.c')
-rw-r--r-- | drivers/md/raid1.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f05d5983efb6..491dc2d4ad5f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -2136,7 +2136,7 @@ static int raid1_reshape(mddev_t *mddev) | |||
2136 | conf_t *conf = mddev_to_conf(mddev); | 2136 | conf_t *conf = mddev_to_conf(mddev); |
2137 | int cnt, raid_disks; | 2137 | int cnt, raid_disks; |
2138 | unsigned long flags; | 2138 | unsigned long flags; |
2139 | int d, d2; | 2139 | int d, d2, err; |
2140 | 2140 | ||
2141 | /* Cannot change chunk_size, layout, or level */ | 2141 | /* Cannot change chunk_size, layout, or level */ |
2142 | if (mddev->chunk_size != mddev->new_chunk || | 2142 | if (mddev->chunk_size != mddev->new_chunk || |
@@ -2148,7 +2148,9 @@ static int raid1_reshape(mddev_t *mddev) | |||
2148 | return -EINVAL; | 2148 | return -EINVAL; |
2149 | } | 2149 | } |
2150 | 2150 | ||
2151 | md_allow_write(mddev); | 2151 | err = md_allow_write(mddev); |
2152 | if (err) | ||
2153 | return err; | ||
2152 | 2154 | ||
2153 | raid_disks = mddev->raid_disks + mddev->delta_disks; | 2155 | raid_disks = mddev->raid_disks + mddev->delta_disks; |
2154 | 2156 | ||