From 2a528478c75b6659188fc2ce0d9543124992fe6c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 13 Oct 2008 16:15:16 +1100 Subject: [PATCH 1/4] Manage: allow adding device that is just large enough to v1.x array. When adding a device to an array, we check that it is large enough. Currently the check makes sure there is also room for a reasonably sized bitmap. But if the array doesn't have a bitmap, then this test might be too restrictive. So when adding, only insist there is enough space for the current bitmap. When Creating, still require room for the standard sized bitmap. This resolved Debian Bug 500309 --- Manage.c | 17 +++++++++-------- bitmap.c | 9 +++++++++ mdadm.h | 1 + super1.c | 13 ++++++++++++- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Manage.c b/Manage.c index 8297708..7b3fabe 100644 --- a/Manage.c +++ b/Manage.c @@ -349,14 +349,6 @@ int Manage_subdevs(char *devname, int fd, if (array.not_persistent == 0) { - /* Make sure device is large enough */ - if (tst->ss->avail_size(tst, ldsize/512) < - array_size) { - fprintf(stderr, Name ": %s not large enough to join array\n", - dv->devname); - return 1; - } - /* need to find a sample superblock to copy, and * a spare slot to use */ @@ -386,6 +378,15 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); return 1; } + + /* Make sure device is large enough */ + if (tst->ss->avail_size(tst, ldsize/512) < + array_size) { + fprintf(stderr, Name ": %s not large enough to join array\n", + dv->devname); + return 1; + } + /* Possibly this device was recently part of the array * and was temporarily removed, and is now being re-added. * If so, we can simply re-add it. diff --git a/bitmap.c b/bitmap.c index fdf8884..b647939 100644 --- a/bitmap.c +++ b/bitmap.c @@ -115,6 +115,15 @@ unsigned long long bitmap_bits(unsigned long long array_size, return (array_size * 512 + chunksize - 1) / chunksize; } +unsigned long bitmap_sectors(struct bitmap_super_s *bsb) +{ + unsigned long long bits = bitmap_bits(__le64_to_cpu(bsb->sync_size), + __le32_to_cpu(bsb->chunksize)); + int bits_per_sector = 8*512; + return (bits + bits_per_sector - 1) / bits_per_sector; +} + + bitmap_info_t *bitmap_fd_read(int fd, int brief) { /* Note: fd might be open O_DIRECT, so we must be diff --git a/mdadm.h b/mdadm.h index 5c18d15..ce140e5 100644 --- a/mdadm.h +++ b/mdadm.h @@ -474,6 +474,7 @@ extern int CreateBitmap(char *filename, int force, char uuid[16], int major); extern int ExamineBitmap(char *filename, int brief, struct supertype *st); extern int bitmap_update_uuid(int fd, int *uuid, int swap); +extern unsigned long bitmap_sectors(struct bitmap_super_s *bsb); extern int md_get_version(int fd); extern int get_linux_version(void); diff --git a/super1.c b/super1.c index fe915f8..e1d0219 100644 --- a/super1.c +++ b/super1.c @@ -1214,10 +1214,21 @@ static struct supertype *match_metadata_desc1(char *arg) */ static __u64 avail_size1(struct supertype *st, __u64 devsize) { + struct mdp_superblock_1 *super = st->sb; if (devsize < 24) return 0; - devsize -= choose_bm_space(devsize); + if (super == NULL) + /* creating: allow suitable space for bitmap */ + devsize -= choose_bm_space(devsize); +#ifndef MDASSEMBLE + else if (__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) { + /* hot-add. allow for actual size of bitmap */ + struct bitmap_super_s *bsb; + bsb = (struct bitmap_super_s *)(((char*)super)+1024); + devsize -= bitmap_sectors(bsb); + } +#endif switch(st->minor_version) { case -1: /* no specified. Now time to set default */ From e4965ef8461b3d0db6e94939f07d814d819f86c2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 13 Oct 2008 16:15:18 +1100 Subject: [PATCH 2/4] Improve reporting of layout for raid10. Showing e.g. near=1, far=2 for the 'far2' layout of raid10 is confusing even though there is a sense in which is it correct. Make it less confusing by only printing whichever number is not 1. If both are 1, make that clear too (i.e. no redundancy). --- Detail.c | 6 +++--- mdadm.h | 3 ++- super0.c | 7 +++---- super1.c | 14 ++++++-------- util.c | 17 +++++++++++++++++ 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/Detail.c b/Detail.c index 2b2111c..25b91b1 100644 --- a/Detail.c +++ b/Detail.c @@ -239,9 +239,9 @@ int Detail(char *dev, int brief, int export, int test, char *homehost) printf(" Layout : %s\n", c?c:"-unknown-"); } if (array.level == 10) { - printf(" Layout : near=%d, %s=%d\n", - array.layout&255, (array.layout&0x10000)?"offset":"far", - (array.layout>>8)&255); + printf(" Layout :"); + print_r10_layout(array.layout); + printf("\n"); } switch (array.level) { case 0: diff --git a/mdadm.h b/mdadm.h index ce140e5..174ea39 100644 --- a/mdadm.h +++ b/mdadm.h @@ -513,7 +513,8 @@ extern void remove_partitions(int fd); extern char *human_size(long long bytes); -char *human_size_brief(long long bytes); +extern char *human_size_brief(long long bytes); +extern void print_r10_layout(int layout); #define NoMdDev (1<<23) extern int find_free_devnum(int use_partitions); diff --git a/super0.c b/super0.c index 8e4c568..71dc39c 100644 --- a/super0.c +++ b/super0.c @@ -188,10 +188,9 @@ static void examine_super0(struct supertype *st, char *homehost) printf(" Layout : %s\n", c?c:"-unknown-"); } if (sb->level == 10) { - printf(" Layout : near=%d, %s=%d\n", - sb->layout&255, - (sb->layout&0x10000)?"offset":"far", - (sb->layout>>8)&255); + printf(" Layout :"); + print_r10_layout(sb->layout); + printf("\n"); } switch(sb->level) { case 0: diff --git a/super1.c b/super1.c index e1d0219..bec0c5e 100644 --- a/super1.c +++ b/super1.c @@ -248,10 +248,9 @@ static void examine_super1(struct supertype *st, char *homehost) printf(" New Layout : %s\n", c?c:"-unknown-"); } if (__le32_to_cpu(sb->level) == 10) { - printf(" New Layout : near=%d, %s=%d\n", - __le32_to_cpu(sb->new_layout)&255, - (__le32_to_cpu(sb->new_layout)&0x10000)?"offset":"far", - (__le32_to_cpu(sb->new_layout)>>8)&255); + printf(" New Layout :"); + print_r10_layout(__le32_to_cpu(sb->new_layout)); + printf("\n"); } } if (__le32_to_cpu(sb->new_chunk) != __le32_to_cpu(sb->chunksize)) @@ -281,10 +280,9 @@ static void examine_super1(struct supertype *st, char *homehost) } if (__le32_to_cpu(sb->level) == 10) { int lo = __le32_to_cpu(sb->layout); - printf(" Layout : near=%d, %s=%d\n", - lo&255, - (lo&0x10000)?"offset":"far", - (lo>>8)&255); + printf(" Layout :"); + print_r10_layout(lo); + printf("\n"); } switch(__le32_to_cpu(sb->level)) { case 0: diff --git a/util.c b/util.c index 75f3706..2d51de0 100644 --- a/util.c +++ b/util.c @@ -606,6 +606,23 @@ char *human_size_brief(long long bytes) ); return buf; } + +void print_r10_layout(int layout) +{ + int near = layout & 255; + int far = (layout >> 8) & 255; + int offset = (layout&0x10000); + char *sep = ""; + + if (near != 1) { + printf("%s near=%d", sep, near); + sep = ","; + } + if (far != 1) + printf("%s %s=%d", sep, offset?"offset":"far", far); + if (near*far == 1) + printf("NO REDUNDANCY"); +} #endif #if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) From 1c6cb603fa60d3425f4d4b76e721b485bb006fcb Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 15 Oct 2008 14:34:18 +1100 Subject: [PATCH 3/4] Grow: Fix linear-growth when devices are not all the same size. If we add a device to a linear array which is a difference size to the other devices in the array then, for v1.x metadata, we need to make sure the size is correctly reflected in the superblock. --- super1.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/super1.c b/super1.c index bec0c5e..62a3ab9 100644 --- a/super1.c +++ b/super1.c @@ -599,7 +599,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info, } if (strcmp(update, "linear-grow-new") == 0) { int i; - int rfd; + int rfd, fd; int max = __le32_to_cpu(sb->max_dev); for (i=0 ; i < max ; i++) @@ -620,6 +620,25 @@ static int update_super1(struct supertype *st, struct mdinfo *info, sb->dev_roles[i] = __cpu_to_le16(info->disk.raid_disk); + + fd = open(devname, O_RDONLY); + if (fd >= 0) { + unsigned long long ds; + get_dev_size(fd, devname, &ds); + close(fd); + ds >>= 9; + if (__le64_to_cpu(sb->super_offset) < + __le64_to_cpu(sb->data_offset)) { + sb->data_size = __cpu_to_le64( + ds - __le64_to_cpu(sb->data_offset)); + } else { + ds -= 8*2; + ds &= ~(unsigned long long)(4*2-1); + sb->super_offset = __cpu_to_le64(ds); + sb->data_size = __cpu_to_le64( + ds - __le64_to_cpu(sb->data_offset)); + } + } } if (strcmp(update, "linear-grow-update") == 0) { sb->raid_disks = __cpu_to_le32(info->array.raid_disks); From 11cd8b79c0690bf39b40a25352f86a82a838622a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 17 Oct 2008 11:52:38 +1100 Subject: [PATCH 4/4] Remove .UR .UE macros from man page because the don't do what we want. .UR URL text .UE is meant to create a hyperlink from the 'text' to the 'URL'. But I wanted just to have the URL, so UR isn't really the right tool - the URL gets displayed twice. So just display the URL in bold and assume man2html etc can recognise it and do the right thing. Signed-off-by: NeilBrown --- mdadm.8 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/mdadm.8 b/mdadm.8 index be8568d..d26da80 100644 --- a/mdadm.8 +++ b/mdadm.8 @@ -2115,11 +2115,8 @@ configuration file at all. .SH SEE ALSO For further information on mdadm usage, MD and the various levels of RAID, see: - .IP -.UR http://linux-raid.osdl.org/ -http://linux\-raid.osdl.org/ -.UE +.B http://linux\-raid.osdl.org/ .PP (based upon Jakob \(/Ostergaard's Software\-RAID.HOWTO) .\".PP @@ -2140,9 +2137,9 @@ The latest version of .I mdadm should always be available from .IP -.UR http://www.kernel.org/pub/linux/utils/raid/mdadm/ -http://www.kernel.org/pub/linux/utils/raid/mdadm/ -.UE +.B http://www.kernel.org/pub/linux/utils/raid/mdadm/ +.PP +Related man pages: .PP .IR mdadm.conf (5), .IR md (4).