MD: hold mddev lock to change bitmap location

Changing the location changes a lot of things. Holding the lock to avoid race.
This makes the .quiesce called with mddev lock hold too.

Acked-by: NeilBrown <neilb@suse.com>
Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
Shaohua Li 2016-07-30 10:05:31 -07:00
parent ff00d3b4e5
commit d9dd26b20c

View File

@ -2183,19 +2183,29 @@ location_show(struct mddev *mddev, char *page)
static ssize_t static ssize_t
location_store(struct mddev *mddev, const char *buf, size_t len) location_store(struct mddev *mddev, const char *buf, size_t len)
{ {
int rv;
rv = mddev_lock(mddev);
if (rv)
return rv;
if (mddev->pers) { if (mddev->pers) {
if (!mddev->pers->quiesce) if (!mddev->pers->quiesce) {
return -EBUSY; rv = -EBUSY;
if (mddev->recovery || mddev->sync_thread) goto out;
return -EBUSY; }
if (mddev->recovery || mddev->sync_thread) {
rv = -EBUSY;
goto out;
}
} }
if (mddev->bitmap || mddev->bitmap_info.file || if (mddev->bitmap || mddev->bitmap_info.file ||
mddev->bitmap_info.offset) { mddev->bitmap_info.offset) {
/* bitmap already configured. Only option is to clear it */ /* bitmap already configured. Only option is to clear it */
if (strncmp(buf, "none", 4) != 0) if (strncmp(buf, "none", 4) != 0) {
return -EBUSY; rv = -EBUSY;
goto out;
}
if (mddev->pers) { if (mddev->pers) {
mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 1);
bitmap_destroy(mddev); bitmap_destroy(mddev);
@ -2214,21 +2224,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
/* nothing to be done */; /* nothing to be done */;
else if (strncmp(buf, "file:", 5) == 0) { else if (strncmp(buf, "file:", 5) == 0) {
/* Not supported yet */ /* Not supported yet */
return -EINVAL; rv = -EINVAL;
goto out;
} else { } else {
int rv;
if (buf[0] == '+') if (buf[0] == '+')
rv = kstrtoll(buf+1, 10, &offset); rv = kstrtoll(buf+1, 10, &offset);
else else
rv = kstrtoll(buf, 10, &offset); rv = kstrtoll(buf, 10, &offset);
if (rv) if (rv)
return rv; goto out;
if (offset == 0) if (offset == 0) {
return -EINVAL; rv = -EINVAL;
goto out;
}
if (mddev->bitmap_info.external == 0 && if (mddev->bitmap_info.external == 0 &&
mddev->major_version == 0 && mddev->major_version == 0 &&
offset != mddev->bitmap_info.default_offset) offset != mddev->bitmap_info.default_offset) {
return -EINVAL; rv = -EINVAL;
goto out;
}
mddev->bitmap_info.offset = offset; mddev->bitmap_info.offset = offset;
if (mddev->pers) { if (mddev->pers) {
struct bitmap *bitmap; struct bitmap *bitmap;
@ -2245,7 +2259,7 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
mddev->pers->quiesce(mddev, 0); mddev->pers->quiesce(mddev, 0);
if (rv) { if (rv) {
bitmap_destroy(mddev); bitmap_destroy(mddev);
return rv; goto out;
} }
} }
} }
@ -2257,6 +2271,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
set_bit(MD_CHANGE_DEVS, &mddev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags);
md_wakeup_thread(mddev->thread); md_wakeup_thread(mddev->thread);
} }
rv = 0;
out:
mddev_unlock(mddev);
if (rv)
return rv;
return len; return len;
} }