History

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>

Dan Williams committed 18 years ago

Commit b5470dc1 parent 1fe797e4 files · +30 −17Browse files

Unified · Split

4 files
  1. drivers/md/md.c +16 −11
  2. drivers/md/raid1.c +4 −2
  3. drivers/md/raid5.c +9 −3
  4. include/linux/raid/md.h +1 −1
drivers/md/md.c+16−11
@@ -4172,9 +4172,11 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg) · 4171 unmodified lines
41724172 char *ptr, *buf = NULL;
41734173 int err = -ENOMEM;
41744174
4175− md_allow_write(mddev);
4175+ if (md_allow_write(mddev))
4176+ file = kmalloc(sizeof(*file), GFP_NOIO);
4177+ else
4178+ file = kmalloc(sizeof(*file), GFP_KERNEL);
41764179
4177− file = kmalloc(sizeof(*file), GFP_KERNEL);
41784180 if (!file)
41794181 goto out;
41804182
@@ -5667,15 +5669,18 @@ void md_write_end(mddev_t *mddev) · 1486 unmodified lines
56675669 * may proceed without blocking. It is important to call this before
56685670 * attempting a GFP_KERNEL allocation while holding the mddev lock.
56695671 * Must be called with mddev_lock held.
5672+ *
5673+ * In the ->external case MD_CHANGE_CLEAN can not be cleared until mddev->lock
5674+ * is dropped, so return -EAGAIN after notifying userspace.
56705675 */
5671−void md_allow_write(mddev_t *mddev)
5676+int md_allow_write(mddev_t *mddev)
56725677 {
56735678 if (!mddev->pers)
5674− return;
5679+ return 0;
56755680 if (mddev->ro)
5676− return;
5681+ return 0;
56775682 if (!mddev->pers->sync_request)
5678− return;
5683+ return 0;
56795684
56805685 spin_lock_irq(&mddev->write_lock);
56815686 if (mddev->in_sync) {
@@ -5686,14 +5691,14 @@ void md_allow_write(mddev_t *mddev) · 4 unmodified lines
56865691 mddev->safemode = 1;
56875692 spin_unlock_irq(&mddev->write_lock);
56885693 md_update_sb(mddev, 0);
5689−
56905694 sysfs_notify(&mddev->kobj, NULL, "array_state");
5691− /* wait for the dirty state to be recorded in the metadata */
5692− wait_event(mddev->sb_wait,
5693− !test_bit(MD_CHANGE_CLEAN, &mddev->flags) &&
5694− !test_bit(MD_CHANGE_PENDING, &mddev->flags));
56955695 } else
56965696 spin_unlock_irq(&mddev->write_lock);
5697+
5698+ if (test_bit(MD_CHANGE_CLEAN, &mddev->flags))
5699+ return -EAGAIN;
5700+ else
5701+ return 0;
56975702 }
56985703 EXPORT_SYMBOL_GPL(md_allow_write);
56995704
drivers/md/raid1.c+4−2
@@ -2136,7 +2136,7 @@ static int raid1_reshape(mddev_t *mddev) · 2135 unmodified lines
21362136 conf_t *conf = mddev_to_conf(mddev);
21372137 int cnt, raid_disks;
21382138 unsigned long flags;
2139− int d, d2;
2139+ int d, d2, err;
21402140
21412141 /* Cannot change chunk_size, layout, or level */
21422142 if (mddev->chunk_size != mddev->new_chunk ||
@@ -2148,7 +2148,9 @@ static int raid1_reshape(mddev_t *mddev) · 5 unmodified lines
21482148 return -EINVAL;
21492149 }
21502150
2151− md_allow_write(mddev);
2151+ err = md_allow_write(mddev);
2152+ if (err)
2153+ return err;
21522154
21532155 raid_disks = mddev->raid_disks + mddev->delta_disks;
21542156
drivers/md/raid5.c+9−3
@@ -911,14 +911,16 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) · 910 unmodified lines
911911 struct stripe_head *osh, *nsh;
912912 LIST_HEAD(newstripes);
913913 struct disk_info *ndisks;
914− int err = 0;
914+ int err;
915915 struct kmem_cache *sc;
916916 int i;
917917
918918 if (newsize <= conf->pool_size)
919919 return 0; /* never bother to shrink */
920920
921− md_allow_write(conf->mddev);
921+ err = md_allow_write(conf->mddev);
922+ if (err)
923+ return err;
922924
923925 /* Step 1 */
924926 sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
@@ -3843,6 +3845,8 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) · 2918 unmodified lines
38433845 {
38443846 raid5_conf_t *conf = mddev_to_conf(mddev);
38453847 unsigned long new;
3848+ int err;
3849+
38463850 if (len >= PAGE_SIZE)
38473851 return -EINVAL;
38483852 if (!conf)
@@ -3858,7 +3862,9 @@ raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) · 9 unmodified lines
38583862 else
38593863 break;
38603864 }
3861− md_allow_write(mddev);
3865+ err = md_allow_write(mddev);
3866+ if (err)
3867+ return err;
38623868 while (new > conf->max_nr_stripes) {
38633869 if (grow_one_stripe(conf))
38643870 conf->max_nr_stripes++;
include/linux/raid/md.h+1−1
@@ -95,7 +95,7 @@ extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, · 94 unmodified lines
9595 struct page *page, int rw);
9696 extern void md_do_sync(mddev_t *mddev);
9797 extern void md_new_event(mddev_t *mddev);
98−extern void md_allow_write(mddev_t *mddev);
98+extern int md_allow_write(mddev_t *mddev);
9999 extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
100100
101101 #endif /* CONFIG_MD */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t