summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-05-21 09:42:26 +1000
committerNeilBrown <neilb@suse.de>2012-05-21 09:42:26 +1000
commit2c01e1d859afa61402d3deadd45001ed26be90ce (patch)
treef61c6d3d87cea810b151feda9f92890ac810b641
parent21f2f2235301ced5f3192f2b39e370762e82ab9d (diff)
downloadmdadm-2c01e1d859afa61402d3deadd45001ed26be90ce.tar.gz
Add space_before/space_after fields to mdinfo
These will be needed to guide changes to data_offset during reshape. Only set them for super1 for now. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--mdadm.h8
-rw-r--r--super1.c36
2 files changed, 43 insertions, 1 deletions
diff --git a/mdadm.h b/mdadm.h
index c3f6126..67eb9ce 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -206,6 +206,12 @@ struct mdinfo {
* for native metadata it is
* reshape_active field mirror
*/
+ /* During reshape we can sometimes change the data_offset to avoid
+ * over-writing still-valid data. We need to know if there is space.
+ * So getinfo_super will fill in space_before and space_after in sectors.
+ * data_offset can be increased or decreased by this amount.
+ */
+ unsigned long long space_before, space_after;
union {
unsigned long long resync_start; /* per-array resync position */
unsigned long long recovery_start; /* per-device rebuild position */
@@ -547,7 +553,7 @@ struct active_array;
struct metadata_update;
-/* 'struct reshape' records the intermediate states
+/* 'struct reshape' records the intermediate states of
* a general reshape.
* The starting geometry is converted to the 'before' geometry
* by at most an atomic level change. They could be the same.
diff --git a/super1.c b/super1.c
index 3b4ec20..94b6c7f 100644
--- a/super1.c
+++ b/super1.c
@@ -621,10 +621,14 @@ static void uuid_from_super1(struct supertype *st, int uuid[4])
static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
{
struct mdp_superblock_1 *sb = st->sb;
+ struct bitmap_super_s *bsb = (void*)(((char*)sb)+MAX_SB_SIZE);
+ struct misc_dev_info *misc = (void*)(((char*)sb)+MAX_SB_SIZE+BM_SUPER_SIZE);
int working = 0;
unsigned int i;
unsigned int role;
unsigned int map_disks = info->array.raid_disks;
+ unsigned long long super_offset;
+ unsigned long long data_size;
memset(info, 0, sizeof(*info));
info->array.major_version = 1;
@@ -655,6 +659,38 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
else
role = __le16_to_cpu(sb->dev_roles[__le32_to_cpu(sb->dev_number)]);
+ super_offset = __le64_to_cpu(sb->super_offset);
+ data_size = __le64_to_cpu(sb->size);
+ if (info->data_offset < super_offset) {
+ unsigned long long end;
+ info->space_before = info->data_offset;
+ end = super_offset;
+ if (info->bitmap_offset < 0)
+ end += info->bitmap_offset;
+ if (info->data_offset + data_size < end)
+ info->space_after = end - data_size - info->data_offset;
+ else
+ info->space_after = 0;
+ } else {
+ info->space_before = (info->data_offset -
+ super_offset);
+ if (info->bitmap_offset > 0) {
+ unsigned long long bmend = info->bitmap_offset;
+ unsigned long long size = __le64_to_cpu(bsb->sync_size);
+ size /= __le32_to_cpu(bsb->chunksize) >> 9;
+ size = (size + 7) >> 3;
+ size += sizeof(bitmap_super_t);
+ size = ROUND_UP(size, 4096);
+ size /= 512;
+ size += bmend;
+ if (size < info->space_before)
+ info->space_before -= size;
+ else
+ info->space_before = 0;
+ }
+ info->space_after = misc->device_size - data_size - info->data_offset;
+ }
+
info->disk.raid_disk = -1;
switch(role) {
case 0xFFFF: