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

[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
...@@ -207,6 +207,28 @@ All md devices contain: ...@@ -207,6 +207,28 @@ All md devices contain:
available. It will then appear at md/dev-XXX (depending on the available. It will then appear at md/dev-XXX (depending on the
name of the device) and further configuration is then possible. 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' As component devices are added to an md array, they appear in the 'md'
directory as new directories named directory as new directories named
......
...@@ -81,10 +81,22 @@ static DEFINE_SPINLOCK(pers_lock); ...@@ -81,10 +81,22 @@ static DEFINE_SPINLOCK(pers_lock);
* idle IO detection. * idle IO detection.
* *
* you can change it via /proc/sys/dev/raid/speed_limit_min and _max. * 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_min = 1000;
static int sysctl_speed_limit_max = 200000; 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; 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); ...@@ -2197,6 +2209,90 @@ md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
static struct md_sysfs_entry static struct md_sysfs_entry
md_mismatches = __ATTR_RO(mismatch_cnt); 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[] = { static struct attribute *md_default_attrs[] = {
&md_level.attr, &md_level.attr,
&md_raid_disks.attr, &md_raid_disks.attr,
...@@ -2210,6 +2306,10 @@ static struct attribute *md_default_attrs[] = { ...@@ -2210,6 +2306,10 @@ static struct attribute *md_default_attrs[] = {
static struct attribute *md_redundancy_attrs[] = { static struct attribute *md_redundancy_attrs[] = {
&md_scan_mode.attr, &md_scan_mode.attr,
&md_mismatches.attr, &md_mismatches.attr,
&md_sync_min.attr,
&md_sync_max.attr,
&md_sync_speed.attr,
&md_sync_completed.attr,
NULL, NULL,
}; };
static struct attribute_group md_redundancy_group = { static struct attribute_group md_redundancy_group = {
...@@ -4433,10 +4533,10 @@ static void md_do_sync(mddev_t *mddev) ...@@ -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: syncing RAID array %s\n", mdname(mddev));
printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" 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 " printk(KERN_INFO "md: using maximum available idle IO bandwidth "
"(but not more than %d KB/sec) for reconstruction.\n", "(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 */ is_mddev_idle(mddev); /* this also initializes IO event counters */
/* we don't use the checkpoint if there's a bitmap */ /* we don't use the checkpoint if there's a bitmap */
...@@ -4477,7 +4577,7 @@ static void md_do_sync(mddev_t *mddev) ...@@ -4477,7 +4577,7 @@ static void md_do_sync(mddev_t *mddev)
skipped = 0; skipped = 0;
sectors = mddev->pers->sync_request(mddev, j, &skipped, sectors = mddev->pers->sync_request(mddev, j, &skipped,
currspeed < sysctl_speed_limit_min); currspeed < speed_min(mddev));
if (sectors == 0) { if (sectors == 0) {
set_bit(MD_RECOVERY_ERR, &mddev->recovery); set_bit(MD_RECOVERY_ERR, &mddev->recovery);
goto out; goto out;
...@@ -4542,8 +4642,8 @@ static void md_do_sync(mddev_t *mddev) ...@@ -4542,8 +4642,8 @@ static void md_do_sync(mddev_t *mddev)
currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2 currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
/((jiffies-mddev->resync_mark)/HZ +1) +1; /((jiffies-mddev->resync_mark)/HZ +1) +1;
if (currspeed > sysctl_speed_limit_min) { if (currspeed > speed_min(mddev)) {
if ((currspeed > sysctl_speed_limit_max) || if ((currspeed > speed_max(mddev)) ||
!is_mddev_idle(mddev)) { !is_mddev_idle(mddev)) {
msleep(500); msleep(500);
goto repeat; goto repeat;
......
...@@ -143,6 +143,10 @@ struct mddev_s ...@@ -143,6 +143,10 @@ struct mddev_s
sector_t resync_mismatches; /* count of sectors where sector_t resync_mismatches; /* count of sectors where
* parity/replica mismatch found * parity/replica mismatch found
*/ */
/* if zero, use the system-wide default */
int sync_speed_min;
int sync_speed_max;
int ok_start_degraded; int ok_start_degraded;
/* recovery/resync flags /* recovery/resync flags
* NEEDED: we might need to start a resync/recover * NEEDED: we might need to start a resync/recover
......
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