diff options
Diffstat (limited to 'drivers/md/md.c')
| -rw-r--r-- | drivers/md/md.c | 110 |
1 files changed, 105 insertions, 5 deletions
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; |
