Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -2931,6 +2931,7 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len)
		 * can be sane */
		return -EBUSY;
	rdev->data_offset = offset;
	rdev->new_data_offset = offset;
	return len;
}

@@ -3926,8 +3927,8 @@ array_state_show(struct mddev *mddev, char *page)
	return sprintf(page, "%s\n", array_states[st]);
}

static int do_md_stop(struct mddev * mddev, int ro, int is_open);
static int md_set_readonly(struct mddev * mddev, 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, struct block_device *bdev);
static int do_md_run(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)
		/* stopping an active array */
		if (atomic_read(&mddev->openers) > 0)
			return -EBUSY;
		err = do_md_stop(mddev, 0, 0);
		err = do_md_stop(mddev, 0, NULL);
		break;
	case inactive:
		/* stopping an active array */
		if (mddev->pers) {
			if (atomic_read(&mddev->openers) > 0)
				return -EBUSY;
			err = do_md_stop(mddev, 2, 0);
			err = do_md_stop(mddev, 2, NULL);
		} else
			err = 0; /* already inactive */
		break;
@@ -3958,7 +3959,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
		break; /* not supported yet */
	case readonly:
		if (mddev->pers)
			err = md_set_readonly(mddev, 0);
			err = md_set_readonly(mddev, NULL);
		else {
			mddev->ro = 1;
			set_disk_ro(mddev->gendisk, 1);
@@ -3968,7 +3969,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
	case read_auto:
		if (mddev->pers) {
			if (mddev->ro == 0)
				err = md_set_readonly(mddev, 0);
				err = md_set_readonly(mddev, NULL);
			else if (mddev->ro == 1)
				err = restart_array(mddev);
			if (err == 0) {
@@ -5351,15 +5352,17 @@ void md_stop(struct mddev *mddev)
}
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;
	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));
		err = -EBUSY;
		goto out;
	}
	if (bdev)
		sync_blockdev(bdev);
	if (mddev->pers) {
		__md_stop_writes(mddev);

@@ -5381,18 +5384,26 @@ static int md_set_readonly(struct mddev *mddev, int is_open)
 *   0 - completely stop and dis-assemble 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 md_rdev *rdev;

	mutex_lock(&mddev->open_mutex);
	if (atomic_read(&mddev->openers) > is_open ||
	if (atomic_read(&mddev->openers) > !!bdev ||
	    mddev->sysfs_active) {
		printk("md: %s still in use.\n",mdname(mddev));
		mutex_unlock(&mddev->open_mutex);
		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->ro)
@@ -5466,7 +5477,7 @@ static void autorun_array(struct mddev *mddev)
	err = do_md_run(mddev);
	if (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,
			goto done_unlock;

		case STOP_ARRAY:
			err = do_md_stop(mddev, 0, 1);
			err = do_md_stop(mddev, 0, bdev);
			goto done_unlock;

		case STOP_ARRAY_RO:
			err = md_set_readonly(mddev, 1);
			err = md_set_readonly(mddev, bdev);
			goto done_unlock;

		case BLKROSET:
+8 −2
Original line number Diff line number Diff line
@@ -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 we're here, all write(s) have completed, so clean up */
		md_done_sync(mddev, r1_bio->sectors, 1);
		int s = r1_bio->sectors;
		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);
		}
	}
}