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

Commit 697a067f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull md updates from NeilBrown:
 "Mostly fixes, with a few minor features (eg 'last_sync_action' sysfs
  file)

  A couple marked for -stable including one recent bug which causes a
  RAID10 reshape to complete without moving any data :-(

  A couple more bugfixes (at least) to come, but haven't confirmed the
  right solution yet."

* tag 'md-3.11' of git://neil.brown.name/md:
  md/raid10: fix bug which causes all RAID10 reshapes to move no data.
  md/raid5: allow 5-device RAID6 to be reshaped to 4-device.
  md/raid10: fix two bugs affecting RAID10 reshape.
  md: remove doubled description for sync_max, merging it within sync_min/sync_max
  MD: Remember the last sync operation that was performed
  md: fix buglet in RAID5 -> RAID0 conversion.
  md/raid10: check In_sync flag in 'enough()'.
  md/raid10: locking changes for 'enough()'.
  md: replace strict_strto*() with kstrto*()
  md: Wait for md_check_recovery before attempting device removal.
  dm-raid: silence compiler warning on rebuilds_per_group.
  DM RAID: Fix raid_resume not reviving failed devices in all cases
  DM RAID: Break-up untidy function
  DM RAID: Add ability to restore transiently failed devices on resume
parents e61aca51 13765120
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -222,3 +222,5 @@ Version History
1.4.2   Add RAID10 "far" and "offset" algorithm support.
1.5.0   Add message interface to allow manipulation of the sync_action.
	New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
1.5.1   Add ability to restore transiently failed devices on resume.
1.5.2   'mismatch_cnt' is zero unless [last_]sync_action is "check".
+6 −7
Original line number Diff line number Diff line
@@ -566,13 +566,6 @@ also have
     when it reaches the current sync_max (below) and possibly at
     other times.

   sync_max
     This is a number of sectors at which point a resync/recovery
     process will pause.  When a resync is active, the value can
     only ever be increased, never decreased.  The value of 'max'
     effectively disables the limit.


   sync_speed
     This shows the current actual speed, in K/sec, of the current
     sync_action.  It is averaged over the last 30 seconds.
@@ -593,6 +586,12 @@ also have
     that number to reach sync_max.  Then you can either increase
     "sync_max", or can write 'idle' to "sync_action".

     The value of 'max' for "sync_max" effectively disables the limit.
     When a resync is active, the value can only ever be increased,
     never decreased.
     The value of '0' is the minimum for "sync_min".



Each active md device may also have attributes specific to the
personality module that manages it.
+4 −4
Original line number Diff line number Diff line
@@ -2002,9 +2002,9 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
		} else {
			int rv;
			if (buf[0] == '+')
				rv = strict_strtoll(buf+1, 10, &offset);
				rv = kstrtoll(buf+1, 10, &offset);
			else
				rv = strict_strtoll(buf, 10, &offset);
				rv = kstrtoll(buf, 10, &offset);
			if (rv)
				return rv;
			if (offset == 0)
@@ -2139,7 +2139,7 @@ static ssize_t
backlog_store(struct mddev *mddev, const char *buf, size_t len)
{
	unsigned long backlog;
	int rv = strict_strtoul(buf, 10, &backlog);
	int rv = kstrtoul(buf, 10, &backlog);
	if (rv)
		return rv;
	if (backlog > COUNTER_MAX)
@@ -2165,7 +2165,7 @@ chunksize_store(struct mddev *mddev, const char *buf, size_t len)
	unsigned long csize;
	if (mddev->bitmap)
		return -EBUSY;
	rv = strict_strtoul(buf, 10, &csize);
	rv = kstrtoul(buf, 10, &csize);
	if (rv)
		return rv;
	if (csize < 512 ||
+70 −6
Original line number Diff line number Diff line
@@ -380,7 +380,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
static int validate_raid_redundancy(struct raid_set *rs)
{
	unsigned i, rebuild_cnt = 0;
	unsigned rebuilds_per_group, copies, d;
	unsigned rebuilds_per_group = 0, copies, d;
	unsigned group_size, last_group_start;

	for (i = 0; i < rs->md.raid_disks; i++)
@@ -504,7 +504,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
	 * First, parse the in-order required arguments
	 * "chunk_size" is the only argument of this type.
	 */
	if ((strict_strtoul(argv[0], 10, &value) < 0)) {
	if ((kstrtoul(argv[0], 10, &value) < 0)) {
		rs->ti->error = "Bad chunk size";
		return -EINVAL;
	} else if (rs->raid_type->level == 1) {
@@ -585,7 +585,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
			continue;
		}

		if (strict_strtoul(argv[i], 10, &value) < 0) {
		if (kstrtoul(argv[i], 10, &value) < 0) {
			rs->ti->error = "Bad numerical argument given in raid params";
			return -EINVAL;
		}
@@ -1181,7 +1181,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
	argv++;

	/* number of RAID parameters */
	if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) {
	if (kstrtoul(argv[0], 10, &num_raid_params) < 0) {
		ti->error = "Cannot understand number of RAID parameters";
		return -EINVAL;
	}
@@ -1194,7 +1194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
		return -EINVAL;
	}

	if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
	if ((kstrtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
	    (num_raid_devs >= INT_MAX)) {
		ti->error = "Cannot understand number of raid devices";
		return -EINVAL;
@@ -1388,6 +1388,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
		 *   performing a "check" of the array.
		 */
		DMEMIT(" %llu",
		       (strcmp(rs->md.last_sync_action, "check")) ? 0 :
		       (unsigned long long)
		       atomic64_read(&rs->md.resync_mismatches));
		break;
@@ -1572,6 +1573,62 @@ static void raid_postsuspend(struct dm_target *ti)
	mddev_suspend(&rs->md);
}

static void attempt_restore_of_faulty_devices(struct raid_set *rs)
{
	int i;
	uint64_t failed_devices, cleared_failed_devices = 0;
	unsigned long flags;
	struct dm_raid_superblock *sb;
	struct md_rdev *r;

	for (i = 0; i < rs->md.raid_disks; i++) {
		r = &rs->dev[i].rdev;
		if (test_bit(Faulty, &r->flags) && r->sb_page &&
		    sync_page_io(r, 0, r->sb_size, r->sb_page, READ, 1)) {
			DMINFO("Faulty %s device #%d has readable super block."
			       "  Attempting to revive it.",
			       rs->raid_type->name, i);

			/*
			 * Faulty bit may be set, but sometimes the array can
			 * be suspended before the personalities can respond
			 * by removing the device from the array (i.e. calling
			 * 'hot_remove_disk').  If they haven't yet removed
			 * the failed device, its 'raid_disk' number will be
			 * '>= 0' - meaning we must call this function
			 * ourselves.
			 */
			if ((r->raid_disk >= 0) &&
			    (r->mddev->pers->hot_remove_disk(r->mddev, r) != 0))
				/* Failed to revive this device, try next */
				continue;

			r->raid_disk = i;
			r->saved_raid_disk = i;
			flags = r->flags;
			clear_bit(Faulty, &r->flags);
			clear_bit(WriteErrorSeen, &r->flags);
			clear_bit(In_sync, &r->flags);
			if (r->mddev->pers->hot_add_disk(r->mddev, r)) {
				r->raid_disk = -1;
				r->saved_raid_disk = -1;
				r->flags = flags;
			} else {
				r->recovery_offset = 0;
				cleared_failed_devices |= 1 << i;
			}
		}
	}
	if (cleared_failed_devices) {
		rdev_for_each(r, &rs->md) {
			sb = page_address(r->sb_page);
			failed_devices = le64_to_cpu(sb->failed_devices);
			failed_devices &= ~cleared_failed_devices;
			sb->failed_devices = cpu_to_le64(failed_devices);
		}
	}
}

static void raid_resume(struct dm_target *ti)
{
	struct raid_set *rs = ti->private;
@@ -1580,6 +1637,13 @@ static void raid_resume(struct dm_target *ti)
	if (!rs->bitmap_loaded) {
		bitmap_load(&rs->md);
		rs->bitmap_loaded = 1;
	} else {
		/*
		 * A secondary resume while the device is active.
		 * Take this opportunity to check whether any failed
		 * devices are reachable again.
		 */
		attempt_restore_of_faulty_devices(rs);
	}

	clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
@@ -1588,7 +1652,7 @@ static void raid_resume(struct dm_target *ti)

static struct target_type raid_target = {
	.name = "raid",
	.version = {1, 5, 0},
	.version = {1, 5, 2},
	.module = THIS_MODULE,
	.ctr = raid_ctr,
	.dtr = raid_dtr,
+37 −16
Original line number Diff line number Diff line
@@ -521,6 +521,7 @@ void mddev_init(struct mddev *mddev)
	init_waitqueue_head(&mddev->recovery_wait);
	mddev->reshape_position = MaxSector;
	mddev->reshape_backwards = 0;
	mddev->last_sync_action = "none";
	mddev->resync_min = 0;
	mddev->resync_max = MaxSector;
	mddev->level = LEVEL_NONE;
@@ -2867,7 +2868,7 @@ static ssize_t
offset_store(struct md_rdev *rdev, const char *buf, size_t len)
{
	unsigned long long offset;
	if (strict_strtoull(buf, 10, &offset) < 0)
	if (kstrtoull(buf, 10, &offset) < 0)
		return -EINVAL;
	if (rdev->mddev->pers && rdev->raid_disk >= 0)
		return -EBUSY;
@@ -2895,7 +2896,7 @@ static ssize_t new_offset_store(struct md_rdev *rdev,
	unsigned long long new_offset;
	struct mddev *mddev = rdev->mddev;

	if (strict_strtoull(buf, 10, &new_offset) < 0)
	if (kstrtoull(buf, 10, &new_offset) < 0)
		return -EINVAL;

	if (mddev->sync_thread)
@@ -2961,7 +2962,7 @@ static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
	unsigned long long blocks;
	sector_t new;

	if (strict_strtoull(buf, 10, &blocks) < 0)
	if (kstrtoull(buf, 10, &blocks) < 0)
		return -EINVAL;

	if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
@@ -3069,7 +3070,7 @@ static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_

	if (cmd_match(buf, "none"))
		recovery_start = MaxSector;
	else if (strict_strtoull(buf, 10, &recovery_start))
	else if (kstrtoull(buf, 10, &recovery_start))
		return -EINVAL;

	if (rdev->mddev->pers &&
@@ -3497,7 +3498,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
	if (clevel[len-1] == '\n')
		len--;
	clevel[len] = 0;
	if (strict_strtol(clevel, 10, &level))
	if (kstrtol(clevel, 10, &level))
		level = LEVEL_NONE;

	if (request_module("md-%s", clevel) != 0)
@@ -4272,6 +4273,17 @@ action_store(struct mddev *mddev, const char *page, size_t len)
	return len;
}

static struct md_sysfs_entry md_scan_mode =
__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);

static ssize_t
last_sync_action_show(struct mddev *mddev, char *page)
{
	return sprintf(page, "%s\n", mddev->last_sync_action);
}

static struct md_sysfs_entry md_last_scan_mode = __ATTR_RO(last_sync_action);

static ssize_t
mismatch_cnt_show(struct mddev *mddev, char *page)
{
@@ -4280,10 +4292,6 @@ mismatch_cnt_show(struct mddev *mddev, char *page)
		       atomic64_read(&mddev->resync_mismatches));
}

static struct md_sysfs_entry md_scan_mode =
__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);


static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);

static ssize_t
@@ -4356,7 +4364,7 @@ sync_force_parallel_store(struct mddev *mddev, const char *buf, size_t len)
{
	long n;

	if (strict_strtol(buf, 10, &n))
	if (kstrtol(buf, 10, &n))
		return -EINVAL;

	if (n != 0 && n != 1)
@@ -4424,7 +4432,7 @@ static ssize_t
min_sync_store(struct mddev *mddev, const char *buf, size_t len)
{
	unsigned long long min;
	if (strict_strtoull(buf, 10, &min))
	if (kstrtoull(buf, 10, &min))
		return -EINVAL;
	if (min > mddev->resync_max)
		return -EINVAL;
@@ -4461,7 +4469,7 @@ max_sync_store(struct mddev *mddev, const char *buf, size_t len)
		mddev->resync_max = MaxSector;
	else {
		unsigned long long max;
		if (strict_strtoull(buf, 10, &max))
		if (kstrtoull(buf, 10, &max))
			return -EINVAL;
		if (max < mddev->resync_min)
			return -EINVAL;
@@ -4686,6 +4694,7 @@ static struct attribute *md_default_attrs[] = {

static struct attribute *md_redundancy_attrs[] = {
	&md_scan_mode.attr,
	&md_last_scan_mode.attr,
	&md_mismatches.attr,
	&md_sync_min.attr,
	&md_sync_max.attr,
@@ -6405,6 +6414,12 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
		/* need to ensure md_delayed_delete() has completed */
		flush_workqueue(md_misc_wq);

	if (cmd == HOT_REMOVE_DISK)
		/* need to ensure recovery thread has run */
		wait_event_interruptible_timeout(mddev->sb_wait,
						 !test_bit(MD_RECOVERY_NEEDED,
							   &mddev->flags),
						 msecs_to_jiffies(5000));
	err = mddev_lock(mddev);
	if (err) {
		printk(KERN_INFO 
@@ -7323,7 +7338,7 @@ void md_do_sync(struct md_thread *thread)
	sector_t last_check;
	int skipped = 0;
	struct md_rdev *rdev;
	char *desc;
	char *desc, *action = NULL;
	struct blk_plug plug;

	/* just incase thread restarts... */
@@ -7333,17 +7348,21 @@ void md_do_sync(struct md_thread *thread)
		return;

	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
		if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
		if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
			desc = "data-check";
		else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
			action = "check";
		} else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
			desc = "requested-resync";
		else
			action = "repair";
		} else
			desc = "resync";
	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
		desc = "reshape";
	else
		desc = "recovery";

	mddev->last_sync_action = action ?: desc;

	/* we overload curr_resync somewhat here.
	 * 0 == not engaged in resync at all
	 * 2 == checking that there is no conflict with another sync
@@ -7892,6 +7911,8 @@ void md_check_recovery(struct mddev *mddev)
			md_new_event(mddev);
		}
	unlock:
		wake_up(&mddev->sb_wait);

		if (!mddev->sync_thread) {
			clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
			if (test_and_clear_bit(MD_RECOVERY_RECOVER,
Loading