X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=super1.c;h=0fd84e25bfde2fbfd1f5fb814f0d1e42bd7c57f8;hb=1ade5cc15a61c6fe3084c5170934e05e9a574843;hp=088df4bf3e9d13764961e2e0af12b0fc59fa061f;hpb=0ddc35beedea6f07c686c99429aaddd8b5e1182d;p=thirdparty%2Fmdadm.git diff --git a/super1.c b/super1.c index 088df4bf..0fd84e25 100644 --- a/super1.c +++ b/super1.c @@ -22,6 +22,7 @@ * Email: */ +#include #include "mdadm.h" /* * The version-1 superblock : @@ -57,7 +58,7 @@ struct mdp_superblock_1 { __u64 reshape_position; /* next address in array-space for reshape */ __u32 delta_disks; /* change in number of raid_disks */ __u32 new_layout; /* new layout */ - __u32 new_chunk; /* new chunk size (bytes) */ + __u32 new_chunk; /* new chunk size (sectors) */ __u32 new_offset; /* signed number to add to data_offset in new * layout. 0 == no-change. This can be * different on each device in the array. @@ -133,9 +134,6 @@ struct misc_dev_info { |MD_FEATURE_NEW_OFFSET \ ) -#ifndef offsetof -#define offsetof(t,f) ((size_t)&(((t*)0)->f)) -#endif static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) { unsigned int disk_csum, csum; @@ -813,7 +811,7 @@ static int examine_badblocks_super1(struct supertype *st, int fd, char *devname) size = __le32_to_cpu(sb->bblog_size)* 512; if (posix_memalign((void**)&bbl, 4096, size) != 0) { - pr_err("%s could not allocate badblocks list\n", __func__); + pr_err("could not allocate badblocks list\n"); return 0; } offset = __le64_to_cpu(sb->super_offset) + @@ -1247,21 +1245,44 @@ static int update_super1(struct supertype *st, struct mdinfo *info, /* set data_size to device size less data_offset */ struct misc_dev_info *misc = (struct misc_dev_info*) (st->sb + MAX_SB_SIZE + BM_SUPER_SIZE); - printf("Size was %llu\n", (unsigned long long) - __le64_to_cpu(sb->data_size)); sb->data_size = __cpu_to_le64( misc->device_size - __le64_to_cpu(sb->data_offset)); - printf("Size is %llu\n", (unsigned long long) - __le64_to_cpu(sb->data_size)); } else if (strcmp(update, "revert-reshape") == 0) { rv = -2; if (!(sb->feature_map & __cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE))) pr_err("No active reshape to revert on %s\n", devname); else { - rv = 0; __u32 temp; - sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) + + unsigned long long reshape_sectors; + long reshape_chunk; + rv = 0; + /* reshape_position is a little messy. + * Its value must be a multiple of the larger + * chunk size, and of the "after" data disks. + * So when reverting we need to change it to + * be a multiple of the new "after" data disks, + * which is the old "before". + * If it isn't already a multiple of 'before', + * the only thing we could do would be + * copy some block around on the disks, which + * is easy to get wrong. + * So we reject a revert-reshape unless the + * alignment is good. + */ + if (__le32_to_cpu(sb->level) >= 4 && + __le32_to_cpu(sb->level) <= 6) { + reshape_sectors = __le64_to_cpu(sb->reshape_position); + reshape_chunk = __le32_to_cpu(sb->new_chunk); + reshape_chunk *= __le32_to_cpu(sb->raid_disks) - __le32_to_cpu(sb->delta_disks) - + (__le32_to_cpu(sb->level)==6 ? 2 : 1); + if (reshape_sectors % reshape_chunk) { + pr_err("Reshape position is not suitably aligned.\n"); + pr_err("Try normal assembly and stop again\n"); + return -2; + } + } + sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) - __le32_to_cpu(sb->delta_disks)); if (sb->delta_disks == 0) sb->feature_map ^= __cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS); @@ -1277,9 +1298,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info, sb->chunksize = temp; if (sb->feature_map & __cpu_to_le32(MD_FEATURE_NEW_OFFSET)) { - sb->data_offset = __cpu_to_le64(__le64_to_cpu(sb->data_offset) + - (long)(int32_t)__le32_to_cpu(sb->new_offset)); - sb->new_offset = __cpu_to_le32(-(int32_t)__le32_to_cpu(sb->new_offset)); + long offset_delta = (int32_t)__le32_to_cpu(sb->new_offset); + sb->data_offset = __cpu_to_le64(__le64_to_cpu(sb->data_offset) + offset_delta); + sb->new_offset = __cpu_to_le32(-offset_delta); + sb->data_size = __cpu_to_le64(__le64_to_cpu(sb->data_size) - offset_delta); } } } else if (strcmp(update, "_reshape_progress")==0) @@ -1306,7 +1328,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info, int sbsize; if (posix_memalign((void**)&sb, 4096, SUPER1_SIZE) != 0) { - pr_err("%s could not allocate superblock\n", __func__); + pr_err("could not allocate superblock\n"); return 0; } memset(sb, 0, SUPER1_SIZE); @@ -1525,14 +1547,13 @@ static int write_init_super1(struct supertype *st) int rfd; int rv = 0; unsigned long long bm_space; - unsigned long long reserved; struct devinfo *di; unsigned long long dsize, array_size; - unsigned long long sb_offset, headroom; + unsigned long long sb_offset; unsigned long long data_offset; for (di = st->info; di; di = di->next) { - if (di->disk.state == 1) + if (di->disk.state & (1 << MD_DISK_FAULTY)) continue; if (di->fd < 0) continue; @@ -1594,35 +1615,25 @@ static int write_init_super1(struct supertype *st) * 0: At least 8K, but less than 12K, from end of device * 1: At start of device * 2: 4K from start of device. - * Depending on the array size, we might leave extra space - * for a bitmap. - * Also leave 4K for bad-block log. + * data_offset has already been set. */ array_size = __le64_to_cpu(sb->size); /* work out how much space we left for a bitmap, * Add 8 sectors for bad block log */ bm_space = choose_bm_space(array_size) + 8; - /* We try to leave 0.1% at the start for reshape - * operations, but limit this to 128Meg (0.1% of 10Gig) - * which is plenty for efficient reshapes - * However we make it at least 2 chunks as one chunk - * is minimum needed for reshape. - */ - headroom = 128 * 1024 * 2; - while (headroom << 10 > array_size && - headroom/2 >= __le32_to_cpu(sb->chunksize) * 2) - headroom >>= 1; - data_offset = di->data_offset; + if (data_offset == INVALID_SECTORS) + data_offset = st->data_offset; switch(st->minor_version) { case 0: + if (data_offset == INVALID_SECTORS) + data_offset = 0; sb_offset = dsize; sb_offset -= 8*2; sb_offset &= ~(4*2-1); + sb->data_offset = __cpu_to_le64(data_offset); sb->super_offset = __cpu_to_le64(sb_offset); - if (data_offset == INVALID_SECTORS) - sb->data_offset = 0; if (sb_offset < array_size + bm_space) bm_space = sb_offset - array_size; sb->data_size = __cpu_to_le64(sb_offset - bm_space); @@ -1633,70 +1644,37 @@ static int write_init_super1(struct supertype *st) break; case 1: sb->super_offset = __cpu_to_le64(0); - if (data_offset == INVALID_SECTORS) { - reserved = bm_space + 4*2; - if (reserved < headroom) - reserved = headroom; - if (reserved + array_size > dsize) - reserved = dsize - array_size; - /* Try for multiple of 1Meg so it is nicely aligned */ - #define ONE_MEG (2*1024) - if (reserved > ONE_MEG) - reserved = (reserved/ONE_MEG) * ONE_MEG; - - /* force 4K alignment */ - reserved &= ~7ULL; - - } else - reserved = data_offset; - - sb->data_offset = __cpu_to_le64(reserved); - sb->data_size = __cpu_to_le64(dsize - reserved); - if (reserved >= 8 + 32*2 + 8) { + if (data_offset == INVALID_SECTORS) + data_offset = 16; + + sb->data_offset = __cpu_to_le64(data_offset); + sb->data_size = __cpu_to_le64(dsize - data_offset); + if (data_offset >= 8 + 32*2 + 8) { sb->bblog_size = __cpu_to_le16(8); sb->bblog_offset = __cpu_to_le32(8 + 32*2); - } else if (reserved >= 16) { + } else if (data_offset >= 16) { sb->bblog_size = __cpu_to_le16(8); - sb->bblog_offset = __cpu_to_le32(reserved-8); + sb->bblog_offset = __cpu_to_le32(data_offset-8); } break; case 2: sb_offset = 4*2; - sb->super_offset = __cpu_to_le64(4*2); - if (data_offset == INVALID_SECTORS) { - if (4*2 + 4*2 + bm_space + array_size - > dsize) - bm_space = dsize - array_size - - 4*2 - 4*2; - - reserved = bm_space + 4*2 + 4*2; - if (reserved < headroom) - reserved = headroom; - if (reserved + array_size > dsize) - reserved = dsize - array_size; - /* Try for multiple of 1Meg so it is nicely aligned */ - #define ONE_MEG (2*1024) - if (reserved > ONE_MEG) - reserved = (reserved/ONE_MEG) * ONE_MEG; - - /* force 4K alignment */ - reserved &= ~7ULL; - - } else - reserved = data_offset; - - sb->data_offset = __cpu_to_le64(reserved); - sb->data_size = __cpu_to_le64(dsize - reserved); - if (reserved >= 16 + 32*2 + 8) { + sb->super_offset = __cpu_to_le64(sb_offset); + if (data_offset == INVALID_SECTORS) + data_offset = 24; + + sb->data_offset = __cpu_to_le64(data_offset); + sb->data_size = __cpu_to_le64(dsize - data_offset); + if (data_offset >= 16 + 32*2 + 8) { sb->bblog_size = __cpu_to_le16(8); sb->bblog_offset = __cpu_to_le32(8 + 32*2); - } else if (reserved >= 16+16) { + } else if (data_offset >= 16+16) { sb->bblog_size = __cpu_to_le16(8); /* '8' sectors for the bblog, and another '8' * because we want offset from superblock, not * start of device. */ - sb->bblog_offset = __cpu_to_le32(reserved-8-8); + sb->bblog_offset = __cpu_to_le32(data_offset-8-8); } break; default: @@ -1706,6 +1684,10 @@ static int write_init_super1(struct supertype *st) rv = -EINVAL; goto out; } + if (conf_get_create_info()->bblist == 0) { + sb->bblog_size = 0; + sb->bblog_offset = 0; + } sb->sb_csum = calc_sb_1_csum(sb); rv = store_super1(st, di->fd); @@ -1744,7 +1726,7 @@ static int compare_super1(struct supertype *st, struct supertype *tst) if (!first) { if (posix_memalign((void**)&first, 4096, SUPER1_SIZE) != 0) { - pr_err("%s could not allocate superblock\n", __func__); + pr_err("could not allocate superblock\n"); return 1; } memcpy(first, second, SUPER1_SIZE); @@ -1855,8 +1837,7 @@ static int load_super1(struct supertype *st, int fd, char *devname) } if (posix_memalign((void**)&super, 4096, SUPER1_SIZE) != 0) { - pr_err("%s could not allocate superblock\n", - __func__); + pr_err("could not allocate superblock\n"); return 1; } @@ -1896,6 +1877,8 @@ static int load_super1(struct supertype *st, int fd, char *devname) misc = (struct misc_dev_info*) (((char*)super)+MAX_SB_SIZE+BM_SUPER_SIZE); misc->device_size = dsize; + if (st->data_offset == INVALID_SECTORS) + st->data_offset = __le64_to_cpu(super->data_offset); /* Now check on the bitmap superblock */ if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0) @@ -1928,6 +1911,7 @@ static struct supertype *match_metadata_desc1(char *arg) st->ss = &super1; st->max_devs = MAX_DEVS; st->sb = NULL; + st->data_offset = INVALID_SECTORS; /* leading zeros can be safely ignored. --detail generates them. */ while (*arg == '0') arg++; @@ -1964,19 +1948,17 @@ static struct supertype *match_metadata_desc1(char *arg) * superblock type st, and reserving 'reserve' sectors for * a possible bitmap */ -static __u64 _avail_size1(struct supertype *st, __u64 devsize, - unsigned long long data_offset, int chunksize) +static __u64 avail_size1(struct supertype *st, __u64 devsize, + unsigned long long data_offset) { struct mdp_superblock_1 *super = st->sb; int bmspace = 0; + int bbspace = 0; if (devsize < 24) return 0; - if (super == NULL) - /* creating: allow suitable space for bitmap */ - bmspace = choose_bm_space(devsize); #ifndef MDASSEMBLE - else if (__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) { + 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)+MAX_SB_SIZE); @@ -1984,19 +1966,20 @@ static __u64 _avail_size1(struct supertype *st, __u64 devsize, } #endif /* Allow space for bad block log */ - if (super && super->bblog_size) - devsize -= __le16_to_cpu(super->bblog_size); - else - devsize -= 8; + if (super->bblog_size) + bbspace = __le16_to_cpu(super->bblog_size); if (st->minor_version < 0) /* not specified, so time to set default */ st->minor_version = 2; + if (data_offset == INVALID_SECTORS) + data_offset = st->data_offset; + if (data_offset != INVALID_SECTORS) switch(st->minor_version) { case 0: - return devsize - data_offset - 8*2; + return devsize - data_offset - 8*2 - bbspace; case 1: case 2: return devsize - data_offset; @@ -2006,36 +1989,19 @@ static __u64 _avail_size1(struct supertype *st, __u64 devsize, devsize -= bmspace; - if (super == NULL && st->minor_version > 0) { - /* haven't committed to a size yet, so allow some - * slack for space for reshape. - * Limit slack to 128M, but aim for about 0.1% - */ - unsigned long long headroom = 128*1024*2; - while ((headroom << 10) > devsize && - (chunksize == 0 || - headroom / 2 >= ((unsigned)chunksize*2)*2)) - headroom >>= 1; - devsize -= headroom; - } switch(st->minor_version) { case 0: /* at end */ - return ((devsize - 8*2 ) & ~(4*2-1)); + return ((devsize - 8*2 - bbspace ) & ~(4*2-1)); case 1: /* at start, 4K for superblock and possible bitmap */ - return devsize - 4*2; + return devsize - 4*2 - bbspace; case 2: /* 4k from start, 4K for superblock and possible bitmap */ - return devsize - (4+4)*2; + return devsize - (4+4)*2 - bbspace; } return 0; } -static __u64 avail_size1(struct supertype *st, __u64 devsize, - unsigned long long data_offset) -{ - return _avail_size1(st, devsize, data_offset, 0); -} static int add_internal_bitmap1(struct supertype *st, @@ -2077,8 +2043,8 @@ add_internal_bitmap1(struct supertype *st, * been left. */ offset = 0; - room = choose_bm_space(__le64_to_cpu(sb->size)); bbl_size = 8; + room = choose_bm_space(__le64_to_cpu(sb->size)) + bbl_size; } else { room = __le64_to_cpu(sb->super_offset) - __le64_to_cpu(sb->data_offset) @@ -2104,8 +2070,8 @@ add_internal_bitmap1(struct supertype *st, case 2: /* between superblock and data */ if (creating) { offset = 4*2; - room = choose_bm_space(__le64_to_cpu(sb->size)); bbl_size = 8; + room = choose_bm_space(__le64_to_cpu(sb->size)) + bbl_size; } else { room = __le64_to_cpu(sb->data_offset) - __le64_to_cpu(sb->super_offset); @@ -2134,6 +2100,10 @@ add_internal_bitmap1(struct supertype *st, /* Limit to 128K of bitmap when chunk size not requested */ room = 128*2; + if (room <= 1) + /* No room for a bitmap */ + return 0; + max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8; min_chunk = 4096; /* sub-page chunks don't work yet.. */ @@ -2266,7 +2236,9 @@ static int validate_geometry1(struct supertype *st, int level, char *subdev, unsigned long long *freesize, int verbose) { - unsigned long long ldsize; + unsigned long long ldsize, devsize; + int bmspace; + unsigned long long headroom; int fd; if (level == LEVEL_CONTAINER) { @@ -2274,12 +2246,16 @@ static int validate_geometry1(struct supertype *st, int level, pr_err("1.x metadata does not support containers\n"); return 0; } - if (chunk && *chunk == UnSet) + if (*chunk == UnSet) *chunk = DEFAULT_CHUNK; if (!subdev) return 1; + if (st->minor_version < 0) + /* not specified, so time to set default */ + st->minor_version = 2; + fd = open(subdev, O_RDONLY|O_EXCL, 0); if (fd < 0) { if (verbose) @@ -2294,7 +2270,57 @@ static int validate_geometry1(struct supertype *st, int level, } close(fd); - *freesize = _avail_size1(st, ldsize >> 9, data_offset, *chunk); + devsize = ldsize >> 9; + if (devsize < 24) { + *freesize = 0; + return 0; + } + + /* creating: allow suitable space for bitmap */ + bmspace = choose_bm_space(devsize); + + if (data_offset == INVALID_SECTORS) + data_offset = st->data_offset; + if (data_offset == INVALID_SECTORS) + switch (st->minor_version) { + case 0: + data_offset = 0; + break; + case 1: + case 2: + /* Choose data offset appropriate for this device + * and use as default for whole array. + * The data_offset must allow for bitmap space + * and base metadata, should allow for some headroom + * for reshape, and should be rounded to multiple + * of 1M. + * Headroom is limited to 128M, but aim for about 0.1% + */ + headroom = 128*1024*2; + while ((headroom << 10) > devsize && + (*chunk == 0 || + headroom / 2 >= ((unsigned)(*chunk)*2)*2)) + headroom >>= 1; + data_offset = 12*2 + bmspace + headroom; + #define ONE_MEG (2*1024) + if (data_offset > ONE_MEG) + data_offset = (data_offset / ONE_MEG) * ONE_MEG; + break; + } + if (st->data_offset == INVALID_SECTORS) + st->data_offset = data_offset; + switch(st->minor_version) { + case 0: /* metadata at end. Round down and subtract space to reserve */ + devsize = (devsize & ~(4ULL*2-1)); + /* space for metadata, bblog, bitmap */ + devsize -= 8*2 + 8 + bmspace; + break; + case 1: + case 2: + devsize -= data_offset; + break; + } + *freesize = devsize; return 1; } #endif /* MDASSEMBLE */