Status: ok Add support for internal bitmaps For version 0.90 superblocks, an internal bitmap can be specified at create. Signed-off-by: Neil Brown ### Diffstat output ./Create.c | 21 ++++++++++++ ./bitmap.c | 18 +++++++++-- ./md_p.h | 2 + ./mdadm.c | 12 ++++++- ./mdadm.h | 4 +- ./super0.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 147 insertions(+), 9 deletions(-) diff ./Create.c~current~ ./Create.c --- ./Create.c~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./Create.c 2005-05-06 12:54:33.000000000 +1000 @@ -341,11 +341,26 @@ int Create(struct supertype *st, char *m array.nr_disks = array.working_disks + array.failed_disks; array.layout = layout; array.chunk_size = chunk*1024; - printf("VERS = %d\n", vers); + if (!st->ss->init_super(&super, &array)) return 1; + if (bitmap_file && strcmp(bitmap_file, "internal")==0) { + if ((vers%100) < 2) { + fprintf(stderr, Name ": internal bitmaps not supported by this kernel.\n"); + return 1; + } + if (!st->ss->add_internal_bitmap(super, bitmap_chunk, delay, + size ? size : maxsize)) { + fprintf(stderr, Name ": Given bitmap chunk size not supported.\n"); + return 1; + } + bitmap_file = NULL; + } + + + if ((vers % 100) >= 1) { /* can use different versions */ mdu_array_info_t inf; memset(&inf, 0, sizeof(inf)); @@ -362,6 +377,10 @@ int Create(struct supertype *st, char *m if (bitmap_file) { int uuid[4]; + + if (bitmap_chunk == UnSet) + bitmap_chunk = DEFAULT_BITMAP_CHUNK; + st->ss->uuid_from_super(uuid, super); if (CreateBitmap(bitmap_file, force, (char*)uuid, bitmap_chunk, delay, array.size*2ULL /* FIXME wrong for raid10 */)) { diff ./bitmap.c~current~ ./bitmap.c --- ./bitmap.c~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./bitmap.c 2005-05-06 12:54:34.000000000 +1000 @@ -177,10 +177,11 @@ out: return info; } -bitmap_info_t *bitmap_file_read(char *filename, int brief) +bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st) { int fd; bitmap_info_t *info; + struct stat stb; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -188,13 +189,24 @@ bitmap_info_t *bitmap_file_read(char *fi filename, strerror(errno)); return NULL; } + fstat(fd, &stb); + if ((S_IFMT & stb.st_mode) == S_IFBLK) { + /* block device, so we are probably after an internal bitmap */ + if (!st) st = guess_super(fd); + if (!st) { + /* just look at device... */ + lseek(fd, 0, 0); + } else { + st->ss->locate_bitmap(st, fd); + } + } info = bitmap_fd_read(fd, brief); close(fd); return info; } -int ExamineBitmap(char *filename, int brief) +int ExamineBitmap(char *filename, int brief, struct supertype *st) { /* * Read the bitmap file and display its contents @@ -204,7 +216,7 @@ int ExamineBitmap(char *filename, int br bitmap_info_t *info; int rv = 1; - info = bitmap_file_read(filename, brief); + info = bitmap_file_read(filename, brief, st); if (!info) return rv; diff ./md_p.h~current~ ./md_p.h --- ./md_p.h~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./md_p.h 2005-05-06 12:54:34.000000000 +1000 @@ -96,6 +96,8 @@ typedef struct mdp_device_descriptor_s { #define MD_SB_CLEAN 0 #define MD_SB_ERRORS 1 +#define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ + typedef struct mdp_superblock_s { /* * Constant generic information diff ./mdadm.c~current~ ./mdadm.c --- ./mdadm.c~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./mdadm.c 2005-05-06 12:54:34.000000000 +1000 @@ -698,6 +698,10 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": bitmap file needed with -b in --assemble mode\n"); exit(2); } + if (strcmp(optarg, "internal")==0) { + fprintf(stderr, Name ": there is no need to specify --bitmap when assembling arrays with internal bitmaps\n"); + continue; + } bitmap_fd = open(optarg, O_RDWR); if (!*optarg || bitmap_fd < 0) { fprintf(stderr, Name ": cannot open bitmap file %s: %s\n", optarg, strerror(errno)); @@ -863,6 +867,11 @@ int main(int argc, char *argv[]) if (bitmap_chunk == UnSet) bitmap_chunk = DEFAULT_BITMAP_CHUNK; if (delay == 0) delay = DEFAULT_BITMAP_DELAY; if (bitmap_file) { + if (strcmp(bitmap_file, "internal")==0) { + fprintf(stderr, Name ": 'internal' bitmaps not supported with --build\n"); + rv |= 1; + break; + } bitmap_fd = open(bitmap_file, O_RDWR,0); if (bitmap_fd < 0 && errno != ENOENT) { perror(Name ": cannot create bitmap file"); @@ -879,7 +888,6 @@ int main(int argc, char *argv[]) bitmap_file, bitmap_chunk, delay); break; case CREATE: - if (bitmap_chunk == UnSet) bitmap_chunk = DEFAULT_BITMAP_CHUNK; if (delay == 0) delay = DEFAULT_BITMAP_DELAY; if (ss == NULL) { for(i=0; !ss && superlist[i]; i++) @@ -958,7 +966,7 @@ int main(int argc, char *argv[]) case 'Q': rv |= Query(dv->devname); continue; case 'X': - rv |= ExamineBitmap(dv->devname, brief); continue; + rv |= ExamineBitmap(dv->devname, brief, ss); continue; } mdfd = open_mddev(dv->devname, 0); if (mdfd>=0) { diff ./mdadm.h~current~ ./mdadm.h --- ./mdadm.h~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./mdadm.h 2005-05-06 12:54:34.000000000 +1000 @@ -185,6 +185,8 @@ extern struct superswitch { 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, unsigned long long size); + void (*locate_bitmap)(struct supertype *st, int fd); int major; } super0, super1, *superlist[]; @@ -240,7 +242,7 @@ extern int Kill(char *dev, int force); extern int CreateBitmap(char *filename, int force, char uuid[16], unsigned long chunksize, unsigned long daemon_sleep, unsigned long long array_size); -extern int ExamineBitmap(char *filename, int brief); +extern int ExamineBitmap(char *filename, int brief, struct supertype *st); extern int md_get_version(int fd); extern int get_linux_version(void); diff ./super0.c~current~ ./super0.c --- ./super0.c~current~ 2005-05-06 12:54:35.000000000 +1000 +++ ./super0.c 2005-05-06 12:54:34.000000000 +1000 @@ -28,6 +28,7 @@ */ #include "mdadm.h" +#include /* * All handling for the 0.90.0 version superblock is in @@ -81,6 +82,8 @@ static void examine_super0(void *sbv) printf(" Update Time : %.24s\n", ctime(&atime)); printf(" State : %s\n", (sb->state&(1<state & (1<active_disks); printf("Working Devices : %d\n", sb->working_disks); printf(" Failed Devices : %d\n", sb->failed_disks); @@ -324,9 +327,9 @@ static __u64 event_super0(void *sbv) static int init_super0(void **sbp, mdu_array_info_t *info) { - mdp_super_t *sb = malloc(MD_SB_BYTES); + mdp_super_t *sb = malloc(MD_SB_BYTES + sizeof(bitmap_super_t)); int spares; - memset(sb, 0, MD_SB_BYTES); + memset(sb, 0, MD_SB_BYTES + sizeof(bitmap_super_t)); if (info->major_version == -1) { /* zeroing the superblock */ @@ -434,6 +437,27 @@ static int write_init_super0(struct supe sb->this_disk = sb->disks[dinfo->number]; sb->sb_csum = calc_sb0_csum(sb); rv = store_super0(fd, sb); + + if (sb->state & (1< 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; + } + close(fd); if (rv) fprintf(stderr, Name ": failed to write superblock to %s\n", devname); @@ -584,6 +608,75 @@ static __u64 avail_size0(__u64 devsize) return MD_NEW_SIZE_SECTORS(devsize); } +static int add_internal_bitmap0(void *sbv, int chunk, int delay, unsigned long long size) +{ + /* + * The bitmap comes immediately after the superblock and must be 60K in size + * at most. The default size is between 30K and 60K + * + * size is in K, chunk is in bytes !!! + */ + + unsigned long long bits = size; + unsigned long long max_bits = 60*1024*8; + unsigned long long min_chunk; + mdp_super_t *sb = sbv; + bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MD_SB_BYTES); + + + min_chunk = 1024; + 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 */ + + sb->state |= (1<magic = __le32_to_cpu(BITMAP_MAGIC); + bms->version = __le32_to_cpu(BITMAP_MAJOR); + uuid_from_super0((int*)bms->uuid, sb); + bms->chunksize = __le32_to_cpu(chunk); + bms->daemon_sleep = __le32_to_cpu(delay); + bms->sync_size = __le64_to_cpu(size); + + + return 1; +} + + +void locate_bitmap0(struct supertype *st, int fd) +{ + unsigned long long dsize; + unsigned long size; + unsigned long long offset; +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) + return; + else + dsize = ((unsigned long long)size)<<9; + } + + if (dsize < MD_RESERVED_SECTORS*2) + return; + + offset = MD_NEW_SIZE_SECTORS(dsize>>9); + + offset *= 512; + + offset += MD_SB_BYTES; + + lseek64(fd, offset, 0); +} + + + struct superswitch super0 = { .examine_super = examine_super0, .brief_examine_super = brief_examine_super0, @@ -601,5 +694,7 @@ struct superswitch super0 = { .load_super = load_super0, .match_metadata_desc = match_metadata_desc0, .avail_size = avail_size0, + .add_internal_bitmap = add_internal_bitmap0, + .locate_bitmap = locate_bitmap0, .major = 0, };