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

Commit 7e303099 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull MD bugfixes from Shaohua Li:

 - fix raid5-ppl flush request handling hang from Artur

 - fix a potential deadlock in raid5/10 reshape from BingJing

 - fix a deadlock for dm-raid from Heinz

 - fix two md-cluster of raid10 from Lidong and Guoqing

 - fix a NULL deference problem in device removal from Neil

 - fix a NULL deference problem in raid1/raid10 in specific condition
   from Yufen

 - other cleanup and fixes

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md:
  md/raid1: fix NULL pointer dereference
  md: fix a potential deadlock of raid5/raid10 reshape
  md-cluster: choose correct label when clustered layout is not supported
  md: raid5: avoid string overflow warning
  raid5-ppl: fix handling flush requests
  md raid10: fix NULL deference in handle_write_completed()
  md: only allow remove_and_add_spares when no sync_thread running.
  md: document lifetime of internal rdev pointer.
  md: fix md_write_start() deadlock w/o metadata devices
  MD: Free bioset when md_run fails
  raid10: change the size of resync window for clustered raid
  md-multipath: Use seq_putc() in multipath_status()
  md/raid1: Fix trailing semicolon
  md/raid5: simplify uninitialization of shrinker
parents 7bec4a96 3de59bb9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -157,7 +157,7 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev)
		seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
	}
	rcu_read_unlock();
	seq_printf (seq, "]");
	seq_putc(seq, ']');
}

static int multipath_congested(struct mddev *mddev, int bits)
+48 −5
Original line number Diff line number Diff line
@@ -801,6 +801,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
	struct bio *bio;
	int ff = 0;

	if (!page)
		return;

	if (test_bit(Faulty, &rdev->flags))
		return;

@@ -5452,6 +5455,7 @@ int md_run(struct mddev *mddev)
	 * the only valid external interface is through the md
	 * device.
	 */
	mddev->has_superblocks = false;
	rdev_for_each(rdev, mddev) {
		if (test_bit(Faulty, &rdev->flags))
			continue;
@@ -5465,6 +5469,9 @@ int md_run(struct mddev *mddev)
				set_disk_ro(mddev->gendisk, 1);
		}

		if (rdev->sb_page)
			mddev->has_superblocks = true;

		/* perform some consistency tests on the device.
		 * We don't want the data to overlap the metadata,
		 * Internal Bitmap issues have been handled elsewhere.
@@ -5497,8 +5504,10 @@ int md_run(struct mddev *mddev)
	}
	if (mddev->sync_set == NULL) {
		mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
		if (!mddev->sync_set)
			return -ENOMEM;
		if (!mddev->sync_set) {
			err = -ENOMEM;
			goto abort;
		}
	}

	spin_lock(&pers_lock);
@@ -5511,7 +5520,8 @@ int md_run(struct mddev *mddev)
		else
			pr_warn("md: personality for level %s is not loaded!\n",
				mddev->clevel);
		return -EINVAL;
		err = -EINVAL;
		goto abort;
	}
	spin_unlock(&pers_lock);
	if (mddev->level != pers->level) {
@@ -5524,7 +5534,8 @@ int md_run(struct mddev *mddev)
	    pers->start_reshape == NULL) {
		/* This personality cannot handle reshaping... */
		module_put(pers->owner);
		return -EINVAL;
		err = -EINVAL;
		goto abort;
	}

	if (pers->sync_request) {
@@ -5593,7 +5604,7 @@ int md_run(struct mddev *mddev)
		mddev->private = NULL;
		module_put(pers->owner);
		bitmap_destroy(mddev);
		return err;
		goto abort;
	}
	if (mddev->queue) {
		bool nonrot = true;
@@ -5655,6 +5666,18 @@ int md_run(struct mddev *mddev)
	sysfs_notify_dirent_safe(mddev->sysfs_action);
	sysfs_notify(&mddev->kobj, NULL, "degraded");
	return 0;

abort:
	if (mddev->bio_set) {
		bioset_free(mddev->bio_set);
		mddev->bio_set = NULL;
	}
	if (mddev->sync_set) {
		bioset_free(mddev->sync_set);
		mddev->sync_set = NULL;
	}

	return err;
}
EXPORT_SYMBOL_GPL(md_run);

