Commit 3e4b9459 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'md-3.5-fixes' of git://neil.brown.name/md

Pull three md bugfixes from NeilBrown:
 "One of the bugs was introduced in 3.5-rc1.  Others have been there for
  longer."

* tag 'md-3.5-fixes' of git://neil.brown.name/md:
  md/raid1: close some possible races on write errors during resync
  md: avoid crash when stopping md array races with closing other open fds.
  md: fix bug in handling of new_data_offset
parents 309d4b00 58e94ae1
...@@ -2931,6 +2931,7 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len) ...@@ -2931,6 +2931,7 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len)
* can be sane */ * can be sane */
return -EBUSY; return -EBUSY;
rdev->data_offset = offset; rdev->data_offset = offset;
rdev->new_data_offset = offset;
return len; return len;
} }
...@@ -3926,8 +3927,8 @@ array_state_show(struct mddev *mddev, char *page) ...@@ -3926,8 +3927,8 @@ array_state_show(struct mddev *mddev, char *page)
return sprintf(page, "%s\n", array_states[st]); return sprintf(page, "%s\n", array_states[st]);
} }
static int do_md_stop(struct mddev * mddev, int ro, int is_open); static int do_md_stop(struct mddev * mddev, int ro, struct block_device *bdev);
static int md_set_readonly(struct mddev * mddev, int is_open); static int md_set_readonly(struct mddev * mddev, struct block_device *bdev);
static int do_md_run(struct mddev * mddev); static int do_md_run(struct mddev * mddev);
static int restart_array(struct mddev *mddev); static int restart_array(struct mddev *mddev);
...@@ -3943,14 +3944,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -3943,14 +3944,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
/* stopping an active array */ /* stopping an active array */
if (atomic_read(&mddev->openers) > 0) if (atomic_read(&mddev->openers) > 0)
return -EBUSY; return -EBUSY;
err = do_md_stop(mddev, 0, 0); err = do_md_stop(mddev, 0, NULL);
break; break;
case inactive: case inactive:
/* stopping an active array */ /* stopping an active array */
if (mddev->pers) { if (mddev->pers) {
if (atomic_read(&mddev->openers) > 0) if (atomic_read(&mddev->openers) > 0)
return -EBUSY; return -EBUSY;
err = do_md_stop(mddev, 2, 0); err = do_md_stop(mddev, 2, NULL);
} else } else
err = 0; /* already inactive */ err = 0; /* already inactive */
break; break;
...@@ -3958,7 +3959,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -3958,7 +3959,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
break; /* not supported yet */ break; /* not supported yet */
case readonly: case readonly:
if (mddev->pers) if (mddev->pers)
err = md_set_readonly(mddev, 0); err = md_set_readonly(mddev, NULL);
else { else {
mddev->ro = 1; mddev->ro = 1;
set_disk_ro(mddev->gendisk, 1); set_disk_ro(mddev->gendisk, 1);
...@@ -3968,7 +3969,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -3968,7 +3969,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
case read_auto: case read_auto:
if (mddev->pers) { if (mddev->pers) {
if (mddev->ro == 0) if (mddev->ro == 0)
err = md_set_readonly(mddev, 0); err = md_set_readonly(mddev, NULL);
else if (mddev->ro == 1) else if (mddev->ro == 1)
err = restart_array(mddev); err = restart_array(mddev);
if (err == 0) { if (err == 0) {
...@@ -5351,15 +5352,17 @@ void md_stop(struct mddev *mddev) ...@@ -5351,15 +5352,17 @@ void md_stop(struct mddev *mddev)
} }
EXPORT_SYMBOL_GPL(md_stop); EXPORT_SYMBOL_GPL(md_stop);
static int md_set_readonly(struct mddev *mddev, int is_open) static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
{ {
int err = 0; int err = 0;
mutex_lock(&mddev->open_mutex); mutex_lock(&mddev->open_mutex);
if (atomic_read(&mddev->openers) > is_open) { if (atomic_read(&mddev->openers) > !!bdev) {
printk("md: %s still in use.\n",mdname(mddev)); printk("md: %s still in use.\n",mdname(mddev));
err = -EBUSY; err = -EBUSY;
goto out; goto out;
} }
if (bdev)
sync_blockdev(bdev);
if (mddev->pers) { if (mddev->pers) {
__md_stop_writes(mddev); __md_stop_writes(mddev);
...@@ -5381,18 +5384,26 @@ static int md_set_readonly(struct mddev *mddev, int is_open) ...@@ -5381,18 +5384,26 @@ static int md_set_readonly(struct mddev *mddev, int is_open)
* 0 - completely stop and dis-assemble array * 0 - completely stop and dis-assemble array
* 2 - stop but do not disassemble array * 2 - stop but do not disassemble array
*/ */
static int do_md_stop(struct mddev * mddev, int mode, int is_open) static int do_md_stop(struct mddev * mddev, int mode,
struct block_device *bdev)
{ {
struct gendisk *disk = mddev->gendisk; struct gendisk *disk = mddev->gendisk;
struct md_rdev *rdev; struct md_rdev *rdev;
mutex_lock(&mddev->open_mutex); mutex_lock(&mddev->open_mutex);
if (atomic_read(&mddev->openers) > is_open || if (atomic_read(&mddev->openers) > !!bdev ||
mddev->sysfs_active) { mddev->sysfs_active) {
printk("md: %s still in use.\n",mdname(mddev)); printk("md: %s still in use.\n",mdname(mddev));
mutex_unlock(&mddev->open_mutex); mutex_unlock(&mddev->open_mutex);
return -EBUSY; return -EBUSY;
} }
if (bdev)
/* It is possible IO was issued on some other
* open file which was closed before we took ->open_mutex.
* As that was not the last close __blkdev_put will not
* have called sync_blockdev, so we must.
*/
sync_blockdev(bdev);
if (mddev->pers) { if (mddev->pers) {
if (mddev->ro) if (mddev->ro)
...@@ -5466,7 +5477,7 @@ static void autorun_array(struct mddev *mddev) ...@@ -5466,7 +5477,7 @@ static void autorun_array(struct mddev *mddev)
err = do_md_run(mddev); err = do_md_run(mddev);
if (err) { if (err) {
printk(KERN_WARNING "md: do_md_run() returned %d\n", err); printk(KERN_WARNING "md: do_md_run() returned %d\n", err);
do_md_stop(mddev, 0, 0); do_md_stop(mddev, 0, NULL);
} }
} }
...@@ -6481,11 +6492,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -6481,11 +6492,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
goto done_unlock; goto done_unlock;
case STOP_ARRAY: case STOP_ARRAY:
err = do_md_stop(mddev, 0, 1); err = do_md_stop(mddev, 0, bdev);
goto done_unlock; goto done_unlock;
case STOP_ARRAY_RO: case STOP_ARRAY_RO:
err = md_set_readonly(mddev, 1); err = md_set_readonly(mddev, bdev);
goto done_unlock; goto done_unlock;
case BLKROSET: case BLKROSET:
......
...@@ -1818,8 +1818,14 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio) ...@@ -1818,8 +1818,14 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
if (atomic_dec_and_test(&r1_bio->remaining)) { if (atomic_dec_and_test(&r1_bio->remaining)) {
/* if we're here, all write(s) have completed, so clean up */ /* if we're here, all write(s) have completed, so clean up */
md_done_sync(mddev, r1_bio->sectors, 1); int s = r1_bio->sectors;
put_buf(r1_bio); if (test_bit(R1BIO_MadeGood, &r1_bio->state) ||
test_bit(R1BIO_WriteError, &r1_bio->state))
reschedule_retry(r1_bio);
else {
put_buf(r1_bio);
md_done_sync(mddev, s, 1);
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment