X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=super1.c;h=f3e40232cf56c1ed42ee178edea5fd4779f0c8ab;hb=a8cb6604b606deaaa66979e84a6f1c6d2c044b3b;hp=5bb1f0143790122dd208c4d2b4bc8db498e13ba9;hpb=72e7fb13f0154eb59941cfbe69e75c830bde4441;p=thirdparty%2Fmdadm.git diff --git a/super1.c b/super1.c index 5bb1f014..f3e40232 100644 --- a/super1.c +++ b/super1.c @@ -1,7 +1,7 @@ /* * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2001-2009 Neil Brown + * Copyright (C) 2001-2016 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -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. @@ -67,7 +68,10 @@ struct mdp_superblock_1 { __u64 data_offset; /* sector start of data, often 0 */ __u64 data_size; /* sectors in this device that can be used for data */ __u64 super_offset; /* sector start of this superblock */ - __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + union { + __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + __u64 journal_tail;/* journal tail of journal device (from data_offset) */ + }; __u32 dev_number; /* permanent identifier of this device - not role in raid */ __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ @@ -124,6 +128,8 @@ struct misc_dev_info { * backwards anyway. */ #define MD_FEATURE_NEW_OFFSET 64 /* new_offset must be honoured */ +#define MD_FEATURE_BITMAP_VERSIONED 256 /* bitmap version number checked properly */ +#define MD_FEATURE_JOURNAL 512 /* support write journal */ #define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \ |MD_FEATURE_RECOVERY_OFFSET \ |MD_FEATURE_RESHAPE_ACTIVE \ @@ -131,11 +137,39 @@ struct misc_dev_info { |MD_FEATURE_REPLACEMENT \ |MD_FEATURE_RESHAPE_BACKWARDS \ |MD_FEATURE_NEW_OFFSET \ + |MD_FEATURE_BITMAP_VERSIONED \ + |MD_FEATURE_JOURNAL \ ) -#ifndef offsetof -#define offsetof(t,f) ((size_t)&(((t*)0)->f)) +#ifndef MDASSEMBLE +static int role_from_sb(struct mdp_superblock_1 *sb) +{ + unsigned int d; + int role; + + d = __le32_to_cpu(sb->dev_number); + if (d < __le32_to_cpu(sb->max_dev)) + role = __le16_to_cpu(sb->dev_roles[d]); + else + role = MD_DISK_ROLE_SPARE; + return role; +} #endif + +/* return how many bytes are needed for bitmap, for cluster-md each node + * should have it's own bitmap */ +static unsigned int calc_bitmap_size(bitmap_super_t *bms, unsigned int boundary) +{ + unsigned long long bits, bytes; + + bits = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9); + bytes = (bits+7) >> 3; + bytes += sizeof(bitmap_super_t); + bytes = ROUND_UP(bytes, boundary); + + return bytes; +} + static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) { unsigned int disk_csum, csum; @@ -199,8 +233,7 @@ static int aread(struct align_fd *afd, void *buf, int len) if (!bsize || bsize > 4096 || len > 4096) { if (!bsize) - fprintf(stderr, "WARNING - aread() called with " - "invalid block size\n"); + fprintf(stderr, "WARNING - aread() called with invalid block size\n"); return -1; } b = ROUND_UP_PTR((char *)abuf, 4096); @@ -232,8 +265,7 @@ static int awrite(struct align_fd *afd, void *buf, int len) bsize = afd->blk_sz; if (!bsize || bsize > 4096 || len > 4096) { if (!bsize) - fprintf(stderr, "WARNING - awrite() called with " - "invalid block size\n"); + fprintf(stderr, "WARNING - awrite() called with invalid block size\n"); return -1; } b = ROUND_UP_PTR((char *)abuf, 4096); @@ -260,6 +292,7 @@ static int awrite(struct align_fd *afd, void *buf, int len) static void examine_super1(struct supertype *st, char *homehost) { struct mdp_superblock_1 *sb = st->sb; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE); time_t atime; unsigned int d; int role; @@ -269,6 +302,7 @@ static void examine_super1(struct supertype *st, char *homehost) int l = homehost ? strlen(homehost) : 0; int layout; unsigned long long sb_offset; + struct mdinfo info; printf(" Magic : %08x\n", __le32_to_cpu(sb->magic)); printf(" Version : 1"); @@ -292,6 +326,8 @@ static void examine_super1(struct supertype *st, char *homehost) strncmp(sb->set_name, homehost, l) == 0) printf(" (local to host %s)", homehost); printf("\n"); + if (bms->nodes > 0 && (__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) + printf(" Cluster Name : %-64s\n", bms->cluster_name); atime = __le64_to_cpu(sb->ctime) & 0xFFFFFFFFFFULL; printf(" Creation Time : %.24s\n", ctime(&atime)); c=map_num(pers, __le32_to_cpu(sb->level)); @@ -327,7 +363,8 @@ static void examine_super1(struct supertype *st, char *homehost) if (sb->data_offset) printf(" Data Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->data_offset)); - if (sb->new_offset) { + if (sb->new_offset && + (__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) { unsigned long long offset = __le64_to_cpu(sb->data_offset); offset += (signed)(int32_t)__le32_to_cpu(sb->new_offset); printf(" New Offset : %llu sectors\n", offset); @@ -336,6 +373,13 @@ static void examine_super1(struct supertype *st, char *homehost) (unsigned long long)__le64_to_cpu(sb->super_offset)); if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_RECOVERY_OFFSET) printf("Recovery Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->recovery_offset)); + + st->ss->getinfo_super(st, &info, NULL); + if (info.space_after != 1 && + !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) + printf(" Unused Space : before=%llu sectors, after=%llu sectors\n", + info.space_before, info.space_after); + printf(" State : %s\n", (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean"); printf(" Device UUID : "); for (i=0; i<16; i++) { @@ -395,14 +439,13 @@ static void examine_super1(struct supertype *st, char *homehost) if (sb->bblog_size && sb->bblog_offset) { printf(" Bad Block Log : %d entries available at offset %ld sectors", __le16_to_cpu(sb->bblog_size)*512/8, - (long)__le32_to_cpu(sb->bblog_offset)); + (long)(int32_t)__le32_to_cpu(sb->bblog_offset)); if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS)) printf(" - bad blocks present."); printf("\n"); } - if (calc_sb_1_csum(sb) == sb->sb_csum) printf(" Checksum : %x - correct\n", __le32_to_cpu(sb->sb_csum)); else @@ -442,25 +485,23 @@ static void examine_super1(struct supertype *st, char *homehost) /* This turns out to just be confusing */ printf(" Array Slot : %d (", __le32_to_cpu(sb->dev_number)); for (i= __le32_to_cpu(sb->max_dev); i> 0 ; i--) - if (__le16_to_cpu(sb->dev_roles[i-1]) != 0xffff) + if (__le16_to_cpu(sb->dev_roles[i-1]) != MD_DISK_ROLE_SPARE) break; for (d=0; d < i; d++) { int role = __le16_to_cpu(sb->dev_roles[d]); if (d) printf(", "); - if (role == 0xffff) printf("empty"); - else if(role == 0xfffe) printf("failed"); + if (role == MD_DISK_ROLE_SPARE) printf("empty"); + else if(role == MD_DISK_ROLE_FAULTY) printf("failed"); else printf("%d", role); } printf(")\n"); #endif printf(" Device Role : "); - d = __le32_to_cpu(sb->dev_number); - if (d < __le32_to_cpu(sb->max_dev)) - role = __le16_to_cpu(sb->dev_roles[d]); - else - role = 0xFFFF; - if (role >= 0xFFFE) + role = role_from_sb(sb); + if (role >= MD_DISK_ROLE_FAULTY) printf("spare\n"); + else if (role == MD_DISK_ROLE_JOURNAL) + printf("Journal\n"); else if (sb->feature_map & __cpu_to_le32(MD_FEATURE_REPLACEMENT)) printf("Replacement device %d\n", role); else @@ -489,7 +530,7 @@ static void examine_super1(struct supertype *st, char *homehost) faulty = 0; for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { int role = __le16_to_cpu(sb->dev_roles[i]); - if (role == 0xFFFE) + if (role == MD_DISK_ROLE_FAULTY) faulty++; } if (faulty) printf(" %d failed", faulty); @@ -498,7 +539,6 @@ static void examine_super1(struct supertype *st, char *homehost) printf("\n"); } - static void brief_examine_super1(struct supertype *st, int verbose) { struct mdp_superblock_1 *sb = st->sb; @@ -597,9 +637,143 @@ static void export_examine_super1(struct supertype *st) (unsigned long long)__le64_to_cpu(sb->events)); } +static int copy_metadata1(struct supertype *st, int from, int to) +{ + /* Read superblock. If it looks good, write it out. + * Then if a bitmap is present, copy that. + * And if a bad-block-list is present, copy that too. + */ + void *buf; + unsigned long long dsize, sb_offset; + const int bufsize = 4*1024; + struct mdp_superblock_1 super, *sb; + + if (posix_memalign(&buf, 4096, bufsize) != 0) + return 1; + + if (!get_dev_size(from, NULL, &dsize)) + goto err; + + dsize >>= 9; + if (dsize < 24) + goto err; + switch(st->minor_version) { + case 0: + sb_offset = dsize; + sb_offset -= 8*2; + sb_offset &= ~(4*2-1); + break; + case 1: + sb_offset = 0; + break; + case 2: + sb_offset = 4*2; + break; + default: + goto err; + } + + if (lseek64(from, sb_offset << 9, 0) < 0LL) + goto err; + if (read(from, buf, bufsize) != bufsize) + goto err; + + sb = buf; + super = *sb; // save most of sb for when we reuse buf + + if (__le32_to_cpu(super.magic) != MD_SB_MAGIC || + __le32_to_cpu(super.major_version) != 1 || + __le64_to_cpu(super.super_offset) != sb_offset || + calc_sb_1_csum(sb) != super.sb_csum) + goto err; + + if (lseek64(to, sb_offset << 9, 0) < 0LL) + goto err; + if (write(to, buf, bufsize) != bufsize) + goto err; + + if (super.feature_map & __le32_to_cpu(MD_FEATURE_BITMAP_OFFSET)) { + unsigned long long bitmap_offset = sb_offset; + int bytes = 4096; // just an estimate. + int written = 0; + struct align_fd afrom, ato; + + init_afd(&afrom, from); + init_afd(&ato, to); + + bitmap_offset += (int32_t)__le32_to_cpu(super.bitmap_offset); + + if (lseek64(from, bitmap_offset<<9, 0) < 0) + goto err; + if (lseek64(to, bitmap_offset<<9, 0) < 0) + goto err; + + for (written = 0; written < bytes ; ) { + int n = bytes - written; + if (n > 4096) + n = 4096; + if (aread(&afrom, buf, n) != n) + goto err; + if (written == 0) { + /* have the header, can calculate + * correct bitmap bytes */ + bitmap_super_t *bms; + bms = (void*)buf; + bytes = calc_bitmap_size(bms, 512); + if (n > bytes) + n = bytes; + } + if (awrite(&ato, buf, n) != n) + goto err; + written += n; + } + } + + if (super.bblog_size != 0 && + __le16_to_cpu(super.bblog_size) <= 100 && + super.bblog_offset != 0 && + (super.feature_map & __le32_to_cpu(MD_FEATURE_BAD_BLOCKS))) { + /* There is a bad block log */ + unsigned long long bb_offset = sb_offset; + int bytes = __le16_to_cpu(super.bblog_size) * 512; + int written = 0; + struct align_fd afrom, ato; + + init_afd(&afrom, from); + init_afd(&ato, to); + + bb_offset += (int32_t)__le32_to_cpu(super.bblog_offset); + + if (lseek64(from, bb_offset<<9, 0) < 0) + goto err; + if (lseek64(to, bb_offset<<9, 0) < 0) + goto err; + + for (written = 0; written < bytes ; ) { + int n = bytes - written; + if (n > 4096) + n = 4096; + if (aread(&afrom, buf, n) != n) + goto err; + + if (awrite(&ato, buf, n) != n) + goto err; + written += n; + } + } + + free(buf); + return 0; + +err: + free(buf); + return 1; +} + static void detail_super1(struct supertype *st, char *homehost) { struct mdp_superblock_1 *sb = st->sb; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); int i; int l = homehost ? strlen(homehost) : 0; @@ -608,6 +782,8 @@ static void detail_super1(struct supertype *st, char *homehost) sb->set_name[l] == ':' && strncmp(sb->set_name, homehost, l) == 0) printf(" (local to host %s)", homehost); + if (bms->nodes > 0 && (__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) + printf("\n Cluster Name : %-64s", bms->cluster_name); printf("\n UUID : "); for (i=0; i<16; i++) { if ((i&3)==0 && i != 0) printf(":"); @@ -648,6 +824,62 @@ static void export_detail_super1(struct supertype *st) printf("MD_NAME=%.*s\n", len, sb->set_name); } +static int examine_badblocks_super1(struct supertype *st, int fd, char *devname) +{ + struct mdp_superblock_1 *sb = st->sb; + unsigned long long offset; + int size; + __u64 *bbl, *bbp; + int i; + + if (!sb->bblog_size || __le16_to_cpu(sb->bblog_size) > 100 + || !sb->bblog_offset){ + printf("No bad-blocks list configured on %s\n", devname); + return 0; + } + if ((sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS)) + == 0) { + printf("Bad-blocks list is empty in %s\n", devname); + return 0; + } + + size = __le16_to_cpu(sb->bblog_size)* 512; + if (posix_memalign((void**)&bbl, 4096, size) != 0) { + pr_err("could not allocate badblocks list\n"); + return 0; + } + offset = __le64_to_cpu(sb->super_offset) + + (int)__le32_to_cpu(sb->bblog_offset); + offset <<= 9; + if (lseek64(fd, offset, 0) < 0) { + pr_err("Cannot seek to bad-blocks list\n"); + return 1; + } + if (read(fd, bbl, size) != size) { + pr_err("Cannot read bad-blocks list\n"); + return 1; + } + /* 64bits per entry. 10 bits is block-count, 54 bits is block + * offset. Blocks are sectors unless bblog->shift makes them bigger + */ + bbp = (__u64*)bbl; + printf("Bad-blocks on %s:\n", devname); + for (i = 0; i < size/8; i++, bbp++) { + __u64 bb = __le64_to_cpu(*bbp); + int count = bb & 0x3ff; + unsigned long long sector = bb >> 10; + + if (bb + 1 == 0) + break; + + sector <<= sb->bblog_shift; + count <<= sb->bblog_shift; + + printf("%20llu for %d sectors\n", sector, count); + } + return 0; +} + #endif static int match_home1(struct supertype *st, char *homehost) @@ -695,6 +927,8 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) info->array.state = (__le64_to_cpu(sb->resync_offset) == MaxSector) ? 1 : 0; + if (__le32_to_cpu(bsb->nodes) > 1) + info->array.state |= (1 << MD_SB_CLUSTERED); info->data_offset = __le64_to_cpu(sb->data_offset); info->component_size = __le64_to_cpu(sb->size); @@ -706,25 +940,37 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) info->disk.number = __le32_to_cpu(sb->dev_number); if (__le32_to_cpu(sb->dev_number) >= __le32_to_cpu(sb->max_dev) || __le32_to_cpu(sb->dev_number) >= MAX_DEVS) - role = 0xfffe; + role = MD_DISK_ROLE_FAULTY; 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->array.level <= 0) + data_size = __le64_to_cpu(sb->data_size); + else + 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 (sb->bblog_offset && sb->bblog_size) { + unsigned long long bboffset = super_offset; + bboffset += (int32_t)__le32_to_cpu(sb->bblog_offset); + if (bboffset < end) + end = bboffset; + } + + if (super_offset + info->bitmap_offset < end) + end = super_offset + 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); + unsigned long long earliest; + earliest = super_offset + (32+4)*2; /* match kernel */ if (info->bitmap_offset > 0) { unsigned long long bmend = info->bitmap_offset; unsigned long long size = __le64_to_cpu(bsb->sync_size); @@ -733,24 +979,45 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) 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; - } else - info->space_before -= 8; /* superblock */ + bmend += size; + if (bmend > earliest) + earliest = bmend; + } + if (sb->bblog_offset && sb->bblog_size) { + unsigned long long bbend = super_offset; + bbend += (int32_t)__le32_to_cpu(sb->bblog_offset); + bbend += __le16_to_cpu(sb->bblog_size); + if (bbend > earliest) + earliest = bbend; + } + if (earliest < info->data_offset) + info->space_before = info->data_offset - earliest; + else + info->space_before = 0; info->space_after = misc->device_size - data_size - info->data_offset; } + if (info->space_before == 0 && info->space_after == 0) { + /* It will look like we don't support data_offset changes, + * be we do - it's just that there is no room. + * A change that reduced the number of devices should + * still be allowed, so set the otherwise useless value of '1' + */ + info->space_after = 1; + } info->disk.raid_disk = -1; switch(role) { - case 0xFFFF: + case MD_DISK_ROLE_SPARE: info->disk.state = 0; /* spare: not active, not sync, not faulty */ break; - case 0xFFFE: + case MD_DISK_ROLE_FAULTY: info->disk.state = 1; /* faulty */ break; + case MD_DISK_ROLE_JOURNAL: + info->disk.state = (1 << MD_DISK_JOURNAL); + info->disk.raid_disk = role; + info->space_after = (misc->device_size - info->data_offset) % 8; /* journal uses all 4kB blocks*/ + break; default: info->disk.state = 6; /* active and in sync */ info->disk.raid_disk = role; @@ -771,7 +1038,6 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) info->disk.state |= 1 << MD_DISK_REPLACEMENT; } - if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RECOVERY_OFFSET)) info->recovery_start = __le32_to_cpu(sb->recovery_offset); else @@ -779,7 +1045,8 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) { info->reshape_active = 1; - if (info->array.level == 10) + if ((sb->feature_map & __le32_to_cpu(MD_FEATURE_NEW_OFFSET)) && + sb->new_offset != 0) info->reshape_active |= RESHAPE_NO_BACKUP; info->reshape_progress = __le64_to_cpu(sb->reshape_position); info->new_level = __le32_to_cpu(sb->new_level); @@ -798,7 +1065,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) map[i] = 0; for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) { role = __le16_to_cpu(sb->dev_roles[i]); - if (/*role == 0xFFFF || */role < (unsigned) info->array.raid_disks) { + if (/*role == MD_DISK_ROLE_SPARE || */role < (unsigned) info->array.raid_disks) { working++; if (map && role < map_disks) map[role] = 1; @@ -806,6 +1073,9 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) } info->array.working_disks = working; + if (sb->feature_map & __le32_to_cpu(MD_FEATURE_JOURNAL)) + info->journal_device_required = 1; + info->journal_clean = 0; } static struct mdinfo *container_content1(struct supertype *st, char *subarray) @@ -830,7 +1100,33 @@ static int update_super1(struct supertype *st, struct mdinfo *info, * ignored. */ int rv = 0; + int lockid; struct mdp_superblock_1 *sb = st->sb; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); + + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) { + rv = cluster_get_dlmlock(&lockid); + if (rv) { + pr_err("Cannot get dlmlock in %s return %d\n", __func__, rv); + cluster_release_dlmlock(lockid); + return rv; + } + } + + if (strcmp(update, "homehost") == 0 && + homehost) { + /* Note that 'homehost' is special as it is really + * a "name" update. + */ + char *c; + update = "name"; + c = strchr(sb->set_name, ':'); + if (c) + strncpy(info->name, c+1, 31 - (c-sb->set_name)); + else + strncpy(info->name, sb->set_name, 32); + info->name[32] = 0; + } if (strcmp(update, "force-one")==0) { /* Not enough devices for a working array, @@ -855,8 +1151,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info, int want; if (info->disk.state & (1<disk.raid_disk; + else if (info->disk.state & (1<dev_roles[d] != __cpu_to_le16(want)) { sb->dev_roles[d] = __cpu_to_le16(want); rv = 1; @@ -877,24 +1175,18 @@ static int update_super1(struct supertype *st, struct mdinfo *info, } } else if (strcmp(update, "linear-grow-new") == 0) { unsigned int i; - int rfd, fd; + int fd; unsigned int max = __le32_to_cpu(sb->max_dev); for (i=0 ; i < max ; i++) - if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe) + if (__le16_to_cpu(sb->dev_roles[i]) >= MD_DISK_ROLE_FAULTY) break; sb->dev_number = __cpu_to_le32(i); info->disk.number = i; if (max >= __le32_to_cpu(sb->max_dev)) sb->max_dev = __cpu_to_le32(max+1); - if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || - read(rfd, sb->device_uuid, 16) != 16) { - __u32 r[4] = {random(), random(), random(), random()}; - memcpy(sb->device_uuid, r, 16); - } - if (rfd >= 0) - close(rfd); + random_uuid(sb->device_uuid); sb->dev_roles[i] = __cpu_to_le16(info->disk.raid_disk); @@ -940,27 +1232,29 @@ static int update_super1(struct supertype *st, struct mdinfo *info, */ unsigned long long sb_offset = __le64_to_cpu(sb->super_offset); unsigned long long data_offset = __le64_to_cpu(sb->data_offset); - long bitmap_offset = (long)__le64_to_cpu(sb->bitmap_offset); + long bitmap_offset = (long)(int32_t)__le32_to_cpu(sb->bitmap_offset); long bm_sectors = 0; long space; +#ifndef MDASSEMBLE if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) { struct bitmap_super_s *bsb; bsb = (struct bitmap_super_s *)(((char*)sb)+MAX_SB_SIZE); bm_sectors = bitmap_sectors(bsb); } - +#endif if (sb_offset < data_offset) { - /* 1.1 or 1.2. Put bbl just before data + /* 1.1 or 1.2. Put bbl after bitmap leaving at least 32K */ long bb_offset; - space = data_offset - sb_offset; - bb_offset = space - 8; + bb_offset = sb_offset + 8; if (bm_sectors && bitmap_offset > 0) - space -= (bitmap_offset + bm_sectors); - else - space -= 8; /* The superblock */ - if (space >= 8) { + bb_offset = bitmap_offset + bm_sectors; + while (bb_offset < (long)sb_offset + 8 + 32*2 + && bb_offset + 8+8 <= (long)data_offset) + /* too close to bitmap, and room to grow */ + bb_offset += 8; + if (bb_offset + 8 <= (long)data_offset) { sb->bblog_size = __cpu_to_le16(8); sb->bblog_offset = __cpu_to_le32(bb_offset); } @@ -984,16 +1278,11 @@ static int update_super1(struct supertype *st, struct mdinfo *info, sb->bblog_shift = 0; sb->bblog_offset = 0; } - } else if (strcmp(update, "homehost") == 0 && - homehost) { - char *c; - update = "name"; - c = strchr(sb->set_name, ':'); - if (c) - strncpy(info->name, c+1, 31 - (c-sb->set_name)); - else - strncpy(info->name, sb->set_name, 32); - info->name[32] = 0; + } else if (strcmp(update, "force-no-bbl") == 0) { + sb->feature_map &= ~ __cpu_to_le32(MD_FEATURE_BAD_BLOCKS); + sb->bblog_size = 0; + sb->bblog_shift = 0; + sb->bblog_offset = 0; } else if (strcmp(update, "name") == 0) { if (info->name[0] == 0) sprintf(info->name, "%d", info->array.md_minor); @@ -1012,12 +1301,84 @@ 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 (strncmp(update, "revert-reshape", 14) == 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 { + __u32 temp; + unsigned long long reshape_sectors; + long reshape_chunk; + rv = 0; + /* If the reshape hasn't started, just stop it. + * It is conceivable that a stripe was modified but + * the metadata not updated. In that case the backup + * should have been used to get passed the critical stage. + * If that couldn't happen, the "-nobackup" version + * will be used. + */ + if (strcmp(update, "revert-reshape-nobackup") == 0 && + sb->reshape_position == 0 && + (__le32_to_cpu(sb->delta_disks) > 0 || + (__le32_to_cpu(sb->delta_disks) == 0 && + !(sb->feature_map & __cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS))))) { + sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); + sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) - + __le32_to_cpu(sb->delta_disks)); + sb->delta_disks = 0; + goto done; + } + /* 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); + else + sb->delta_disks = __cpu_to_le32(-__le32_to_cpu(sb->delta_disks)); + + temp = sb->new_layout; + sb->new_layout = sb->layout; + sb->layout = temp; + + temp = sb->new_chunk; + sb->new_chunk = sb->chunksize; + sb->chunksize = temp; + + if (sb->feature_map & __cpu_to_le32(MD_FEATURE_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); + } + done:; + } } else if (strcmp(update, "_reshape_progress")==0) sb->reshape_position = __cpu_to_le64(info->reshape_progress); else if (strcmp(update, "writemostly")==0) @@ -1028,6 +1389,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info, rv = -1; sb->sb_csum = calc_sb_1_csum(sb); + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) + cluster_release_dlmlock(lockid); + return rv; } @@ -1037,12 +1401,11 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info, { struct mdp_superblock_1 *sb; int spares; - int rfd; char defname[10]; 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); @@ -1067,14 +1430,8 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info, if (uuid) copy_uuid(sb->set_uuid, uuid, super1.swapuuid); - else { - if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || - read(rfd, sb->set_uuid, 16) != 16) { - __u32 r[4] = {random(), random(), random(), random()}; - memcpy(sb->set_uuid, r, 16); - } - if (rfd >= 0) close(rfd); - } + else + random_uuid(sb->set_uuid);; if (name == NULL || *name == 0) { sprintf(defname, "%d", info->md_minor); @@ -1131,13 +1488,26 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk, struct mdp_superblock_1 *sb = st->sb; __u16 *rp = sb->dev_roles + dk->number; struct devinfo *di, **dip; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); + int rv, lockid; + + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) { + rv = cluster_get_dlmlock(&lockid); + if (rv) { + pr_err("Cannot get dlmlock in %s return %d\n", __func__, rv); + cluster_release_dlmlock(lockid); + return rv; + } + } if ((dk->state & 6) == 6) /* active, sync */ *rp = __cpu_to_le16(dk->raid_disk); + else if (dk->state & (1<state & ~2) == 0) /* active or idle -> spare */ - *rp = 0xffff; + *rp = MD_DISK_ROLE_SPARE; else - *rp = 0xfffe; + *rp = MD_DISK_ROLE_FAULTY; if (dk->number >= (int)__le32_to_cpu(sb->max_dev) && __le32_to_cpu(sb->max_dev) < MAX_DEVS) @@ -1158,11 +1528,14 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk, di->next = NULL; *dip = di; + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) + cluster_release_dlmlock(lockid); + return 0; } #endif -static void locate_bitmap1(struct supertype *st, int fd); +static int locate_bitmap1(struct supertype *st, int fd, int node_num); static int store_super1(struct supertype *st, int fd) { @@ -1171,6 +1544,17 @@ static int store_super1(struct supertype *st, int fd) struct align_fd afd; int sbsize; unsigned long long dsize; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); + int rv, lockid; + + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) { + rv = cluster_get_dlmlock(&lockid); + if (rv) { + pr_err("Cannot get dlmlock in %s return %d\n", __func__, rv); + cluster_release_dlmlock(lockid); + return rv; + } + } if (!get_dev_size(fd, NULL, &dsize)) return 1; @@ -1206,8 +1590,6 @@ static int store_super1(struct supertype *st, int fd) return -EINVAL; } - - if (sb_offset != __le64_to_cpu(sb->super_offset) && 0 != __le64_to_cpu(sb->super_offset) ) { @@ -1227,12 +1609,15 @@ static int store_super1(struct supertype *st, int fd) struct bitmap_super_s *bm = (struct bitmap_super_s*) (((char*)sb)+MAX_SB_SIZE); if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) { - locate_bitmap1(st, fd); + locate_bitmap1(st, fd, 0); if (awrite(&afd, bm, sizeof(*bm)) != sizeof(*bm)) return 5; } } fsync(fd); + if (bms->version == BITMAP_MAJOR_CLUSTERED && dlm_funs_ready()) + cluster_release_dlmlock(lockid); + return 0; } @@ -1245,7 +1630,8 @@ static unsigned long choose_bm_space(unsigned long devsize) * NOTE: result must be multiple of 4K else bad things happen * on 4K-sector devices. */ - if (devsize < 64*2) return 0; + if (devsize < 64*2) + return 0; if (devsize - 64*2 >= 200*1024*1024*2) return 128*2; if (devsize - 4*2 > 8*1024*1024*2) @@ -1255,22 +1641,73 @@ static unsigned long choose_bm_space(unsigned long devsize) static void free_super1(struct supertype *st); +#define META_BLOCK_SIZE 4096 +__u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len); + #ifndef MDASSEMBLE +static int write_empty_r5l_meta_block(struct supertype *st, int fd) +{ + struct r5l_meta_block *mb; + struct mdp_superblock_1 *sb = st->sb; + struct align_fd afd; + __u32 crc; + + init_afd(&afd, fd); + + if (posix_memalign((void**)&mb, 4096, META_BLOCK_SIZE) != 0) { + pr_err("Could not allocate memory for the meta block.\n"); + return 1; + } + + memset(mb, 0, META_BLOCK_SIZE); + + mb->magic = __cpu_to_le32(R5LOG_MAGIC); + mb->version = R5LOG_VERSION; + mb->meta_size = __cpu_to_le32(sizeof(struct r5l_meta_block)); + mb->seq = __cpu_to_le64(random32()); + mb->position = __cpu_to_le64(0); + + crc = crc32c_le(0xffffffff, sb->set_uuid, sizeof(sb->set_uuid)); + crc = crc32c_le(crc, (void *)mb, META_BLOCK_SIZE); + mb->checksum = crc; + + if (lseek64(fd, (sb->data_offset) * 512, 0) < 0LL) { + pr_err("cannot seek to offset of the meta block\n"); + goto fail_to_write; + } + + if (awrite(&afd, mb, META_BLOCK_SIZE) != META_BLOCK_SIZE) { + pr_err("failed to store write the meta block \n"); + goto fail_to_write; + } + fsync(fd); + + free(mb); + return 0; + +fail_to_write: + free(mb); + return 1; +} + static int write_init_super1(struct supertype *st) { struct mdp_superblock_1 *sb = st->sb; struct supertype *refst; - 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_JOURNAL)) + sb->feature_map |= MD_FEATURE_JOURNAL; + } + + for (di = st->info; di; di = di->next) { + if (di->disk.state & (1 << MD_DISK_FAULTY)) continue; if (di->fd < 0) continue; @@ -1284,18 +1721,13 @@ static int write_init_super1(struct supertype *st) else sb->devflags &= ~WriteMostly1; - if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || - read(rfd, sb->device_uuid, 16) != 16) { - __u32 r[4] = {random(), random(), random(), random()}; - memcpy(sb->device_uuid, r, 16); - } - if (rfd >= 0) - close(rfd); + random_uuid(sb->device_uuid); - sb->events = 0; + if (!(di->disk.state & (1<events = 0; refst = dup_super(st); - if (load_super1(refst, di->fd, NULL)==0) { + if (load_super1(refst, di->fd, NULL)==0) { struct mdp_superblock_1 *refsb = refst->sb; memcpy(sb->device_uuid, refsb->device_uuid, 16); @@ -1325,7 +1757,6 @@ static int write_init_super1(struct supertype *st) goto error_out; } - /* * Calculate the position of the superblock. * It is always aligned to a 4K boundary and @@ -1333,35 +1764,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); @@ -1372,78 +1793,62 @@ 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 >= 16) { + 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 (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+16) { + 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 (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: - pr_err("Failed to write invalid " - "metadata format 1.%i to %s\n", + pr_err("Failed to write invalid metadata format 1.%i to %s\n", st->minor_version, di->devname); rv = -EINVAL; goto out; } + /* Disable badblock log on clusters, or when explicitly requested */ + if (st->nodes > 0 || 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); + + if (rv == 0 && (di->disk.state & (1 << MD_DISK_JOURNAL))) { + rv = write_empty_r5l_meta_block(st, di->fd); + if (rv) + goto error_out; + } + if (rv == 0 && (__le32_to_cpu(sb->feature_map) & 1)) - rv = st->ss->write_bitmap(st, di->fd); + rv = st->ss->write_bitmap(st, di->fd, NodeNumUpdate); close(di->fd); di->fd = -1; if (rv) @@ -1477,7 +1882,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); @@ -1580,9 +1985,6 @@ static int load_super1(struct supertype *st, int fd, char *devname) return -EINVAL; } - ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ - - if (lseek64(fd, sb_offset << 9, 0)< 0LL) { if (devname) pr_err("Cannot seek to superblock on %s: %s\n", @@ -1591,11 +1993,12 @@ 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; } + memset(super, 0, SUPER1_SIZE); + if (aread(&afd, super, MAX_SB_SIZE) != MAX_SB_SIZE) { if (devname) pr_err("Cannot read superblock on %s\n", @@ -1632,6 +2035,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) @@ -1640,7 +2045,7 @@ static int load_super1(struct supertype *st, int fd, char *devname) * valid. If it doesn't clear the bit. An --assemble --force * should get that written out. */ - locate_bitmap1(st, fd); + locate_bitmap1(st, fd, 0); if (aread(&afd, bsb, 512) != 512) goto no_bitmap; @@ -1656,15 +2061,15 @@ static int load_super1(struct supertype *st, int fd, char *devname) return 0; } - static struct supertype *match_metadata_desc1(char *arg) { struct supertype *st = xcalloc(1, sizeof(*st)); - st->container_dev = NoMdDev; + st->container_devnm[0] = 0; 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++; @@ -1701,19 +2106,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); @@ -1721,20 +2124,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; @@ -1744,36 +2147,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, @@ -1798,11 +2184,11 @@ add_internal_bitmap1(struct supertype *st, unsigned long long chunk = *chunkp; int room = 0; int creating = 0; + int len; struct mdp_superblock_1 *sb = st->sb; bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); int uuid[4]; - if (__le64_to_cpu(sb->data_size) == 0) /* Must be creating the array, else data_size would be non-zero */ creating = 1; @@ -1816,8 +2202,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) @@ -1830,7 +2216,7 @@ add_internal_bitmap1(struct supertype *st, bbl_size = -bbl_offset; if (!may_change || (room < 3*2 && - __le32_to_cpu(sb->max_dev) <= 384)) { + __le32_to_cpu(sb->max_dev) <= 384)) { room = 3*2; offset = 1*2; bbl_size = 0; @@ -1843,8 +2229,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); @@ -1865,7 +2251,7 @@ add_internal_bitmap1(struct supertype *st, } break; default: - return 0; + return -ENOSPC; } room -= bbl_size; @@ -1873,6 +2259,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 -ENOSPC; + max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8; min_chunk = 4096; /* sub-page chunks don't work yet.. */ @@ -1889,9 +2279,9 @@ add_internal_bitmap1(struct supertype *st, if (chunk < 64*1024*1024) chunk = 64*1024*1024; } else if (chunk < min_chunk) - return 0; /* chunk size too small */ + return -EINVAL; /* chunk size too small */ if (chunk == 0) /* rounding problem */ - return 0; + return -EINVAL; if (offset == 0) { /* start bitmap on a 4K boundary with enough space for @@ -1916,68 +2306,154 @@ add_internal_bitmap1(struct supertype *st, bms->daemon_sleep = __cpu_to_le32(delay); bms->sync_size = __cpu_to_le64(size); bms->write_behind = __cpu_to_le32(write_behind); + bms->nodes = __cpu_to_le32(st->nodes); + if (st->nodes) + sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) + | MD_FEATURE_BITMAP_VERSIONED); + if (st->cluster_name) { + len = sizeof(bms->cluster_name); + strncpy((char *)bms->cluster_name, st->cluster_name, len); + bms->cluster_name[len - 1] = '\0'; + } *chunkp = chunk; - return 1; + return 0; } -static void locate_bitmap1(struct supertype *st, int fd) +static int locate_bitmap1(struct supertype *st, int fd, int node_num) { unsigned long long offset; struct mdp_superblock_1 *sb; int mustfree = 0; + int ret; if (!st->sb) { if (st->ss->load_super(st, fd, NULL)) - return; /* no error I hope... */ + return -1; /* no error I hope... */ mustfree = 1; } sb = st->sb; + if ((__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) + ret = 0; + else + ret = -1; offset = __le64_to_cpu(sb->super_offset); - offset += (int32_t) __le32_to_cpu(sb->bitmap_offset); + offset += (int32_t) __le32_to_cpu(sb->bitmap_offset) * (node_num + 1); if (mustfree) free(sb); lseek64(fd, offset<<9, 0); + return ret; } -static int write_bitmap1(struct supertype *st, int fd) +static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update) { struct mdp_superblock_1 *sb = st->sb; bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE); int rv = 0; void *buf; - int towrite, n; + int towrite, n, len; struct align_fd afd; + unsigned int i = 0; + unsigned long long total_bm_space, bm_space_per_node; + + switch (update) { + case NameUpdate: + /* update cluster name */ + if (st->cluster_name) { + len = sizeof(bms->cluster_name); + memset((char *)bms->cluster_name, 0, len); + strncpy((char *)bms->cluster_name, + st->cluster_name, len); + bms->cluster_name[len - 1] = '\0'; + } + break; + case NodeNumUpdate: + /* cluster md only supports superblock 1.2 now */ + if (st->minor_version != 2 && bms->version == BITMAP_MAJOR_CLUSTERED) { + pr_err("Warning: cluster md only works with superblock 1.2\n"); + return -EINVAL; + } + + if (bms->version == BITMAP_MAJOR_CLUSTERED) { + if (st->nodes == 1) { + /* the parameter for nodes is not valid */ + pr_err("Warning: cluster-md at least needs two nodes\n"); + return -EINVAL; + } else if (st->nodes == 0) + /* --nodes is not specified */ + break; + else if (__cpu_to_le32(st->nodes) < bms->nodes) { + /* Since the nodes num is not increased, no need to check the space + * is enough or not, just update bms->nodes */ + bms->nodes = __cpu_to_le32(st->nodes); + break; + } + } else { + /* no need to change bms->nodes for other bitmap types */ + if (st->nodes) + pr_err("Warning: --nodes option is only suitable for clustered bitmap\n"); + break; + } + + /* Each node has an independent bitmap, it is necessary to calculate the + * space is enough or not, first get how many bytes for the total bitmap */ + bm_space_per_node = calc_bitmap_size(bms, 4096); + + total_bm_space = 512 * (__le64_to_cpu(sb->data_offset) - __le64_to_cpu(sb->super_offset)); + total_bm_space = total_bm_space - 4096; /* leave another 4k for superblock */ + + if (bm_space_per_node * st->nodes > total_bm_space) { + pr_err("Warning: The max num of nodes can't exceed %llu\n", + total_bm_space / bm_space_per_node); + return -ENOMEM; + } + + bms->nodes = __cpu_to_le32(st->nodes); + break; + case NoUpdate: + default: + break; + } init_afd(&afd, fd); - locate_bitmap1(st, fd); + locate_bitmap1(st, fd, 0); if (posix_memalign(&buf, 4096, 4096)) return -ENOMEM; - memset(buf, 0xff, 4096); - memcpy(buf, (char *)bms, sizeof(bitmap_super_t)); - - towrite = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9); - towrite = (towrite+7) >> 3; /* bits to bytes */ - towrite += sizeof(bitmap_super_t); - towrite = ROUND_UP(towrite, 512); - while (towrite > 0) { - n = towrite; - if (n > 4096) - n = 4096; - n = awrite(&afd, buf, n); - if (n > 0) - towrite -= n; + do { + /* Only the bitmap[0] should resync + * whole device on initial assembly + */ + if (i) + memset(buf, 0x00, 4096); else + memset(buf, 0xff, 4096); + memcpy(buf, (char *)bms, sizeof(bitmap_super_t)); + + towrite = calc_bitmap_size(bms, 4096); + while (towrite > 0) { + n = towrite; + if (n > 4096) + n = 4096; + n = awrite(&afd, buf, n); + if (n > 0) + towrite -= n; + else + break; + if (i) + memset(buf, 0x00, 4096); + else + memset(buf, 0xff, 4096); + } + fsync(fd); + if (towrite) { + rv = -2; break; - memset(buf, 0xff, 4096); - } - fsync(fd); - if (towrite) - rv = -2; + } + } while (++i < __le32_to_cpu(bms->nodes)); free(buf); return rv; @@ -1985,6 +2461,7 @@ static int write_bitmap1(struct supertype *st, int fd) static void free_super1(struct supertype *st) { + if (st->sb) free(st->sb); while (st->info) { @@ -2005,7 +2482,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) { @@ -2013,12 +2492,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) @@ -2033,11 +2516,111 @@ 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 */ +void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0) +{ + /* Create a v1.0 superblock based on 'info'*/ + void *ret; + struct mdp_superblock_1 *sb; + int i; + unsigned long long offset; + + if (posix_memalign(&ret, 4096, 1024) != 0) + return NULL; + sb = ret; + memset(ret, 0, 1024); + sb->magic = __cpu_to_le32(MD_SB_MAGIC); + sb->major_version = __cpu_to_le32(1); + + copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid); + sprintf(sb->set_name, "%d", sb0->md_minor); + sb->ctime = __cpu_to_le32(info->array.ctime+1); + sb->level = __cpu_to_le32(info->array.level); + sb->layout = __cpu_to_le32(info->array.layout); + sb->size = __cpu_to_le64(info->component_size); + sb->chunksize = __cpu_to_le32(info->array.chunk_size/512); + sb->raid_disks = __cpu_to_le32(info->array.raid_disks); + if (info->array.level > 0) + sb->data_size = sb->size; + else + sb->data_size = st->ss->avail_size(st, st->devsize/512, 0); + sb->resync_offset = MaxSector; + sb->max_dev = __cpu_to_le32(MD_SB_DISKS); + sb->dev_number = __cpu_to_le32(info->disk.number); + sb->utime = __cpu_to_le64(info->array.utime); + + offset = st->devsize/512 - 8*2; + offset &= ~(4*2-1); + sb->super_offset = __cpu_to_le64(offset); + //*(__u64*)(st->other + 128 + 8 + 8) = __cpu_to_le64(offset); + + random_uuid(sb->device_uuid); + + for (i = 0; i < MD_SB_DISKS; i++) { + int state = sb0->disks[i].state; + sb->dev_roles[i] = MD_DISK_ROLE_SPARE; + if ((state & (1<dev_roles[i] = __cpu_to_le16(sb0->disks[i].raid_disk); + } + sb->sb_csum = calc_sb_1_csum(sb); + return ret; +} + struct superswitch super1 = { #ifndef MDASSEMBLE .examine_super = examine_super1, @@ -2049,6 +2632,8 @@ struct superswitch super1 = { .write_init_super = write_init_super1, .validate_geometry = validate_geometry1, .add_to_super = add_to_super1, + .examine_badblocks = examine_badblocks_super1, + .copy_metadata = copy_metadata1, #endif .match_home = match_home1, .uuid_from_super = uuid_from_super1,