@@ -8049,6 +8072,7 @@ EXPORT_SYMBOL(md_done_sync);
bool md_write_start(struct mddev *mddev, struct bio *bi)
{
	int did_change = 0;

	if (bio_data_dir(bi) != WRITE)
		return true;

@@ -8081,6 +8105,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi)
	rcu_read_unlock();
	if (did_change)
		sysfs_notify_dirent_safe(mddev->sysfs_state);
	if (!mddev->has_superblocks)
		return true;
	wait_event(mddev->sb_wait,
		   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) ||
		   mddev->suspended);
@@ -8543,6 +8569,19 @@ void md_do_sync(struct md_thread *thread)
	set_mask_bits(&mddev->sb_flags, 0,
		      BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS));

	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
			!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
			mddev->delta_disks > 0 &&
			mddev->pers->finish_reshape &&
			mddev->pers->size &&
			mddev->queue) {
		mddev_lock_nointr(mddev);
		md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
		mddev_unlock(mddev);
		set_capacity(mddev->gendisk, mddev->array_sectors);
		revalidate_disk(mddev->gendisk);
	}

	spin_lock(&mddev->lock);
	if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
		/* We completed so min/max setting can be forgotten if used. */
@@ -8569,6 +8608,10 @@ static int remove_and_add_spares(struct mddev *mddev,
	int removed = 0;
	bool remove_some = false;

	if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
		/* Mustn't remove devices when resync thread is running */
		return 0;

	rdev_for_each(rdev, mddev) {
		if ((this == NULL || rdev == this) &&
		    rdev->raid_disk >= 0 &&
+2 −0
Original line number Diff line number Diff line
@@ -468,6 +468,8 @@ struct mddev {
	void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
	struct md_cluster_info		*cluster_info;
	unsigned int			good_device_nr;	/* good device num within cluster raid */

	bool	has_superblocks:1;
};

enum recovery_flags {
+11 −0
Original line number Diff line number Diff line
@@ -1809,6 +1809,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
			struct md_rdev *repl =
				conf->mirrors[conf->raid_disks + number].rdev;
			freeze_array(conf, 0);
			if (atomic_read(&repl->nr_pending)) {
				/* It means that some queued IO of retry_list
				 * hold repl. Thus, we cannot set replacement
				 * as NULL, avoiding rdev NULL pointer
				 * dereference in sync_request_write and
				 * handle_write_finished.
				 */
				err = -EBUSY;
				unfreeze_array(conf);
				goto abort;
			}
			clear_bit(Replacement, &repl->flags);
			p->rdev = repl;
			conf->mirrors[conf->raid_disks + number].rdev = NULL;
+12 −0
Original line number Diff line number Diff line
@@ -26,6 +26,18 @@
#define BARRIER_BUCKETS_NR_BITS		(PAGE_SHIFT - ilog2(sizeof(atomic_t)))
#define BARRIER_BUCKETS_NR		(1<<BARRIER_BUCKETS_NR_BITS)

/* Note: raid1_info.rdev can be set to NULL asynchronously by raid1_remove_disk.
 * There are three safe ways to access raid1_info.rdev.
 * 1/ when holding mddev->reconfig_mutex
 * 2/ when resync/recovery is known to be happening - i.e. in code that is
 *    called as part of performing resync/recovery.
 * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
 *    and if it is non-NULL, increment rdev->nr_pending before dropping the
 *    RCU lock.
 * When .rdev is set to NULL, the nr_pending count checked again and if it has
 * been incremented, the pointer is put back in .rdev.
 */

struct raid1_info {
	struct md_rdev	*rdev;
	sector_t	head_position;
Loading