diff options
author | NeilBrown <neilb@suse.de> | 2006-01-06 03:21:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:34:10 -0500 |
commit | 88202a0c84e1951d6630d1d557d4801a8cc5b5ef (patch) | |
tree | 5a1aadc008de1ee68f40a4bb667157f248211230 | |
parent | 6d7ff7380b2e28c2807da3bf9fa614d91d15bacf (diff) |
[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>
-rw-r--r-- | Documentation/md.txt | 22 | ||||
-rw-r--r-- | drivers/md/md.c | 110 | ||||
-rw-r--r-- | include/linux/raid/md_k.h | 4 |
3 files changed, 131 insertions, 5 deletions
diff --git a/Documentation/md.txt b/Documentation/md.txt index b8d172b254f7..03a13c462cf2 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt | |||
@@ -207,6 +207,28 @@ All md devices contain: | |||
207 | available. It will then appear at md/dev-XXX (depending on the | 207 | available. It will then appear at md/dev-XXX (depending on the |
208 | name of the device) and further configuration is then possible. | 208 | name of the device) and further configuration is then possible. |
209 | 209 | ||
210 | sync_speed_min | ||
211 | sync_speed_max | ||
212 | This are similar to /proc/sys/dev/raid/speed_limit_{min,max} | ||
213 | however they only apply to the particular array. | ||
214 | If no value has been written to these, of if the word 'system' | ||
215 | is written, then the system-wide value is used. If a value, | ||
216 | in kibibytes-per-second is written, then it is used. | ||
217 | When the files are read, they show the currently active value | ||
218 | followed by "(local)" or "(system)" depending on whether it is | ||
219 | a locally set or system-wide value. | ||
220 | |||
221 | sync_completed | ||
222 | This shows the number of sectors that have been completed of | ||
223 | whatever the current sync_action is, followed by the number of | ||
224 | sectors in total that could need to be processed. The two | ||
225 | numbers are separated by a '/' thus effectively showing one | ||
226 | value, a fraction of the process that is complete. | ||
227 | |||
228 | sync_speed | ||
229 | This shows the current actual speed, in K/sec, of the current | ||
230 | sync_action. It is averaged over the last 30 seconds. | ||
231 | |||
210 | 232 | ||
211 | As component devices are added to an md array, they appear in the 'md' | 233 | As component devices are added to an md array, they appear in the 'md' |
212 | directory as new directories named | 234 | directory as new directories named |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 825e235b791b..1b76fb29fb70 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -81,10 +81,22 @@ static DEFINE_SPINLOCK(pers_lock); | |||
81 | * idle IO detection. | 81 | * idle IO detection. |
82 | * | 82 | * |
83 | * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. | 83 | * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. |
84 | * or /sys/block/mdX/md/sync_speed_{min,max} | ||
84 | */ | 85 | */ |
85 | 86 | ||
86 | static int sysctl_speed_limit_min = 1000; | 87 | static int sysctl_speed_limit_min = 1000; |
87 | static int sysctl_speed_limit_max = 200000; | 88 | static int sysctl_speed_limit_max = 200000; |
89 | static inline int speed_min(mddev_t *mddev) | ||
90 | { | ||
91 | return mddev->sync_speed_min ? | ||
92 | mddev->sync_speed_min : sysctl_speed_limit_min; | ||
93 | } | ||
94 | |||
95 | static inline int speed_max(mddev_t *mddev) | ||
96 | { | ||
97 | return mddev->sync_speed_max ? | ||
98 | mddev->sync_speed_max : sysctl_speed_limit_max; | ||
99 | } | ||
88 | 100 | ||
89 | static struct ctl_table_header *raid_table_header; | 101 | static struct ctl_table_header *raid_table_header; |
90 | 102 | ||
@@ -2197,6 +2209,90 @@ md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store); | |||
2197 | static struct md_sysfs_entry | 2209 | static struct md_sysfs_entry |
2198 | md_mismatches = __ATTR_RO(mismatch_cnt); | 2210 | md_mismatches = __ATTR_RO(mismatch_cnt); |
2199 | 2211 | ||
2212 | static ssize_t | ||
2213 | sync_min_show(mddev_t *mddev, char *page) | ||
2214 | { | ||
2215 | return sprintf(page, "%d (%s)\n", speed_min(mddev), | ||
2216 | mddev->sync_speed_min ? "local": "system"); | ||
2217 | } | ||
2218 | |||
2219 | static ssize_t | ||
2220 | sync_min_store(mddev_t *mddev, const char *buf, size_t len) | ||
2221 | { | ||
2222 | int min; | ||
2223 | char *e; | ||
2224 | if (strncmp(buf, "system", 6)==0) { | ||
2225 | mddev->sync_speed_min = 0; | ||
2226 | return len; | ||
2227 | } | ||
2228 | min = simple_strtoul(buf, &e, 10); | ||
2229 | if (buf == e || (*e && *e != '\n') || min <= 0) | ||
2230 | return -EINVAL; | ||
2231 | mddev->sync_speed_min = min; | ||
2232 | return len; | ||
2233 | } | ||
2234 | |||
2235 | static struct md_sysfs_entry md_sync_min = | ||
2236 | __ATTR(sync_speed_min, S_IRUGO|S_IWUSR, sync_min_show, sync_min_store); | ||
2237 | |||
2238 | static ssize_t | ||
2239 | sync_max_show(mddev_t *mddev, char *page) | ||
2240 | { | ||
2241 | return sprintf(page, "%d (%s)\n", speed_max(mddev), | ||
2242 | mddev->sync_speed_max ? "local": "system"); | ||
2243 | } | ||
2244 | |||
2245 | static ssize_t | ||
2246 | sync_max_store(mddev_t *mddev, const char *buf, size_t len) | ||
2247 | { | ||
2248 | int max; | ||
2249 | char *e; | ||
2250 | if (strncmp(buf, "system", 6)==0) { | ||
2251 | mddev->sync_speed_max = 0; | ||
2252 | return len; | ||
2253 | } | ||
2254 | max = simple_strtoul(buf, &e, 10); | ||
2255 | if (buf == e || (*e && *e != '\n') || max <= 0) | ||
2256 | return -EINVAL; | ||
2257 | mddev->sync_speed_max = max; | ||
2258 | return len; | ||
2259 | } | ||
2260 | |||
2261 | static struct md_sysfs_entry md_sync_max = | ||
2262 | __ATTR(sync_speed_max, S_IRUGO|S_IWUSR, sync_max_show, sync_max_store); | ||
2263 | |||
2264 | |||
2265 | static ssize_t | ||
2266 | sync_speed_show(mddev_t *mddev, char *page) | ||
2267 | { | ||
2268 | unsigned long resync, dt, db; | ||
2269 | resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active)); | ||
2270 | dt = ((jiffies - mddev->resync_mark) / HZ); | ||
2271 | if (!dt) dt++; | ||
2272 | db = resync - (mddev->resync_mark_cnt); | ||
2273 | return sprintf(page, "%ld\n", db/dt/2); /* K/sec */ | ||
2274 | } | ||
2275 | |||
2276 | static struct md_sysfs_entry | ||
2277 | md_sync_speed = __ATTR_RO(sync_speed); | ||
2278 | |||
2279 | static ssize_t | ||
2280 | sync_completed_show(mddev_t *mddev, char *page) | ||
2281 | { | ||
2282 | unsigned long max_blocks, resync; | ||
2283 | |||
2284 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) | ||
2285 | max_blocks = mddev->resync_max_sectors; | ||
2286 | else | ||
2287 | max_blocks = mddev->size << 1; | ||
2288 | |||
2289 | resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active)); | ||
2290 | return sprintf(page, "%lu / %lu\n", resync, max_blocks); | ||
2291 | } | ||
2292 | |||
2293 | static struct md_sysfs_entry | ||
2294 | md_sync_completed = __ATTR_RO(sync_completed); | ||
2295 | |||
2200 | static struct attribute *md_default_attrs[] = { | 2296 | static struct attribute *md_default_attrs[] = { |
2201 | &md_level.attr, | 2297 | &md_level.attr, |
2202 | &md_raid_disks.attr, | 2298 | &md_raid_disks.attr, |
@@ -2210,6 +2306,10 @@ static struct attribute *md_default_attrs[] = { | |||
2210 | static struct attribute *md_redundancy_attrs[] = { | 2306 | static struct attribute *md_redundancy_attrs[] = { |
2211 | &md_scan_mode.attr, | 2307 | &md_scan_mode.attr, |
2212 | &md_mismatches.attr, | 2308 | &md_mismatches.attr, |
2309 | &md_sync_min.attr, | ||
2310 | &md_sync_max.attr, | ||
2311 | &md_sync_speed.attr, | ||
2312 | &md_sync_completed.attr, | ||
2213 | NULL, | 2313 | NULL, |
2214 | }; | 2314 | }; |
2215 | static struct attribute_group md_redundancy_group = { | 2315 | static struct attribute_group md_redundancy_group = { |
@@ -4433,10 +4533,10 @@ static void md_do_sync(mddev_t *mddev) | |||
4433 | 4533 | ||
4434 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); | 4534 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); |
4435 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" | 4535 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" |
4436 | " %d KB/sec/disc.\n", sysctl_speed_limit_min); | 4536 | " %d KB/sec/disc.\n", speed_min(mddev)); |
4437 | printk(KERN_INFO "md: using maximum available idle IO bandwidth " | 4537 | printk(KERN_INFO "md: using maximum available idle IO bandwidth " |
4438 | "(but not more than %d KB/sec) for reconstruction.\n", | 4538 | "(but not more than %d KB/sec) for reconstruction.\n", |
4439 | sysctl_speed_limit_max); | 4539 | speed_max(mddev)); |
4440 | 4540 | ||
4441 | is_mddev_idle(mddev); /* this also initializes IO event counters */ | 4541 | is_mddev_idle(mddev); /* this also initializes IO event counters */ |
4442 | /* we don't use the checkpoint if there's a bitmap */ | 4542 | /* we don't use the checkpoint if there's a bitmap */ |
@@ -4477,7 +4577,7 @@ static void md_do_sync(mddev_t *mddev) | |||
4477 | 4577 | ||
4478 | skipped = 0; | 4578 | skipped = 0; |
4479 | sectors = mddev->pers->sync_request(mddev, j, &skipped, | 4579 | sectors = mddev->pers->sync_request(mddev, j, &skipped, |
4480 | currspeed < sysctl_speed_limit_min); | 4580 | currspeed < speed_min(mddev)); |
4481 | if (sectors == 0) { | 4581 | if (sectors == 0) { |
4482 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); | 4582 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); |
4483 | goto out; | 4583 | goto out; |
@@ -4542,8 +4642,8 @@ static void md_do_sync(mddev_t *mddev) | |||
4542 | currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2 | 4642 | currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2 |
4543 | /((jiffies-mddev->resync_mark)/HZ +1) +1; | 4643 | /((jiffies-mddev->resync_mark)/HZ +1) +1; |
4544 | 4644 | ||
4545 | if (currspeed > sysctl_speed_limit_min) { | 4645 | if (currspeed > speed_min(mddev)) { |
4546 | if ((currspeed > sysctl_speed_limit_max) || | 4646 | if ((currspeed > speed_max(mddev)) || |
4547 | !is_mddev_idle(mddev)) { | 4647 | !is_mddev_idle(mddev)) { |
4548 | msleep(500); | 4648 | msleep(500); |
4549 | goto repeat; | 4649 | goto repeat; |
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 68b929c079ab..617b9506c760 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h | |||
@@ -143,6 +143,10 @@ struct mddev_s | |||
143 | sector_t resync_mismatches; /* count of sectors where | 143 | sector_t resync_mismatches; /* count of sectors where |
144 | * parity/replica mismatch found | 144 | * parity/replica mismatch found |
145 | */ | 145 | */ |
146 | /* if zero, use the system-wide default */ | ||
147 | int sync_speed_min; | ||
148 | int sync_speed_max; | ||
149 | |||
146 | int ok_start_degraded; | 150 | int ok_start_degraded; |
147 | /* recovery/resync flags | 151 | /* recovery/resync flags |
148 | * NEEDED: we might need to start a resync/recover | 152 | * NEEDED: we might need to start a resync/recover |