1
0
Fork 0

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>
hifive-unleashed-5.1
Shaohua Li 2016-07-30 10:05:31 -07:00
parent ff00d3b4e5
commit d9dd26b20c
1 changed files with 33 additions and 14 deletions

View File

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