diff options
Diffstat (limited to '')
-rw-r--r-- | Grow.c | 150 |
1 files changed, 111 insertions, 39 deletions
@@ -23,6 +23,8 @@ */ #include "mdadm.h" #include "dlink.h" +#include "xmalloc.h" + #include <sys/mman.h> #include <stddef.h> #include <stdint.h> @@ -530,8 +532,10 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s) pr_err("Cannot add bitmap while array is resyncing or reshaping etc.\n"); pr_err("Cannot set bitmap file for %s: %s\n", devname, strerror(err)); + close_fd(&bitmap_fd); return 1; } + close_fd(&bitmap_fd); } return 0; @@ -1692,7 +1696,7 @@ char *analyse_change(char *devname, struct mdinfo *info, struct reshape *re) /* Current RAID6 layout has a RAID5 * equivalent - good */ - strcat(strcpy(layout, ls), "-6"); + snprintf(layout, 40, "%s-6", ls); l = map_name(r6layout, layout); if (l == UnSet) return "Cannot find RAID6 layout to convert to"; @@ -2032,7 +2036,8 @@ int Grow_reshape(char *devname, int fd, sysfs_free(sra); return 1; } else if (frozen < 0) { - pr_err("%s is performing resync/recovery and cannot be reshaped\n", devname); + pr_err("%s is performing resync/recovery and cannot be %s\n", devname, + (s->level != UnSet && s->level != array.level) ? "taken over" : "reshaped"); sysfs_free(sra); return 1; } @@ -2147,19 +2152,14 @@ int Grow_reshape(char *devname, int fd, if (s->size == MAX_SIZE) s->size = 0; array.size = s->size; - if (s->size & ~INT32_MAX) { - /* got truncated to 32bit, write to - * component_size instead - */ - rv = sysfs_set_num(sra, NULL, "component_size", s->size); - } else { - rv = md_set_array_info(fd, &array); + rv = sysfs_set_num(sra, NULL, "component_size", s->size); - /* manage array size when it is managed externally - */ - if ((rv == 0) && st->ss->external) - rv = set_array_size(st, sra, sra->text_version); - } + /* + * For native metadata, md/array_size is updated by kernel, + * for external management update it here. + */ + if (st->ss->external && rv == MDADM_STATUS_SUCCESS) + rv = set_array_size(st, sra, sra->text_version); if (raid0_takeover) { /* do not recync non-existing parity, @@ -2944,15 +2944,24 @@ static int impose_reshape(struct mdinfo *sra, * persists from some earlier problem. */ int err = 0; + if (sysfs_set_num(sra, NULL, "chunk_size", info->new_chunk) < 0) err = errno; + if (!err && sysfs_set_num(sra, NULL, "layout", reshape->after.layout) < 0) err = errno; + + /* new_level is introduced in kernel 6.12 */ + if (!err && sysfs_attribute_available(sra, NULL, "new_level") && + sysfs_set_num(sra, NULL, "new_level", info->new_level) < 0) + err = errno; + if (!err && subarray_set_num(container, sra, "raid_disks", reshape->after.data_disks + reshape->parity) < 0) err = errno; + if (err) { pr_err("Cannot set device shape for %s\n", devname); @@ -3028,6 +3037,13 @@ static int impose_level(int fd, int level, char *devname, int verbose) makedev(disk.major, disk.minor)); hot_remove_disk(fd, makedev(disk.major, disk.minor), 1); } + /* + * hot_remove_disk lets kernel set MD_RECOVERY_RUNNING + * and it can't set level. It needs to wait sometime + * to let md thread to clear the flag. + */ + pr_info("wait 5 seconds to give kernel space to finish job\n"); + sleep_for(5, 0, true); } c = map_num(pers, level); if (c) { @@ -3083,6 +3099,7 @@ static int reshape_array(char *container, int fd, char *devname, int done; struct mdinfo *sra = NULL; char buf[SYSFS_MAX_BUF_SIZE]; + bool located_backup = false; /* when reshaping a RAID0, the component_size might be zero. * So try to fix that up. @@ -3165,8 +3182,10 @@ static int reshape_array(char *container, int fd, char *devname, goto release; } - if (!backup_file) + if (!backup_file) { backup_file = locate_backup(sra->sys_name); + located_backup = true; + } goto started; } @@ -3261,7 +3280,12 @@ static int reshape_array(char *container, int fd, char *devname, /* This is a spare that wants to * be part of the array. */ - add_disk(fd, st, info2, d); + if (add_disk(fd, st, info2, d) < 0) { + pr_err("Can not add disk %s\n", + d->sys_name); + free(info2); + goto release; + } } } sysfs_free(info2); @@ -3607,15 +3631,13 @@ started: mdstat_wait(30 - (delayed-1) * 25); } while (delayed); mdstat_close(); - if (check_env("MDADM_GROW_VERIFY")) - fd = open(devname, O_RDONLY | O_DIRECT); - else - fd = -1; mlockall(MCL_FUTURE); if (signal_s(SIGTERM, catch_term) == SIG_ERR) goto release; + if (check_env("MDADM_GROW_VERIFY")) + fd = open(devname, O_RDONLY | O_DIRECT); if (st->ss->external) { /* metadata handler takes it from here */ done = st->ss->manage_reshape( @@ -3627,6 +3649,7 @@ started: fd, sra, &reshape, st, blocks, fdlist, offsets, d - odisks, fdlist + odisks, offsets + odisks); + close_fd(&fd); free(fdlist); free(offsets); @@ -3681,9 +3704,12 @@ started: set_array_size(st, info, info->text_version); if (info->new_level != reshape.level) { - if (fd < 0) - fd = open(devname, O_RDONLY); - impose_level(fd, info->new_level, devname, verbose); + fd = open_dev(sra->sys_name); + if (fd < 0) { + pr_err("Can't open %s\n", sra->sys_name); + goto out; + } + impose_level(fd, info->new_level, sra->sys_name, verbose); close(fd); if (info->new_level == 0) st->update_tail = NULL; @@ -3696,6 +3722,8 @@ out: exit(0); release: + if (located_backup) + free(backup_file); free(fdlist); free(offsets); if (orig_level != UnSet && sra) { @@ -3834,6 +3862,7 @@ int reshape_container(char *container, char *devname, pr_err("Unable to initialize sysfs for %s\n", mdstat->devnm); rv = 1; + close_fd(&fd); break; } @@ -4132,8 +4161,8 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape, * waiting forever on a dead array */ char action[SYSFS_MAX_BUF_SIZE]; - if (sysfs_get_str(info, NULL, "sync_action", action, sizeof(action)) <= 0 || - strncmp(action, "reshape", 7) != 0) + + if (sysfs_get_str(info, NULL, "sync_action", action, sizeof(action)) <= 0) break; /* Some kernels reset 'sync_completed' to zero * before setting 'sync_action' to 'idle'. @@ -4141,12 +4170,18 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape, */ if (completed == 0 && advancing && strncmp(action, "idle", 4) == 0 && - info->reshape_progress > 0) + info->reshape_progress > 0) { + info->reshape_progress = need_backup; break; + } if (completed == 0 && !advancing && strncmp(action, "idle", 4) == 0 && info->reshape_progress < - (info->component_size * reshape->after.data_disks)) + (info->component_size * reshape->after.data_disks)) { + info->reshape_progress = need_backup; + break; + } + if (strncmp(action, "reshape", 7) != 0) break; sysfs_wait(fd, NULL); if (sysfs_fd_get_ll(fd, &completed) < 0) @@ -4413,7 +4448,10 @@ static void validate(int afd, int bfd, unsigned long long offset) */ if (afd < 0) return; - lseek64(bfd, offset - 4096, 0); + if (lseek64(bfd, offset - 4096, 0) < 0) { + pr_err("lseek64 fails %d:%s\n", errno, strerror(errno)); + return; + } if (read(bfd, &bsb2, 512) != 512) fail("cannot read bsb"); if (bsb2.sb_csum != bsb_csum((char*)&bsb2, @@ -4444,12 +4482,19 @@ static void validate(int afd, int bfd, unsigned long long offset) } } - lseek64(bfd, offset, 0); + if (lseek64(bfd, offset, 0) < 0) { + pr_err("lseek64 fails %d:%s\n", errno, strerror(errno)); + goto out; + } if ((unsigned long long)read(bfd, bbuf, len) != len) { //printf("len %llu\n", len); fail("read first backup failed"); } - lseek64(afd, __le64_to_cpu(bsb2.arraystart)*512, 0); + + if (lseek64(afd, __le64_to_cpu(bsb2.arraystart)*512, 0) < 0) { + pr_err("lseek64 fails %d:%s\n", errno, strerror(errno)); + goto out; + } if ((unsigned long long)read(afd, abuf, len) != len) fail("read first from array failed"); if (memcmp(bbuf, abuf, len) != 0) @@ -4466,15 +4511,25 @@ static void validate(int afd, int bfd, unsigned long long offset) bbuf = xmalloc(abuflen); } - lseek64(bfd, offset+__le64_to_cpu(bsb2.devstart2)*512, 0); + if (lseek64(bfd, offset+__le64_to_cpu(bsb2.devstart2)*512, 0) < 0) { + pr_err("lseek64 fails %d:%s\n", errno, strerror(errno)); + goto out; + } if ((unsigned long long)read(bfd, bbuf, len) != len) fail("read second backup failed"); - lseek64(afd, __le64_to_cpu(bsb2.arraystart2)*512, 0); + if (lseek64(afd, __le64_to_cpu(bsb2.arraystart2)*512, 0) < 0) { + pr_err("lseek64 fails %d:%s\n", errno, strerror(errno)); + goto out; + } if ((unsigned long long)read(afd, abuf, len) != len) fail("read second from array failed"); if (memcmp(bbuf, abuf, len) != 0) fail("data2 compare failed"); } +out: + free(abuf); + free(bbuf); + return; } int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape, @@ -4692,6 +4747,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, unsigned long long *offsets; unsigned long long nstripe, ostripe; int ndata, odata; + int fd, backup_fd = -1; odata = info->array.raid_disks - info->delta_disks - 1; if (info->array.level == 6) @@ -4707,9 +4763,18 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, * been used */ old_disks = cnt; + + if (backup_file) { + backup_fd = open(backup_file, O_RDONLY); + if (!is_fd_valid(backup_fd)) { + pr_err("Can't open backup file %s : %s\n", + backup_file, strerror(errno)); + return -EINVAL; + } + } + for (i=old_disks-(backup_file?1:0); i<cnt; i++) { struct mdinfo dinfo; - int fd; int bsbsize; char *devname, namebuf[20]; unsigned long long lo, hi; @@ -4722,12 +4787,9 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, * else restore data and update all superblocks */ if (i == old_disks-1) { - fd = open(backup_file, O_RDONLY); - if (fd<0) { - pr_err("backup file %s inaccessible: %s\n", - backup_file, strerror(errno)); + if (!is_fd_valid(backup_fd)) continue; - } + fd = backup_fd; devname = backup_file; } else { fd = fdlist[i]; @@ -4882,6 +4944,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, pr_err("Error restoring backup from %s\n", devname); free(offsets); + close_fd(&backup_fd); return 1; } @@ -4898,6 +4961,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, pr_err("Error restoring second backup from %s\n", devname); free(offsets); + close_fd(&backup_fd); return 1; } @@ -4959,8 +5023,12 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, st->ss->store_super(st, fdlist[j]); st->ss->free_super(st); } + close_fd(&backup_fd); return 0; } + + close_fd(&backup_fd); + /* Didn't find any backup data, try to see if any * was needed. */ @@ -5033,7 +5101,11 @@ int Grow_continue_command(char *devname, int fd, struct context *c) goto Grow_continue_command_exit; } content = &array; - sysfs_init(content, fd, NULL); + if (sysfs_init(content, fd, NULL) < 0) { + pr_err("sysfs_init fails\n"); + ret_val = 1; + goto Grow_continue_command_exit; + } /* Need to load a superblock. * FIXME we should really get what we need from * sysfs |