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

Commit 88202a0c authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[PATCH] md: allow sync-speed to be controlled per-device



Also export current (average) speed and status in sysfs.

Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Acked-by: default avatarGreg KH <greg@kroah.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6d7ff738
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -207,6 +207,28 @@ All md devices contain:
     available.  It will then appear at md/dev-XXX (depending on the
     name of the device) and further configuration is then possible.

   sync_speed_min
   sync_speed_max
     This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
     however they only apply to the particular array.
     If no value has been written to these, of if the word 'system'
     is written, then the system-wide value is used.  If a value,
     in kibibytes-per-second is written, then it is used.
     When the files are read, they show the currently active value
     followed by "(local)" or "(system)" depending on whether it is
     a locally set or system-wide value.

   sync_completed
     This shows the number of sectors that have been completed of
     whatever the current sync_action is, followed by the number of
     sectors in total that could need to be processed.  The two
     numbers are separated by a '/'  thus effectively showing one
     value, a fraction of the process that is complete.

   sync_speed
     This shows the current actual speed, in K/sec, of the current
     sync_action.  It is averaged over the last 30 seconds.


As component devices are added to an md array, they appear in the 'md'
directory as new directories named
+105 −5
Original line number Diff line number Diff line
@@ -81,10 +81,22 @@ static DEFINE_SPINLOCK(pers_lock);
 * idle IO detection.
 *
 * you can change it via /proc/sys/dev/raid/speed_limit_min and _max.
 * or /sys/block/mdX/md/sync_speed_{min,max}
 */

static int sysctl_speed_limit_min = 1000;
static int sysctl_speed_limit_max = 200000;
static inline int speed_min(mddev_t *mddev)
{
	return mddev->sync_speed_min ?
		mddev->sync_speed_min : sysctl_speed_limit_min;
}

static inline int speed_max(mddev_t *mddev)
{
	return mddev->sync_speed_max ?
		mddev->sync_speed_max : sysctl_speed_limit_max;
}

static struct ctl_table_header *raid_table_header;

@@ -2197,6 +2209,90 @@ 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
sync_min_show(mddev_t *mddev, char *page)
{
	return sprintf(page, "%d (%s)\n", speed_min(mddev),
		       mddev->sync_speed_min ? "local": "system");
}

static ssize_t
sync_min_store(mddev_t *mddev, const char *buf, size_t len)
{
	int min;
	char *e;
	if (strncmp(buf, "system", 6)==0) {
		mddev->sync_speed_min = 0;
		return len;
	}
	min = simple_strtoul(buf, &e, 10);
	if (buf == e || (*e && *e != '\n') || min <= 0)
		return -EINVAL;
	mddev->sync_speed_min = min;
	return len;
}

static struct md_sysfs_entry md_sync_min =
__ATTR(sync_speed_min, S_IRUGO|S_IWUSR, sync_min_show, sync_min_store);

static ssize_t
sync_max_show(mddev_t *mddev, char *page)
{
	return sprintf(page, "%d (%s)\n", speed_max(mddev),
		       mddev->sync_speed_max ? "local": "system");
}

static ssize_t
sync_max_store(mddev_t *mddev, const char *buf, size_t len)
{
	int max;
	char *e;
	if (strncmp(buf, "system", 6)==0) {
		mddev->sync_speed_max = 0;
		return len;
	}
	max = simple_strtoul(buf, &e, 10);
	if (buf == e || (*e && *e != '\n') || max <= 0)
		return -EINVAL;
	mddev->sync_speed_max = max;
	return len;
}

static struct md_sysfs_entry md_sync_max =
__ATTR(sync_speed_max, S_IRUGO|S_IWUSR, sync_max_show, sync_max_store);


static ssize_t
sync_speed_show(mddev_t *mddev, char *page)
{
	unsigned long resync, dt, db;
	resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active));
	dt = ((jiffies - mddev->resync_mark) / HZ);
	if (!dt) dt++;
	db = resync - (mddev->resync_mark_cnt);
	return sprintf(page, "%ld\n", db/dt/2); /* K/sec */
}

static struct md_sysfs_entry
md_sync_speed = __ATTR_RO(sync_speed);

static ssize_t
sync_completed_show(mddev_t *mddev, char *page)
{
	unsigned long max_blocks, resync;

	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
		max_blocks = mddev->resync_max_sectors;
	else
		max_blocks = mddev->size << 1;

	resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active));
	return sprintf(page, "%lu / %lu\n", resync, max_blocks);
}

static struct md_sysfs_entry
md_sync_completed = __ATTR_RO(sync_completed);

static struct attribute *md_default_attrs[] = {
	&md_level.attr,
	&md_raid_disks.attr,
@@ -2210,6 +2306,10 @@ static struct attribute *md_default_attrs[] = {
static struct attribute *md_redundancy_attrs[] = {
	&md_scan_mode.attr,
	&md_mismatches.attr,
	&md_sync_min.attr,
	&md_sync_max.attr,
	&md_sync_speed.attr,
	&md_sync_completed.attr,
	NULL,
};
static struct attribute_group md_redundancy_group = {
@@ -4433,10 +4533,10 @@ static void md_do_sync(mddev_t *mddev)

	printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
		" %d KB/sec/disc.\n", sysctl_speed_limit_min);
		" %d KB/sec/disc.\n", speed_min(mddev));
	printk(KERN_INFO "md: using maximum available idle IO bandwidth "
	       "(but not more than %d KB/sec) for reconstruction.\n",
	       sysctl_speed_limit_max);
	       speed_max(mddev));

	is_mddev_idle(mddev); /* this also initializes IO event counters */
	/* we don't use the checkpoint if there's a bitmap */
@@ -4477,7 +4577,7 @@ static void md_do_sync(mddev_t *mddev)

		skipped = 0;
		sectors = mddev->pers->sync_request(mddev, j, &skipped,
					    currspeed < sysctl_speed_limit_min);
					    currspeed < speed_min(mddev));
		if (sectors == 0) {
			set_bit(MD_RECOVERY_ERR, &mddev->recovery);
			goto out;
@@ -4542,8 +4642,8 @@ static void md_do_sync(mddev_t *mddev)
		currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
			/((jiffies-mddev->resync_mark)/HZ +1) +1;

		if (currspeed > sysctl_speed_limit_min) {
			if ((currspeed > sysctl_speed_limit_max) ||
		if (currspeed > speed_min(mddev)) {
			if ((currspeed > speed_max(mddev)) ||
					!is_mddev_idle(mddev)) {
				msleep(500);
				goto repeat;
+4 −0
Original line number Diff line number Diff line
@@ -143,6 +143,10 @@ struct mddev_s
	sector_t			resync_mismatches; /* count of sectors where
							    * parity/replica mismatch found
							    */
	/* if zero, use the system-wide default */
	int				sync_speed_min;
	int				sync_speed_max;

	int				ok_start_degraded;
	/* recovery/resync flags 
	 * NEEDED:   we might need to start a resync/recover