Commit 08a02ecd authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

md: allow reshape_position for md arrays to be set via sysfs

"reshape_position" records how much progress has been made on a "reshape"
(adding drives, changing layout or chunksize).

When it is set, the number of drives, layout and chunksize can have
two possible values, an old an a new.

So allow these different values to be visible, and allow both old and new to
be set: Set the old ones first, then the reshape_position, then the new
values.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 42b9bebe
...@@ -178,6 +178,21 @@ All md devices contain: ...@@ -178,6 +178,21 @@ All md devices contain:
The size should be at least PAGE_SIZE (4k) and should be a power The size should be at least PAGE_SIZE (4k) and should be a power
of 2. This can only be set while assembling an array of 2. This can only be set while assembling an array
layout
The "layout" for the array for the particular level. This is
simply a number that is interpretted differently by different
levels. It can be written while assembling an array.
reshape_position
This is either "none" or a sector number within the devices of
the array where "reshape" is up to. If this is set, the three
attributes mentioned above (raid_disks, chunk_size, layout) can
potentially have 2 values, an old and a new value. If these
values differ, reading the attribute returns
new (old)
and writing will effect the 'new' value, leaving the 'old'
unchanged.
component_size component_size
For arrays with data redundancy (i.e. not raid0, linear, faulty, For arrays with data redundancy (i.e. not raid0, linear, faulty,
multipath), all components must be the same size - or at least multipath), all components must be the same size - or at least
...@@ -193,11 +208,6 @@ All md devices contain: ...@@ -193,11 +208,6 @@ All md devices contain:
1.2 (newer format in varying locations) or "none" indicating that 1.2 (newer format in varying locations) or "none" indicating that
the kernel isn't managing metadata at all. the kernel isn't managing metadata at all.
layout
The "layout" for the array for the particular level. This is
simply a number that is interpretted differently by different
levels. It can be written while assembling an array.
resync_start resync_start
The point at which resync should start. If no resync is needed, The point at which resync should start. If no resync is needed,
this will be a very large number. At array creation it will this will be a very large number. At array creation it will
...@@ -259,29 +269,6 @@ All md devices contain: ...@@ -259,29 +269,6 @@ All md devices contain:
like active, but no writes have been seen for a while (safe_mode_delay). like active, but no writes have been seen for a while (safe_mode_delay).
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
dev-XXX dev-XXX
...@@ -412,6 +399,35 @@ also have ...@@ -412,6 +399,35 @@ also have
Note that the numbers are 'bit' numbers, not 'block' numbers. Note that the numbers are 'bit' numbers, not 'block' numbers.
They should be scaled by the bitmap_chunksize. They should be scaled by the bitmap_chunksize.
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.
suspend_lo
suspend_hi
The two values, given as numbers of sectors, indicate a range
within the array where IO will be blocked. This is currently
only supported for raid4/5/6.
Each active md device may also have attributes specific to the Each active md device may also have attributes specific to the
personality module that manages it. personality module that manages it.
These are specific to the implementation of the module and could These are specific to the implementation of the module and could
......
...@@ -274,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit) ...@@ -274,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit)
atomic_set(&new->active, 1); atomic_set(&new->active, 1);
spin_lock_init(&new->write_lock); spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait); init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
new->queue = blk_alloc_queue(GFP_KERNEL); new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) { if (!new->queue) {
...@@ -2242,6 +2243,10 @@ static ssize_t ...@@ -2242,6 +2243,10 @@ static ssize_t
layout_show(mddev_t *mddev, char *page) layout_show(mddev_t *mddev, char *page)
{ {
/* just a number, not meaningful for all levels */ /* just a number, not meaningful for all levels */
if (mddev->reshape_position != MaxSector &&
mddev->layout != mddev->new_layout)
return sprintf(page, "%d (%d)\n",
mddev->new_layout, mddev->layout);
return sprintf(page, "%d\n", mddev->layout); return sprintf(page, "%d\n", mddev->layout);
} }
...@@ -2250,12 +2255,15 @@ layout_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -2250,12 +2255,15 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
{ {
char *e; char *e;
unsigned long n = simple_strtoul(buf, &e, 10); unsigned long n = simple_strtoul(buf, &e, 10);
if (mddev->pers)
return -EBUSY;
if (!*buf || (*e && *e != '\n')) if (!*buf || (*e && *e != '\n'))
return -EINVAL; return -EINVAL;
if (mddev->pers)
return -EBUSY;
if (mddev->reshape_position != MaxSector)
mddev->new_layout = n;
else
mddev->layout = n; mddev->layout = n;
return len; return len;
} }
...@@ -2268,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page) ...@@ -2268,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page)
{ {
if (mddev->raid_disks == 0) if (mddev->raid_disks == 0)
return 0; return 0;
if (mddev->reshape_position != MaxSector &&
mddev->delta_disks != 0)
return sprintf(page, "%d (%d)\n", mddev->raid_disks,
mddev->raid_disks - mddev->delta_disks);
return sprintf(page, "%d\n", mddev->raid_disks); return sprintf(page, "%d\n", mddev->raid_disks);
} }
...@@ -2285,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -2285,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
if (mddev->pers) if (mddev->pers)
rv = update_raid_disks(mddev, n); rv = update_raid_disks(mddev, n);
else else if (mddev->reshape_position != MaxSector) {
int olddisks = mddev->raid_disks - mddev->delta_disks;
mddev->delta_disks = n - olddisks;
mddev->raid_disks = n;
} else
mddev->raid_disks = n; mddev->raid_disks = n;
return rv ? rv : len; return rv ? rv : len;
} }
...@@ -2295,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store); ...@@ -2295,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
static ssize_t static ssize_t
chunk_size_show(mddev_t *mddev, char *page) chunk_size_show(mddev_t *mddev, char *page)
{ {
if (mddev->reshape_position != MaxSector &&
mddev->chunk_size != mddev->new_chunk)
return sprintf(page, "%d (%d)\n", mddev->new_chunk,
mddev->chunk_size);
return sprintf(page, "%d\n", mddev->chunk_size); return sprintf(page, "%d\n", mddev->chunk_size);
} }
...@@ -2305,11 +2325,14 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -2305,11 +2325,14 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
char *e; char *e;
unsigned long n = simple_strtoul(buf, &e, 10); unsigned long n = simple_strtoul(buf, &e, 10);
if (mddev->pers)
return -EBUSY;
if (!*buf || (*e && *e != '\n')) if (!*buf || (*e && *e != '\n'))
return -EINVAL; return -EINVAL;
if (mddev->pers)
return -EBUSY;
else if (mddev->reshape_position != MaxSector)
mddev->new_chunk = n;
else
mddev->chunk_size = n; mddev->chunk_size = n;
return len; return len;
} }
...@@ -2896,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -2896,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
static struct md_sysfs_entry md_suspend_hi = static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
static ssize_t
reshape_position_show(mddev_t *mddev, char *page)
{
if (mddev->reshape_position != MaxSector)
return sprintf(page, "%llu\n",
(unsigned long long)mddev->reshape_position);
strcpy(page, "none\n");
return 5;
}
static ssize_t
reshape_position_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
if (mddev->pers)
return -EBUSY;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
mddev->reshape_position = new;
mddev->delta_disks = 0;
mddev->new_level = mddev->level;
mddev->new_layout = mddev->layout;
mddev->new_chunk = mddev->chunk_size;
return len;
}
static struct md_sysfs_entry md_reshape_position =
__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
reshape_position_store);
static struct attribute *md_default_attrs[] = { static struct attribute *md_default_attrs[] = {
&md_level.attr, &md_level.attr,
...@@ -2908,6 +2962,7 @@ static struct attribute *md_default_attrs[] = { ...@@ -2908,6 +2962,7 @@ static struct attribute *md_default_attrs[] = {
&md_new_device.attr, &md_new_device.attr,
&md_safe_delay.attr, &md_safe_delay.attr,
&md_array_state.attr, &md_array_state.attr,
&md_reshape_position.attr,
NULL, NULL,
}; };
...@@ -3446,6 +3501,7 @@ static int do_md_stop(mddev_t * mddev, int mode) ...@@ -3446,6 +3501,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->reshape_position = MaxSector;
} else if (mddev->pers) } else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n", printk(KERN_INFO "md: %s switched to read-only mode.\n",
......
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