diff --git a/Create.c b/Create.c index 86b9dff..d8fcdfe 100644 --- a/Create.c +++ b/Create.c @@ -210,7 +210,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, ldsize = dsize; ldsize <<= 9; } - freesize = st->ss->avail_size(ldsize >> 9); + freesize = st->ss->avail_size(st, ldsize >> 9, 64*2); if (freesize == 0) { fprintf(stderr, Name ": %s is too small: %luK\n", dname, (unsigned long)(ldsize>>10)); @@ -355,7 +355,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, fprintf(stderr, Name ": internal bitmaps not supported by this kernel.\n"); return 1; } - if (!st->ss->add_internal_bitmap(super, bitmap_chunk, delay, write_behind, + if (!st->ss->add_internal_bitmap(st, super, bitmap_chunk, delay, write_behind, size ? size : maxsize)) { fprintf(stderr, Name ": Given bitmap chunk size not supported.\n"); return 1; @@ -451,7 +451,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, break; case 2: if (disk.state == 1) break; - st->ss->write_init_super(st, super, &disk, dv->devname); + st->ss->write_init_super(st, super, &disk, dv->devname, 64*2); if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", diff --git a/Grow.c b/Grow.c index 6157261..623daf3 100644 --- a/Grow.c +++ b/Grow.c @@ -273,7 +273,7 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int if (fd2 < 0) continue; if (st->ss->load_super(st, fd2, &super, NULL)==0) { - st->ss->add_internal_bitmap(super, + st->ss->add_internal_bitmap(st, super, chunk, delay, write_behind, array.size); st->ss->write_bitmap(st, fd2, super); diff --git a/Manage.c b/Manage.c index 4cf40e1..8cc977f 100644 --- a/Manage.c +++ b/Manage.c @@ -311,7 +311,7 @@ int Manage_subdevs(char *devname, int fd, if (dv->writemostly) disc.state |= 1 << MD_DISK_WRITEMOSTLY; st->ss->add_to_super(dsuper, &disc); - if (st->ss->write_init_super(st, dsuper, &disc, dv->devname)) + if (st->ss->write_init_super(st, dsuper, &disc, dv->devname, 0 /* FIXME */)) return 1; } else if (dv->re_add) { /* this had better be raid1. diff --git a/bitmap.c b/bitmap.c index 0a2ed5d..36ecd95 100644 --- a/bitmap.c +++ b/bitmap.c @@ -177,11 +177,12 @@ out: return info; } -bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st) +bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype **stp) { int fd; bitmap_info_t *info; struct stat stb; + struct supertype *st = *stp; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -199,6 +200,8 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st) } else { st->ss->locate_bitmap(st, fd); } + ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ + *stp = st; } info = bitmap_fd_read(fd, brief); @@ -206,6 +209,18 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st) return info; } +__u32 swapl(__u32 l) +{ + char *c = (char*)&l; + char t= c[0]; + c[0] = c[3]; + c[3] = t; + + t = c[1]; + c[1] = c[2]; + c[2] = t; + return l; +} int ExamineBitmap(char *filename, int brief, struct supertype *st) { /* @@ -217,7 +232,7 @@ int ExamineBitmap(char *filename, int brief, struct supertype *st) int rv = 1; char buf[64]; - info = bitmap_file_read(filename, brief, st); + info = bitmap_file_read(filename, brief, &st); if (!info) return rv; @@ -234,11 +249,19 @@ int ExamineBitmap(char *filename, int brief, struct supertype *st) } rv = 0; + if (st && st->ss->swapuuid) { + printf(" UUID : %08x.%08x.%08x.%08x\n", + swapl(*(__u32 *)(sb->uuid+0)), + swapl(*(__u32 *)(sb->uuid+4)), + swapl(*(__u32 *)(sb->uuid+8)), + swapl(*(__u32 *)(sb->uuid+12))); + } else { printf(" UUID : %08x.%08x.%08x.%08x\n", *(__u32 *)(sb->uuid+0), *(__u32 *)(sb->uuid+4), *(__u32 *)(sb->uuid+8), *(__u32 *)(sb->uuid+12)); + } printf(" Events : %llu\n", sb->events); printf(" Events Cleared : %llu\n", sb->events_cleared); printf(" State : %s\n", bitmap_state(sb->state)); diff --git a/mdadm.h b/mdadm.h index 547519c..06dd114 100644 --- a/mdadm.h +++ b/mdadm.h @@ -185,12 +185,12 @@ extern struct superswitch { int (*init_super)(struct supertype *st, void **sbp, mdu_array_info_t *info, char *name); void (*add_to_super)(void *sbv, mdu_disk_info_t *dinfo); int (*store_super)(struct supertype *st, int fd, void *sbv); - int (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname); + int (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname, int reserve); int (*compare_super)(void **firstp, void *secondv); int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname); struct supertype * (*match_metadata_desc)(char *arg); - __u64 (*avail_size)(__u64 size); - int (*add_internal_bitmap)(void *sbv, int chunk, int delay, int write_behind, unsigned long long size); + __u64 (*avail_size)(struct supertype *st, __u64 size, int reserve); + int (*add_internal_bitmap)(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size); void (*locate_bitmap)(struct supertype *st, int fd); int (*write_bitmap)(struct supertype *st, int fd, void *sbv); int major; diff --git a/super0.c b/super0.c index b028cff..496e3bb 100644 --- a/super0.c +++ b/super0.c @@ -472,7 +472,7 @@ static int store_super0(struct supertype *st, int fd, void *sbv) return 0; } -static int write_init_super0(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname) +static int write_init_super0(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname, int reserve) { mdp_super_t *sb = sbv; int fd = open(devname, O_RDWR|O_EXCL); @@ -664,14 +664,15 @@ static struct supertype *match_metadata_desc0(char *arg) return NULL; } -static __u64 avail_size0(__u64 devsize) +static __u64 avail_size0(struct supertype *st, __u64 devsize, int reserve) { if (devsize < MD_RESERVED_SECTORS*2) return 0ULL; + if (reserve > 64*2) return 0ULL; return MD_NEW_SIZE_SECTORS(devsize); } -static int add_internal_bitmap0(void *sbv, int chunk, int delay, int write_behind, unsigned long long size) +static int add_internal_bitmap0(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size) { /* * The bitmap comes immediately after the superblock and must be 60K in size diff --git a/super1.c b/super1.c index e25d005..d4e4f76 100644 --- a/super1.c +++ b/super1.c @@ -54,7 +54,11 @@ struct mdp_superblock_1 { __u32 chunksize; /* in 512byte sectors */ __u32 raid_disks; - __u8 pad1[128-96]; /* set to 0 when written */ + __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + __u8 pad1[128-100]; /* set to 0 when written */ /* constant this-device information - 64 bytes */ __u64 data_offset; /* sector start of data, often 0 */ @@ -131,8 +135,8 @@ static void examine_super1(void *sbv) printf(" Version : %02d.%02d\n", 1, __le32_to_cpu(sb->feature_map)); printf(" Array UUID : "); for (i=0; i<16; i++) { - printf("%02x", sb->set_uuid[i]); if ((i&3)==0 && i != 0) printf(":"); + printf("%02x", sb->set_uuid[i]); } printf("\n"); printf(" Name : %.32s\n", sb->set_name); @@ -151,13 +155,13 @@ static void examine_super1(void *sbv) printf(" State : %s\n", (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean"); printf(" Device UUID : "); for (i=0; i<16; i++) { - printf("%02x", sb->set_uuid[i]); if ((i&3)==0 && i != 0) printf(":"); + printf("%02x", sb->device_uuid[i]); } printf("\n"); if (sb->devflags) { printf(" Flags :"); - if (sb->devflags & WriteMostly1) + if (sb->devflags & WriteMostly1) printf(" write-mostly"); printf("\n"); } @@ -243,8 +247,8 @@ static void detail_super1(void *sbv) printf(" Name : %.32s\n", sb->set_name); printf(" UUID : "); for (i=0; i<16; i++) { - printf("%02x", sb->set_uuid[i]); if ((i&3)==0 && i != 0) printf(":"); + printf("%02x", sb->set_uuid[i]); } printf("\n Events : %llu\n\n", (unsigned long long)__le64_to_cpu(sb->events)); } @@ -258,8 +262,8 @@ static void brief_detail_super1(void *sbv) printf(" name=%.32s", sb->set_name); printf(" UUID="); for (i=0; i<16; i++) { - printf("%02x", sb->set_uuid[i]); if ((i&3)==0 && i != 0) printf(":"); + printf("%02x", sb->set_uuid[i]); } } @@ -385,8 +389,9 @@ static __u64 event_super1(void *sbv) static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info, char *name) { - struct mdp_superblock_1 *sb = malloc(1024); + struct mdp_superblock_1 *sb = malloc(1024 + sizeof(bitmap_super_t)); int spares; + int rfd; memset(sb, 0, 1024); if (info->major_version == -1) @@ -405,10 +410,15 @@ static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info, sb->major_version = __cpu_to_le32(1); sb->feature_map = 0; sb->pad0 = 0; - *(__u32*)(sb->set_uuid) = random(); - *(__u32*)(sb->set_uuid+4) = random(); - *(__u32*)(sb->set_uuid+8) = random(); - *(__u32*)(sb->set_uuid+12) = random(); + + if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || + read(rfd, sb->set_uuid, 16) != 16) { + *(__u32*)(sb->set_uuid) = random(); + *(__u32*)(sb->set_uuid+4) = random(); + *(__u32*)(sb->set_uuid+8) = random(); + *(__u32*)(sb->set_uuid+12) = random(); + } + if (rfd >= 0) close(rfd); memset(sb->set_name, 0, 32); strcpy(sb->set_name, name); @@ -431,7 +441,7 @@ static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info, sb->resync_offset = ~0ULL; else sb->resync_offset = 0; - sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/ + sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/ sizeof(sb->dev_roles[0])); memset(sb->pad3, 0, sizeof(sb->pad3)); @@ -450,7 +460,7 @@ static void add_to_super1(void *sbv, mdu_disk_info_t *dk) *rp = __cpu_to_le16(dk->raid_disk); else if ((dk->state & ~2) == 0) /* active or idle -> spare */ *rp = 0xffff; - else + else *rp = 0xfffe; } @@ -493,7 +503,7 @@ static int store_super1(struct supertype *st, int fd, void *sbv) } - + if (sb_offset != __le64_to_cpu(sb->super_offset) && 0 != __le64_to_cpu(sb->super_offset) ) { @@ -515,7 +525,9 @@ static int store_super1(struct supertype *st, int fd, void *sbv) static int load_super1(struct supertype *st, int fd, void **sbp, char *devname); -static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname) +static int write_init_super1(struct supertype *st, void *sbv, + mdu_disk_info_t *dinfo, char *devname, + int reserve) { struct mdp_superblock_1 *sb = sbv; struct mdp_superblock_1 *refsb = NULL; @@ -534,7 +546,7 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d } sb->dev_number = __cpu_to_le32(dinfo->number); - if (dinfo->state & (1<state & (1<devflags |= WriteMostly1; if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || @@ -556,7 +568,7 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d } free(refsb); } - + if (ioctl(fd, BLKGETSIZE, &size)) { close(fd); return 1; @@ -583,18 +595,18 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d sb_offset &= ~(4*2-1); sb->super_offset = __cpu_to_le64(sb_offset); sb->data_offset = __cpu_to_le64(0); - sb->data_size = sb->super_offset; + sb->data_size = __cpu_to_le64(sb_offset - reserve); break; case 1: sb->super_offset = __cpu_to_le64(0); - sb->data_offset = __cpu_to_le64(2); - sb->data_size = __cpu_to_le64(size - 2); + sb->data_offset = __cpu_to_le64(2 + reserve); + sb->data_size = __cpu_to_le64(size - 2 - reserve); break; case 2: sb_offset = 4*2; sb->super_offset = __cpu_to_le64(sb_offset); - sb->data_offset = __cpu_to_le64(sb_offset+2); - sb->data_size = __cpu_to_le64(size - 4*2 - 2); + sb->data_offset = __cpu_to_le64(sb_offset+2 + reserve); + sb->data_size = __cpu_to_le64(size - 4*2 - 2 - reserve); break; default: return -EINVAL; @@ -605,6 +617,30 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d rv = store_super1(st, fd, sb); if (rv) fprintf(stderr, Name ": failed to write superblock to %s\n", devname); + + if (__le32_to_cpu(sb->feature_map) & 1) { + /* write the bitmap */ + int towrite, n; + char buf[4096]; + + st->ss->locate_bitmap(st, fd); + write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t)); + towrite = 62*1024; + memset(buf, 0xff, sizeof(buf)); + while (towrite > 0) { + n=towrite; + if (n > sizeof(buf)) + n = sizeof(buf); + n = write(fd, buf, n); + if (n > 0) + towrite -= n; + else + break; + } + if (towrite) + rv = -2; + } + fsync(fd); close(fd); return rv; } @@ -686,7 +722,7 @@ static int load_super1(struct supertype *st, int fd, void **sbp, char *devname) return 2; } if (ioctl(fd, BLKGETSIZE, &size)) { - if (devname) + if (devname) fprintf(stderr, Name ": cannot find device size for %s: %s\n", devname, strerror(errno)); return 1; @@ -733,7 +769,7 @@ static int load_super1(struct supertype *st, int fd, void **sbp, char *devname) return 1; } - super = malloc(1024); + super = malloc(1024 + sizeof(bitmap_super_t)); if (read(fd, super, 1024) != 1024) { if (devname) @@ -795,12 +831,137 @@ static struct supertype *match_metadata_desc1(char *arg) return NULL; } -static __u64 avail_size1(__u64 devsize) +/* find available size on device with this devsize, using + * superblock type st, and reserving 'reserve' sectors for + * a possible bitmap + */ +static __u64 avail_size1(struct supertype *st, __u64 devsize, int reserve) { if (devsize < 24) return 0; - return (devsize - 8*2 ) & ~(4*2-1); + switch(st->minor_version) { + case 0: + /* at end, with reserve before it */ + return ((devsize - 8*2 ) & ~(4*2-1)) - reserve; + case 1: + /* at start, 1K for superblock */ + return devsize - 2 - reserve; + case 2: + /* 4k from start, 1K for superblock */ + return devsize - (4+1)*2 - reserve; + } + return 0; +} + +static int add_internal_bitmap1(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size) +{ + /* + * The bitmap comes immediately before of after the superblock and must be 62K in size + * at most. The default size is between 31K and 62K + * + * size is in K, chunk is in bytes !!! + */ + + unsigned long long bits = size; + unsigned long long max_bits = 62*1024*8; + unsigned long long min_chunk; + struct mdp_superblock_1 *sb = sbv; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024); + + + min_chunk = 4096; /* sub-page chunks don't work yet.. */ + while (bits > max_bits) { + min_chunk *= 2; + bits = (bits+1)/2; + } + if (chunk == UnSet) + chunk = min_chunk; + else if (chunk < min_chunk) + return 0; /* chunk size too small */ + + if (st->minor_version == 0) + sb->bitmap_offset = __cpu_to_le32(-64*2); + else + sb->bitmap_offset = __cpu_to_le32(2); + + sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1); + memset(bms, sizeof(*bms), 0); + bms->magic = __cpu_to_le32(BITMAP_MAGIC); + bms->version = __cpu_to_le32(BITMAP_MAJOR); + uuid_from_super1((int*)bms->uuid, sb); + bms->chunksize = __cpu_to_le32(chunk); + bms->daemon_sleep = __cpu_to_le32(delay); + bms->sync_size = __cpu_to_le64(size); + bms->write_behind = __cpu_to_le32(write_behind); + + + + return 1; +} + + +void locate_bitmap1(struct supertype *st, int fd) +{ + unsigned long long dsize; + unsigned long size; + unsigned long long offset; + + switch(st->minor_version){ + case 0: +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) + return; + else + dsize = ((unsigned long long)size)<<9; + } + + offset = (dsize - 8192) & ~4095ULL; + + offset -= 65536; + break; + + case 1: + offset = 1024; + break; + case 2: + offset = 4096+1024; + } + lseek64(fd, offset, 0); +} + +int write_bitmap1(struct supertype *st, int fd, void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + + int rv = 0; + + int towrite, n; + char buf[4096]; + + locate_bitmap1(st, fd); + + write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t)); + towrite = 62*1024 - sizeof(bitmap_super_t); + memset(buf, 0xff, sizeof(buf)); + while (towrite > 0) { + n = towrite; + if (n > sizeof(buf)) + n = sizeof(buf); + n = write(fd, buf, n); + if (n > 0) + towrite -= n; + else + break; + } + fsync(fd); + if (towrite) + rv = -2; + + return rv; } struct superswitch super1 = { @@ -822,6 +983,9 @@ struct superswitch super1 = { .load_super = load_super1, .match_metadata_desc = match_metadata_desc1, .avail_size = avail_size1, + .add_internal_bitmap = add_internal_bitmap1, + .locate_bitmap = locate_bitmap1, + .write_bitmap = write_bitmap1, .major = 1, #if __BYTE_ORDER == BIG_ENDIAN .swapuuid = 0, diff --git a/test b/test index dadca13..b505fa9 100644 --- a/test +++ b/test @@ -27,7 +27,9 @@ md0=/dev/md0 md1=/dev/md1 md2=/dev/md2 targetdir=/tmp size=20000 mdsize0=19904 -mdsize1=19992 +mdsize1=19928 +mdsize11=19935 +mdsize12=19931 cleanup() { $mdadm -Ss @@ -96,7 +98,7 @@ check() { bitmap ) grep -s bitmap > /dev/null /proc/mdstat || { - echo >&2 ERROR no bitmap ; cat /proc/mdstat ; exist 1; } + echo >&2 ERROR no bitmap ; cat /proc/mdstat ; exit 1; } ;; nobitmap ) if grep -s "bitmap" > /dev/null /proc/mdstat @@ -134,8 +136,10 @@ rotest() { -for script in tests/$prefix*[^~] +for script in tests/$prefix tests/$prefix*[^~] do + if [ -f "$script" ] + then # source script in a subshell, so it has access to our # namespace, but cannot change it. if ( set -ex ; . $script ) 2> $targetdir/log @@ -144,5 +148,6 @@ do echo "$script failed" exit 1 fi + fi done exit 0 diff --git a/tests/03r0assem b/tests/03r0assem index 0d53901..6428cc0 100644 --- a/tests/03r0assem +++ b/tests/03r0assem @@ -84,7 +84,7 @@ mdadm -A $md2 -u $uuid $devlist $tst mdadm -S $md2 -# version 1 has now super-minor +# version 1 has no super-minor # mdadm --assemble $md2 --super-minor=2 $devlist # # $tst # mdadm -S $md2