Commit 5e96ee65 authored by Neil Brown's avatar Neil Brown

Allow setting start point for requested check/repair

This makes it possible to just resync a small part of an array.
e.g. if a drive reports that it has questionable sectors,
a 'repair' of just the region covering those sectors will
cause them to be read and, if there is an error, re-written
with correct data.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
parent a0da84f3
...@@ -278,6 +278,7 @@ static mddev_t * mddev_find(dev_t unit) ...@@ -278,6 +278,7 @@ static mddev_t * mddev_find(dev_t unit)
init_waitqueue_head(&new->sb_wait); init_waitqueue_head(&new->sb_wait);
init_waitqueue_head(&new->recovery_wait); init_waitqueue_head(&new->recovery_wait);
new->reshape_position = MaxSector; new->reshape_position = MaxSector;
new->resync_min = 0;
new->resync_max = MaxSector; new->resync_max = MaxSector;
new->level = LEVEL_NONE; new->level = LEVEL_NONE;
...@@ -3074,6 +3075,36 @@ sync_completed_show(mddev_t *mddev, char *page) ...@@ -3074,6 +3075,36 @@ sync_completed_show(mddev_t *mddev, char *page)
static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed); static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
min_sync_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n",
(unsigned long long)mddev->resync_min);
}
static ssize_t
min_sync_store(mddev_t *mddev, const char *buf, size_t len)
{
unsigned long long min;
if (strict_strtoull(buf, 10, &min))
return -EINVAL;
if (min > mddev->resync_max)
return -EINVAL;
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
/* Must be a multiple of chunk_size */
if (mddev->chunk_size) {
if (min & (sector_t)((mddev->chunk_size>>9)-1))
return -EINVAL;
}
mddev->resync_min = min;
return len;
}
static struct md_sysfs_entry md_min_sync =
__ATTR(sync_min, S_IRUGO|S_IWUSR, min_sync_show, min_sync_store);
static ssize_t static ssize_t
max_sync_show(mddev_t *mddev, char *page) max_sync_show(mddev_t *mddev, char *page)
{ {
...@@ -3089,9 +3120,10 @@ max_sync_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -3089,9 +3120,10 @@ max_sync_store(mddev_t *mddev, const char *buf, size_t len)
if (strncmp(buf, "max", 3) == 0) if (strncmp(buf, "max", 3) == 0)
mddev->resync_max = MaxSector; mddev->resync_max = MaxSector;
else { else {
char *ep; unsigned long long max;
unsigned long long max = simple_strtoull(buf, &ep, 10); if (strict_strtoull(buf, 10, &max))
if (ep == buf || (*ep != 0 && *ep != '\n')) return -EINVAL;
if (max < mddev->resync_min)
return -EINVAL; return -EINVAL;
if (max < mddev->resync_max && if (max < mddev->resync_max &&
test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
...@@ -3222,6 +3254,7 @@ static struct attribute *md_redundancy_attrs[] = { ...@@ -3222,6 +3254,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_sync_speed.attr, &md_sync_speed.attr,
&md_sync_force_parallel.attr, &md_sync_force_parallel.attr,
&md_sync_completed.attr, &md_sync_completed.attr,
&md_min_sync.attr,
&md_max_sync.attr, &md_max_sync.attr,
&md_suspend_lo.attr, &md_suspend_lo.attr,
&md_suspend_hi.attr, &md_suspend_hi.attr,
...@@ -3777,6 +3810,7 @@ static int do_md_stop(mddev_t * mddev, int mode) ...@@ -3777,6 +3810,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->size = 0; mddev->size = 0;
mddev->raid_disks = 0; mddev->raid_disks = 0;
mddev->recovery_cp = 0; mddev->recovery_cp = 0;
mddev->resync_min = 0;
mddev->resync_max = MaxSector; mddev->resync_max = MaxSector;
mddev->reshape_position = MaxSector; mddev->reshape_position = MaxSector;
mddev->external = 0; mddev->external = 0;
...@@ -5625,9 +5659,11 @@ void md_do_sync(mddev_t *mddev) ...@@ -5625,9 +5659,11 @@ void md_do_sync(mddev_t *mddev)
max_sectors = mddev->resync_max_sectors; max_sectors = mddev->resync_max_sectors;
mddev->resync_mismatches = 0; mddev->resync_mismatches = 0;
/* we don't use the checkpoint if there's a bitmap */ /* we don't use the checkpoint if there's a bitmap */
if (!mddev->bitmap && if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) j = mddev->resync_min;
else if (!mddev->bitmap)
j = mddev->recovery_cp; j = mddev->recovery_cp;
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->size << 1; max_sectors = mddev->size << 1;
else { else {
...@@ -5796,6 +5832,7 @@ void md_do_sync(mddev_t *mddev) ...@@ -5796,6 +5832,7 @@ void md_do_sync(mddev_t *mddev)
skip: skip:
mddev->curr_resync = 0; mddev->curr_resync = 0;
mddev->resync_min = 0;
mddev->resync_max = MaxSector; mddev->resync_max = MaxSector;
sysfs_notify(&mddev->kobj, NULL, "sync_completed"); sysfs_notify(&mddev->kobj, NULL, "sync_completed");
wake_up(&resync_wait); wake_up(&resync_wait);
......
...@@ -227,6 +227,8 @@ struct mddev_s ...@@ -227,6 +227,8 @@ struct mddev_s
atomic_t recovery_active; /* blocks scheduled, but not written */ atomic_t recovery_active; /* blocks scheduled, but not written */
wait_queue_head_t recovery_wait; wait_queue_head_t recovery_wait;
sector_t recovery_cp; sector_t recovery_cp;
sector_t resync_min; /* user requested sync
* starts here */
sector_t resync_max; /* resync should pause sector_t resync_max; /* resync should pause
* when it gets here */ * when it gets here */
......
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