mirror of https://gitee.com/openkylin/linux.git
[PATCH] md: allow sync-speed to be controlled per-device
Also export current (average) speed and status in sysfs. Signed-off-by: Neil Brown <neilb@suse.de> Acked-by: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
6d7ff7380b
commit
88202a0c84
|
@ -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
|
||||||
|
|
110
drivers/md/md.c
110
drivers/md/md.c
|
@ -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);
|
||||||
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[] = {
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue