diff --git a/Assemble.c b/Assemble.c index a8a331e..f38b1a1 100644 --- a/Assemble.c +++ b/Assemble.c @@ -31,7 +31,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, - mddev_dev_t devlist, + mddev_dev_t devlist, char *backup_file, int readonly, int runstop, char *update, int verbose, int force) @@ -585,7 +585,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, fdlist[i] = -1; } if (!err) - err = Grow_restart(st, &info, fdlist, bestcnt); + err = Grow_restart(st, &info, fdlist, bestcnt, backup_file); while (i>0) { i--; if (fdlist[i]>=0) close(fdlist[i]); diff --git a/ChangeLog b/ChangeLog index 22a97cc..4ee2dff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Changes Prior to 2.4 release - Put a 'canary' at each end of the backup so a corruption can be more easily detected. - Remove useless 'ident' arguement from ->getinfo_super method. + - Support --backup-file for backing-up critical section during growth. Changes Prior to 2.3.1 release - Fixed -O2 compile so I could make and RPM. diff --git a/Grow.c b/Grow.c index 04de455..4a225c7 100644 --- a/Grow.c +++ b/Grow.c @@ -408,7 +408,7 @@ int bsb_csum(char *buf, int len) return __cpu_to_le32(csum); } -int Grow_reshape(char *devname, int fd, int quiet, +int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, long long size, int level, int layout, int chunksize, int raid_disks) { @@ -625,8 +625,8 @@ int Grow_reshape(char *devname, int fd, int quiet, devname); return 1; } - if (sra->spares == 0) { - fprintf(stderr, Name ": %s: Cannot grow - need a spare to backup critical section\n", + if (sra->spares == 0 && backup_file == NULL) { + fprintf(stderr, Name ": %s: Cannot grow - need a spare or backup-file to backup critical section\n", devname); return 1; } @@ -634,13 +634,13 @@ int Grow_reshape(char *devname, int fd, int quiet, nrdisks = array.nr_disks + sra->spares; /* Now we need to open all these devices so we can read/write. */ - fdlist = malloc(nrdisks * sizeof(int)); - offsets = malloc(nrdisks * sizeof(offsets[0])); + fdlist = malloc((1+nrdisks) * sizeof(int)); + offsets = malloc((1+nrdisks) * sizeof(offsets[0])); if (!fdlist || !offsets) { fprintf(stderr, Name ": malloc failed: grow aborted\n"); return 1; } - for (d=0; d< nrdisks; d++) + for (d=0; d <= nrdisks; d++) fdlist[d] = -1; d = array.raid_disks; for (sd = sra->devs; sd; sd=sd->next) { @@ -674,8 +674,20 @@ int Grow_reshape(char *devname, int fd, int quiet, " --grow aborted\n", devname, i); goto abort; } + spares = sra->spares; + if (backup_file) { + fdlist[d] = open(backup_file, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fdlist[d] < 0) { + fprintf(stderr, Name ": %s: cannot create backup file %s: %s\n", + devname, backup_file, strerror(errno)); + goto abort; + } + offsets[d] = 8; + d++; + spares++; + } if (fdlist[array.raid_disks] < 0) { - fprintf(stderr, Name ": %s: failed to find a spare - --grow aborted\n", + fprintf(stderr, Name ": %s: failed to find a spare and no backup-file given - --grow aborted\n", devname); goto abort; } @@ -687,8 +699,6 @@ int Grow_reshape(char *devname, int fd, int quiet, goto abort; } - spares = sra->spares; - memcpy(bsb.magic, "md_backup_data-1", 16); st->ss->uuid_from_super((int*)&bsb.set_uuid, super); @@ -701,7 +711,11 @@ int Grow_reshape(char *devname, int fd, int quiet, */ for (i=array.raid_disks; icomponent_size - last_block - 8; + if (i==d-1 && backup_file) { + /* This is the backup file */ + offsets[i] = 8; + } else + offsets[i] += sra->component_size - last_block - 8; if (lseek64(fdlist[i], (offsets[i]<<9) - 4096, 0) != (offsets[i]<<9) - 4096) { fprintf(stderr, Name ": could not seek...\n"); @@ -739,7 +753,7 @@ int Grow_reshape(char *devname, int fd, int quiet, err = save_stripes(fdlist, offsets, odisks, ochunk, olevel, olayout, spares, fdlist+odisks, - 0ULL, nstripe*512); + 0ULL, last_block*512); /* abort if there was an error */ if (err < 0) { @@ -752,7 +766,8 @@ int Grow_reshape(char *devname, int fd, int quiet, bsb.devstart = __cpu_to_le64(offsets[i]); bsb.sb_csum = bsb_csum((char*)&bsb, ((char*)&bsb.sb_csum)-((char*)&bsb)); if (lseek64(fdlist[i], (offsets[i]+last_block)<<9, 0) < 0 || - write(fdlist[i], &bsb, sizeof(bsb)) != sizeof(bsb)) { + write(fdlist[i], &bsb, sizeof(bsb)) != sizeof(bsb) || + fsync(fdlist[i]) != 0) { fprintf(stderr, Name ": %s: fail to save metadata for critical region backups.\n", devname); goto abort_resume; @@ -792,6 +807,8 @@ int Grow_reshape(char *devname, int fd, int quiet, close(fdlist[i]); free(fdlist); free(offsets); + if (backup_file) + unlink(backup_file); printf(Name ": ... critical section passed.\n"); break; @@ -807,6 +824,8 @@ int Grow_reshape(char *devname, int fd, int quiet, close(fdlist[i]); free(fdlist); free(offsets); + if (backup_file) + unlink(backup_file); return 1; } @@ -816,7 +835,7 @@ int Grow_reshape(char *devname, int fd, int quiet, * write that data into the array and update the super blocks with * the new reshape_progress */ -int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt) +int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt, char *backup_file) { int i, j; int old_disks; @@ -832,11 +851,12 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt old_disks = info->array.raid_disks - info->delta_disks; - for (i=old_disks; iss->load_super(st, fdlist[i], &super, NULL)) - continue; + if (i == old_disks-1) { + fd = open(backup_file, O_RDONLY); + if (fd<0) + continue; + if (lseek(fd, 4096, 0) != 4096) + continue; + } else { + fd = fdlist[i]; + if (fd < 0) + continue; + if (st->ss->load_super(st, fd, &super, NULL)) + continue; - st->ss->getinfo_super(&dinfo, super); - free(super); super = NULL; - if (lseek64(fdlist[i], - (dinfo.data_offset + dinfo.component_size - 8) <<9, - 0) < 0) - continue; /* Cannot seek */ - if (read(fdlist[i], &bsb, sizeof(bsb)) != sizeof(bsb)) + st->ss->getinfo_super(&dinfo, super); + free(super); super = NULL; + if (lseek64(fd, + (dinfo.data_offset + dinfo.component_size - 8) <<9, + 0) < 0) + continue; /* Cannot seek */ + } + if (read(fd, &bsb, sizeof(bsb)) != sizeof(bsb)) continue; /* Cannot read */ if (memcmp(bsb.magic, "md_backup_data-1", 16) != 0) continue; @@ -875,15 +904,14 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt info->reshape_progress) continue; /* No new data here */ - if (lseek64(fdlist[i], __le64_to_cpu(bsb.devstart)*512, 0)< 0) + if (lseek64(fd, __le64_to_cpu(bsb.devstart)*512, 0)< 0) continue; /* Cannot seek */ /* There should be a duplicate backup superblock 4k before here */ - if (lseek64(fdlist[i], -4096, 1) < 0 || - read(fdlist[i], buf, 4096) != 4096 || + if (lseek64(fd, -4096, 1) < 0 || + read(fd, buf, 4096) != 4096 || memcmp(buf, &bsb, sizeof(buf)) != 0) continue; /* Cannot find leading superblock */ - /* Now need the data offsets for all devices. */ offsets = malloc(sizeof(*offsets)*info->array.raid_disks); for(j=0; jarray.raid_disks; j++) { @@ -903,7 +931,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt info->new_chunk, info->new_level, info->new_layout, - fdlist[i], __le64_to_cpu(bsb.devstart)*512, + fd, __le64_to_cpu(bsb.devstart)*512, 0, __le64_to_cpu(bsb.length)*512)) { /* didn't succeed, so giveup */ return -1; diff --git a/ReadMe.c b/ReadMe.c index c508a36..448e966 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -172,6 +172,8 @@ struct option long_options[] = { {"daemonize", 0, 0, 'f'}, {"oneshot", 0, 0, '1'}, {"pid-file", 1, 0, 'i'}, + /* For Grow */ + {"backup-file", 1,0, 7}, {0, 0, 0, 0} }; diff --git a/mdadm.c b/mdadm.c index 5347999..6e57c5b 100644 --- a/mdadm.c +++ b/mdadm.c @@ -62,6 +62,7 @@ int main(int argc, char *argv[]) int write_behind = 0; int bitmap_fd = -1; char *bitmap_file = NULL; + char *backup_file = NULL; int bitmap_chunk = UnSet; int SparcAdjust = 0; mddev_dev_t devlist = NULL; @@ -769,6 +770,18 @@ int main(int argc, char *argv[]) ident.bitmap_fd = bitmap_fd; /* for Assemble */ continue; + case O(ASSEMBLE, 7): + case O(GROW, 7): + /* Specify a file into which grow might place a backup, + * or from which assemble might recover a backup + */ + if (backup_file) { + fprintf(stderr, Name ": backup file already specified, rejecting %s\n", optarg); + exit(2); + } + backup_file = optarg; + continue; + case O(GROW,'b'): case O(BUILD,'b'): case O(CREATE,'b'): /* here we create the bitmap */ @@ -812,8 +825,13 @@ int main(int argc, char *argv[]) /* We have now processed all the valid options. Anything else is * an error */ - fprintf(stderr, Name ": option %c not valid in %s mode\n", - opt, map_num(modes, mode)); + if (option_index > 0) + fprintf(stderr, Name ":option --%s not valid in %s mode\n", + long_options[option_index].name, + map_num(modes, mode)); + else + fprintf(stderr, Name ": option -%c not valid in %s mode\n", + opt, map_num(modes, mode)); exit(2); } @@ -927,20 +945,24 @@ int main(int argc, char *argv[]) rv |= 1; else { rv |= Assemble(ss, devlist->devname, mdfd, array_ident, configfile, - NULL, + NULL, backup_file, readonly, runstop, update, verbose-quiet, force); close(mdfd); } } } else if (!scan) rv = Assemble(ss, devlist->devname, mdfd, &ident, configfile, - devlist->next, + devlist->next, backup_file, readonly, runstop, update, verbose-quiet, force); else if (devs_found>0) { if (update && devs_found > 1) { fprintf(stderr, Name ": can only update a single array at a time\n"); exit(1); } + if (backup_file && devs_found > 1) { + fprintf(stderr, Name ": can only assemble a single array when providing a backup file.\n"); + exit(1); + } for (dv = devlist ; dv ; dv=dv->next) { mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname); if (array_ident == NULL) { @@ -956,7 +978,7 @@ int main(int argc, char *argv[]) continue; } rv |= Assemble(ss, dv->devname, mdfd, array_ident, configfile, - NULL, + NULL, backup_file, readonly, runstop, update, verbose-quiet, force); close(mdfd); } @@ -966,6 +988,14 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": No arrays found in config file\n"); rv = 1; } else + if (update) { + fprintf(stderr, Name ": --update not meaningful with a --scan assembly.\n"); + exit(1); + } + if (backup_file) { + fprintf(stderr, Name ": --backup_file not meaningful with a --scan assembly.\n"); + exit(1); + } for (; array_list; array_list = array_list->next) { mdu_array_info_t array; mdfd = open_mddev(array_list->devname, @@ -980,7 +1010,7 @@ int main(int argc, char *argv[]) else rv |= Assemble(ss, array_list->devname, mdfd, array_list, configfile, - NULL, + NULL, NULL, readonly, runstop, NULL, verbose-quiet, force); close(mdfd); } @@ -1155,7 +1185,7 @@ int main(int argc, char *argv[]) } else if (layout != UnSet) rv = Manage_reconfig(devlist->devname, mdfd, layout); else if (size >= 0 || raiddisks) - rv = Grow_reshape(devlist->devname, mdfd, quiet, + rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file, size, level, layout, chunk, raiddisks); else if (bitmap_file) { if (delay == 0) delay = DEFAULT_BITMAP_DELAY; diff --git a/mdadm.h b/mdadm.h index c929be9..1752623 100644 --- a/mdadm.h +++ b/mdadm.h @@ -309,16 +309,17 @@ extern int Manage_subdevs(char *devname, int fd, mddev_dev_t devlist, int verbose); extern int Grow_Add_device(char *devname, int fd, char *newdev); extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force); -extern int Grow_reshape(char *devname, int fd, int quiet, +extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, long long size, int level, int layout, int chunksize, int raid_disks); -extern int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt); +extern int Grow_restart(struct supertype *st, struct mdinfo *info, + int *fdlist, int cnt, char *backup_file); extern int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, - mddev_dev_t devlist, + mddev_dev_t devlist, char *backup_file, int readonly, int runstop, char *update, int verbose, int force);