diff options
70 files changed, 1462 insertions, 1203 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1230149 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/tools/.checkpatch.conf b/.github/tools/.checkpatch.conf new file mode 100644 index 0000000..d6e3bc4 --- /dev/null +++ b/.github/tools/.checkpatch.conf @@ -0,0 +1,10 @@ +--no-tree +--show-types +--exclude .github +--exclude clustermd_tests +--exclude documentation +--exclude misc +--exclude systemd +--exclude tests +--ignore FILE_PATH_CHANGES +--ignore EMAIL_SUBJECT diff --git a/.github/tools/install_ubuntu_packages.sh b/.github/tools/install_ubuntu_packages.sh new file mode 100755 index 0000000..1a31ca4 --- /dev/null +++ b/.github/tools/install_ubuntu_packages.sh @@ -0,0 +1,12 @@ +#!/usr/bin/bash + +VERSION_CODENAME=$(grep -oP '(?<=^VERSION_CODENAME=).+' /etc/os-release | tr -d '"') +echo "Detected VERSION_CODENAME: $VERSION_CODENAME" + +# Add ubuntu repository +sudo add-apt-repository -y "deb [arch=amd64] http://archive.ubuntu.com/ubuntu $VERSION_CODENAME \ + main universe" +# Install gcc +sudo apt-get -y update && sudo apt-get -y install gcc-$1 +# Install dependencies +sudo apt-get -y install make gcc libudev-dev devscripts diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml new file mode 100644 index 0000000..3fa29f6 --- /dev/null +++ b/.github/workflows/review.yml @@ -0,0 +1,41 @@ +name: review +on: [pull_request] +env: + cflags: -Werror +jobs: + make: + runs-on: ubuntu-latest + name: Compilation test with gcc + strategy: + matrix: + gcc-version: [7, 8, 9, 10, 11, 12, 13] + steps: + - uses: actions/checkout@v4 + - name: 'Add ubuntu repository and install dependencies' + run: .github/tools/install_ubuntu_packages.sh ${{ matrix.gcc-version }} + - name: 'Make with DEBUG flag' + run: CC=gcc-${{ matrix.gcc-version }} && V=1 make -j$(nproc) -B CXFLAGS=-DEBUG && make clean + - name: 'Make with DEBIAN flag' + run: CC=gcc-${{ matrix.gcc-version }} && V=1 make -j$(nproc) -B CXGALGS=-DEBIAN && make clean + - name: 'Make with USE_PTHREADS flag' + run: CC=gcc-${{ matrix.gcc-version }} && V=1 make -j$(nproc) -B CXFLAGS=-USE_PTHREADS && make clean + - name: 'Make with DNO_LIBUDEV flag' + run: CC=gcc-${{ matrix.gcc-version }} && V=1 make -j$(nproc) -B CXFLAGS=-DNO_LIBUDEV && make clean + - name: 'Make' + run: CC=gcc-${{ matrix.gcc-version }} && V=1 make -j$(nproc) + - name: hardening-check mdadm + run: hardening-check mdadm + - name: hardening-check mdmon + run: hardening-check mdmon + checkpatch: + runs-on: ubuntu-latest + name: checkpatch review + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + - name: 'Move prepared .checkpatch.conf file to main directory' + run: mv .github/tools/.checkpatch.conf . + - name: Run checkpatch review + uses: webispy/checkpatch-action@v9 @@ -567,6 +567,9 @@ static int select_devices(struct mddev_dev *devlist, tmpdev->used = 1; content = *contentp; + if (!st) + return -1; + if (!st->sb) { /* we need sb from one of the spares */ int dfd = dev_open(tmpdev->devname, O_RDONLY); @@ -652,7 +655,9 @@ static int load_devices(struct devs *devices, char *devmap, /* prepare useful information in info structures */ struct stat stb2; int err; - fstat(mdfd, &stb2); + + if (fstat(mdfd, &stb2) != 0) + goto error; if (c->update == UOPT_UUID && !ident->uuid_set) random_uuid((__u8 *)ident->uuid); @@ -675,13 +680,10 @@ static int load_devices(struct devs *devices, char *devmap, devname); if (dfd >= 0) close(dfd); - close(mdfd); - free(devices); - free(devmap); tst->ss->free_super(tst); free(tst); *stp = st; - return -1; + goto error; } tst->ss->getinfo_super(tst, content, devmap + devcnt * content->array.raid_disks); @@ -715,12 +717,9 @@ static int load_devices(struct devs *devices, char *devmap, map_num(update_options, c->update), tst->ss->name); tst->ss->free_super(tst); free(tst); - close(mdfd); close(dfd); - free(devices); - free(devmap); *stp = st; - return -1; + goto error; } if (c->update == UOPT_UUID && !ident->uuid_set) { @@ -751,18 +750,23 @@ static int load_devices(struct devs *devices, char *devmap, devname); if (dfd >= 0) close(dfd); - close(mdfd); - free(devices); - free(devmap); tst->ss->free_super(tst); free(tst); *stp = st; - return -1; + goto error; } tst->ss->getinfo_super(tst, content, devmap + devcnt * content->array.raid_disks); } - fstat(dfd, &stb); + if (fstat(dfd, &stb) != 0) { + close(dfd); + free(devices); + free(devmap); + tst->ss->free_super(tst); + free(tst); + *stp = st; + return -1; + } close(dfd); if (c->verbose > 0) @@ -814,12 +818,12 @@ static int load_devices(struct devs *devices, char *devmap, if (i >= bestcnt) { int newbestcnt = i+10; int *newbest = xmalloc(sizeof(int)*newbestcnt); - int c; - for (c=0; c < newbestcnt; c++) - if (c < bestcnt) - newbest[c] = best[c]; + int cc; + for (cc = 0; cc < newbestcnt; cc++) + if (cc < bestcnt) + newbest[cc] = best[cc]; else - newbest[c] = -1; + newbest[cc] = -1; if (best)free(best); best = newbest; bestcnt = newbestcnt; @@ -842,12 +846,9 @@ static int load_devices(struct devs *devices, char *devmap, inargv ? "the list" : "the\n DEVICE list in mdadm.conf" ); - close(mdfd); - free(devices); - free(devmap); free(best); *stp = st; - return -1; + goto error; } if (best[i] == -1 || (devices[best[i]].i.events < devices[devcnt].i.events)) @@ -863,6 +864,13 @@ static int load_devices(struct devs *devices, char *devmap, *bestp = best; *stp = st; return devcnt; + +error: + close(mdfd); + free(devices); + free(devmap); + return -1; + } static int force_array(struct mdinfo *content, @@ -1197,9 +1205,7 @@ static int start_array(int mdfd, rv = sysfs_set_str(content, NULL, "array_state", "readonly"); if (rv == 0) - rv = Grow_continue(mdfd, st, content, - c->backup_file, 0, - c->freeze_reshape); + rv = Grow_continue(mdfd, st, content, 0, c); } else if (c->readonly && sysfs_attribute_available(content, NULL, "array_state")) { @@ -1211,23 +1217,19 @@ static int start_array(int mdfd, if (rv == 0) { sysfs_rules_apply(mddev, content); if (c->verbose >= 0) { - pr_err("%s has been started with %d drive%s", + pr_info("%s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (okcnt < (unsigned)content->array.raid_disks) - fprintf(stderr, " (out of %d)", - content->array.raid_disks); + printf(" (out of %d)", content->array.raid_disks); if (rebuilding_cnt) - fprintf(stderr, "%s %d rebuilding", - sparecnt?",":" and", + printf("%s %d rebuilding", sparecnt?",":" and", rebuilding_cnt); if (sparecnt) - fprintf(stderr, " and %d spare%s", - sparecnt, + printf(" and %d spare%s", sparecnt, sparecnt == 1 ? "" : "s"); if (content->journal_clean) - fprintf(stderr, " and %d journal", - journalcnt); - fprintf(stderr, ".\n"); + printf(" and %d journal", journalcnt); + printf(".\n"); } if (content->reshape_active && is_level456(content->array.level)) { @@ -1494,8 +1496,11 @@ try_again: mp = map_by_uuid(&map, content->uuid); if (mp) { struct mdinfo *dv; - /* array already exists. */ pre_exist = sysfs_read(-1, mp->devnm, GET_LEVEL|GET_DEVS); + if (!pre_exist) + goto out; + + /* array already exists. */ if (pre_exist->array.level != UnSet) { pr_err("Found some drive for an array that is already active: %s\n", mp->path); @@ -1607,6 +1612,7 @@ try_again: err = assemble_container_content(st, mdfd, content, c, chosen_name, NULL); close(mdfd); + sysfs_free(pre_exist); return err; } @@ -1746,23 +1752,27 @@ try_again: : (O_RDONLY|O_EXCL)))< 0) { pr_err("Cannot open %s: %s\n", devices[j].devname, strerror(errno)); + free(avail); goto out; } if (st->ss->load_super(st,fd, NULL)) { close(fd); pr_err("RAID superblock has disappeared from %s\n", devices[j].devname); + free(avail); goto out; } close(fd); } if (st->sb == NULL) { pr_err("No suitable drives found for %s\n", mddev); + free(avail); goto out; } st->ss->getinfo_super(st, content, NULL); if (sysfs_init(content, mdfd, NULL)) { pr_err("Unable to initialize sysfs\n"); + free(avail); goto out; } @@ -1825,12 +1835,14 @@ try_again: if (fd < 0) { pr_err("Could not open %s for write - cannot Assemble array.\n", devices[chosen_drive].devname); + free(avail); goto out; } if (st->ss->store_super(st, fd)) { close(fd); pr_err("Could not re-write superblock on %s\n", devices[chosen_drive].devname); + free(avail); goto out; } if (c->verbose >= 0) @@ -1889,6 +1901,7 @@ try_again: pr_err("Failed to restore critical section for reshape, sorry.\n"); if (c->backup_file == NULL) cont_err("Possibly you needed to specify the --backup-file\n"); + free(avail); goto out; } } @@ -1917,6 +1930,7 @@ try_again: if (rv == 1 && !pre_exist) ioctl(mdfd, STOP_ARRAY, NULL); free(devices); + free(avail); out: map_unlock(&map); if (rv == 0) { @@ -1952,11 +1966,14 @@ out: close(mdfd); free(best); + sysfs_free(pre_exist); + /* '2' means 'OK, but not started yet' */ if (rv == -1) { free(devices); return 1; } + close(mdfd); return rv == 2 ? 0 : rv; } @@ -2175,13 +2192,12 @@ int assemble_container_content(struct supertype *st, int mdfd, if (!mdmon_running(st->container_devnm)) start_mdmon(st->container_devnm); ping_monitor(st->container_devnm); - if (mdmon_running(st->container_devnm) && - st->update_tail == NULL) + if (wait_for_mdmon(st->container_devnm) == MDADM_STATUS_SUCCESS && + !st->update_tail) st->update_tail = &st->updates; } - err = Grow_continue(mdfd, st, content, c->backup_file, - 0, c->freeze_reshape); + err = Grow_continue(mdfd, st, content, 0, c); } else switch(content->array.level) { case LEVEL_LINEAR: case LEVEL_MULTIPATH: @@ -168,13 +168,13 @@ int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s, goto abort; } } - if (bitmap_fd >= 0) { - if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) { - pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, - strerror(errno)); - goto abort; - } + if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) { + pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, + strerror(errno)); + close(bitmap_fd); + goto abort; } + close(bitmap_fd); } if (ioctl(mdfd, RUN_ARRAY, ¶m)) { pr_err("RUN_ARRAY failed: %s\n", strerror(errno)); @@ -178,6 +178,7 @@ static int wait_for_zero_forks(int *zero_pids, int count) bool interrupted = false; sigset_t sigset; ssize_t s; + pid_t pid; for (i = 0; i < count; i++) if (zero_pids[i]) @@ -196,7 +197,7 @@ static int wait_for_zero_forks(int *zero_pids, int count) return 1; } - while (1) { + while (wait_count) { s = read(sfd, &fdsi, sizeof(fdsi)); if (s != sizeof(fdsi)) { pr_err("Invalid signalfd read: %s\n", strerror(errno)); @@ -209,23 +210,24 @@ static int wait_for_zero_forks(int *zero_pids, int count) pr_info("Interrupting zeroing processes, please wait...\n"); interrupted = true; } else if (fdsi.ssi_signo == SIGCHLD) { - if (!--wait_count) - break; + for (i = 0; i < count; i++) { + if (!zero_pids[i]) + continue; + + pid = waitpid(zero_pids[i], &wstatus, WNOHANG); + if (pid <= 0) + continue; + + zero_pids[i] = 0; + if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) + ret = 1; + wait_count--; + } } } close(sfd); - for (i = 0; i < count; i++) { - if (!zero_pids[i]) - continue; - - waitpid(zero_pids[i], &wstatus, 0); - zero_pids[i] = 0; - if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) - ret = 1; - } - if (interrupted) { pr_err("zeroing interrupted!\n"); return 1; @@ -295,7 +297,7 @@ static int add_disk_to_super(int mdfd, struct shape *s, struct context *c, if (st->ss->add_to_super(st, &info->disk, fd, dv->devname, dv->data_offset)) { ioctl(mdfd, STOP_ARRAY, NULL); - close(fd); + close_fd(&fd); return 1; } st->ss->getinfo_super(st, info, NULL); @@ -399,6 +401,7 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, */ sigemptyset(&sigset); sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGCHLD); sigprocmask(SIG_BLOCK, &sigset, &orig_sigset); memset(zero_pids, 0, sizeof(zero_pids)); @@ -965,6 +968,13 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, return 1; } + if (st->ss == &super_imsm && s->level == 10 && s->raiddisks > 4) { + /* Print no matter runstop was specifed */ + pr_err("Warning! VROC UEFI driver does not support RAID10 in requested layout.\n"); + pr_err("Array won't be suitable as boot device.\n"); + warn = 1; + } + if (!have_container && s->level > 0 && ((maxsize-s->size)*100 > maxsize)) { if (c->runstop != 1 || c->verbose >= 0) pr_err("largest drive (%s) exceeds size (%lluK) by more than 1%%\n", @@ -984,7 +994,7 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, if (warn) { if (c->runstop!= 1) { - if (!ask("Continue creating array? ")) { + if (!ask("Continue creating array")) { pr_err("create aborted.\n"); return 1; } @@ -1334,9 +1344,11 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, if (c->verbose >= 0) pr_info("array %s started.\n", chosen_name); if (st->ss->external && st->container_devnm[0]) { - if (need_mdmon) + if (need_mdmon) { start_mdmon(st->container_devnm); - + if (wait_for_mdmon_control_socket(st->container_devnm) != MDADM_STATUS_SUCCESS) + goto abort; + } ping_monitor(st->container_devnm); close(container_fd); } @@ -1358,8 +1370,8 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, map_remove(&map, fd2devnm(mdfd)); map_unlock(&map); - if (mdfd >= 0) - close(mdfd); + close_fd(&mdfd); + close_fd(&container_fd); dev_policy_free(custom_pols); return 1; @@ -274,7 +274,7 @@ int Detail(char *dev, struct context *c) array.minor_version); } - if (info) + if (info && memcmp(info->uuid, uuid_zero, sizeof(int[4])) != 0) mp = map_by_uuid(&map, info->uuid); if (!mp) mp = map_by_devnm(&map, fd2devnm(fd)); @@ -37,6 +37,7 @@ int Dump_metadata(char *dev, char *dir, struct context *c, unsigned long long size; DIR *dirp; struct dirent *de; + int ret = 0; if (stat(dir, &stb) != 0 || (S_IFMT & stb.st_mode) != S_IFDIR) { @@ -112,9 +113,15 @@ int Dump_metadata(char *dev, char *dir, struct context *c, } if (c->verbose >= 0) printf("%s saved as %s.\n", dev, fname); - fstat(fd, &dstb); - close(fd); + close(fl); + ret = fstat(fd, &dstb); + close(fd); + if (ret) { + unlink(fname); + free(fname); + return 1; + } if ((dstb.st_mode & S_IFMT) != S_IFBLK) { /* Not a block device, so cannot create links */ free(fname); @@ -862,10 +862,7 @@ static void wait_reshape(struct mdinfo *sra) close(fd); } -static int reshape_super(struct supertype *st, unsigned long long size, - int level, int layout, int chunksize, int raid_disks, - int delta_disks, char *backup_file, char *dev, - int direction, int verbose) +static int reshape_super(struct supertype *st, struct shape *shape, struct context *c) { /* nothing extra to check in the native case */ if (!st->ss->external) @@ -876,9 +873,65 @@ static int reshape_super(struct supertype *st, unsigned long long size, return 1; } - return st->ss->reshape_super(st, size, level, layout, chunksize, - raid_disks, delta_disks, backup_file, dev, - direction, verbose); + return st->ss->reshape_super(st, shape, c); +} + +/** + * reshape_super_size() - Reshape array, size only. + * + * @st: supertype. + * @devname: device name. + * @size: component size. + * @dir metadata changes direction + * Returns: 0 on success, 1 otherwise. + * + * This function is solely used to change size of the volume. + * Setting size is not valid for container. + * Size is only change that can be rolled back, thus the @dir param. + */ +static int reshape_super_size(struct supertype *st, char *devname, + unsigned long long size, change_dir_t direction, + struct context *c) +{ + struct shape shape = {0}; + + shape.level = UnSet; + shape.layout = UnSet; + shape.delta_disks = UnSet; + shape.dev = devname; + shape.size = size; + shape.direction = direction; + + return reshape_super(st, &shape, c); +} + +/** + * reshape_super_non_size() - Reshape array, non size changes. + * + * @st: supertype. + * @devname: device name. + * @info: superblock info. + * Returns: 0 on success, 1 otherwise. + * + * This function is used for any external array changes but size. + * It handles both volumes and containers. + * For changes other than size, rollback is not possible. + */ +static int reshape_super_non_size(struct supertype *st, char *devname, + struct mdinfo *info, struct context *c) +{ + struct shape shape = {0}; + /* Size already set to zero, not updating size */ + shape.level = info->new_level; + shape.layout = info->new_layout; + shape.chunk = info->new_chunk; + shape.raiddisks = info->array.raid_disks; + shape.delta_disks = info->delta_disks; + shape.dev = devname; + /* Rollback not possible for non size changes */ + shape.direction = APPLY_METADATA_CHANGES; + + return reshape_super(st, &shape, c); } static void sync_metadata(struct supertype *st) @@ -1170,13 +1223,14 @@ int reshape_open_backup_file(char *backup_file, * way this will not notice, but it is better than * nothing. */ - fstat(*fdlist, &stb); + if (fstat(*fdlist, &stb) != 0) + goto error; dev = stb.st_dev; - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) + goto error; if (stb.st_rdev == dev) { pr_err("backup file must NOT be on the array being reshaped.\n"); - close(*fdlist); - return 0; + goto error; } memset(buf, 0, 512); @@ -1202,6 +1256,9 @@ int reshape_open_backup_file(char *backup_file, } return 1; +error: + close(*fdlist); + return 0; } unsigned long compute_backup_blocks(int nchunk, int ochunk, @@ -1764,9 +1821,8 @@ static int reshape_container(char *container, char *devname, int mdfd, struct supertype *st, struct mdinfo *info, - int force, - char *backup_file, int verbose, - int forked, int restart, int freeze_reshape); + struct context *c, + int forked, int restart); /** * prepare_external_reshape() - prepares update on external metadata if supported. @@ -1982,9 +2038,8 @@ int Grow_reshape(char *devname, int fd, } /* ========= set size =============== */ - if (s->size > 0 && - (s->size == MAX_SIZE || s->size != (unsigned)array.size)) { - unsigned long long orig_size = get_component_size(fd)/2; + if (s->size > 0 && (s->size == MAX_SIZE || s->size != (unsigned)array.size)) { + unsigned long long orig_size = get_component_size(fd) / 2; unsigned long long min_csize; struct mdinfo *mdi; int raid0_takeover = 0; @@ -2004,9 +2059,7 @@ int Grow_reshape(char *devname, int fd, goto release; } - if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet, NULL, - devname, APPLY_METADATA_CHANGES, - c->verbose > 0)) { + if (reshape_super_size(st, devname, s->size, APPLY_METADATA_CHANGES, c)) { rv = 1; goto release; } @@ -2085,7 +2138,7 @@ int Grow_reshape(char *devname, int fd, if (!mdmon_running(st->container_devnm)) start_mdmon(st->container_devnm); ping_monitor(container); - if (mdmon_running(st->container_devnm) == false) { + if (wait_for_mdmon(st->container_devnm) != MDADM_STATUS_SUCCESS) { pr_err("No mdmon found. Grow cannot continue.\n"); goto release; } @@ -2124,10 +2177,8 @@ size_change_error: int err = errno; /* restore metadata */ - if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0, - UnSet, NULL, devname, - ROLLBACK_METADATA_CHANGES, - c->verbose) == 0) + if (reshape_super_size(st, devname, orig_size, + ROLLBACK_METADATA_CHANGES, c) == 0) sync_metadata(st); pr_err("Cannot set device size for %s: %s\n", devname, strerror(err)); @@ -2338,8 +2389,7 @@ size_change_error: */ close_fd(&fd); rv = reshape_container(container, devname, -1, st, &info, - c->force, c->backup_file, c->verbose, - 0, 0, 0); + c, 0, 0); frozen = 0; } else { /* get spare devices from external metadata @@ -2356,13 +2406,9 @@ size_change_error: } /* Impose these changes on a single array. First - * check that the metadata is OK with the change. */ - - if (reshape_super(st, 0, info.new_level, - info.new_layout, info.new_chunk, - info.array.raid_disks, info.delta_disks, - c->backup_file, devname, - APPLY_METADATA_CHANGES, c->verbose)) { + * check that the metadata is OK with the change. + */ + if (reshape_super_non_size(st, devname, &info, c)) { rv = 1; goto release; } @@ -3176,7 +3222,8 @@ static int reshape_array(char *container, int fd, char *devname, if (!mdmon_running(container)) start_mdmon(container); ping_monitor(container); - if (mdmon_running(container) && st->update_tail == NULL) + if (wait_for_mdmon(container) == MDADM_STATUS_SUCCESS && + !st->update_tail) st->update_tail = &st->updates; } } @@ -3668,23 +3715,15 @@ int reshape_container(char *container, char *devname, int mdfd, struct supertype *st, struct mdinfo *info, - int force, - char *backup_file, int verbose, - int forked, int restart, int freeze_reshape) + struct context *c, + int forked, int restart) { struct mdinfo *cc = NULL; int rv = restart; char last_devnm[32] = ""; - /* component_size is not meaningful for a container, - * so pass '0' meaning 'no change' - */ - if (!restart && - reshape_super(st, 0, info->new_level, - info->new_layout, info->new_chunk, - info->array.raid_disks, info->delta_disks, - backup_file, devname, APPLY_METADATA_CHANGES, - verbose)) { + /* component_size is not meaningful for a container */ + if (!restart && reshape_super_non_size(st, devname, info, c)) { unfreeze(st); return 1; } @@ -3695,7 +3734,7 @@ int reshape_container(char *container, char *devname, */ ping_monitor(container); - if (!forked && !freeze_reshape) + if (!forked && !c->freeze_reshape) if (continue_via_systemd(container, GROW_SERVICE, NULL)) return 0; @@ -3705,7 +3744,7 @@ int reshape_container(char *container, char *devname, unfreeze(st); return 1; default: /* parent */ - if (!freeze_reshape) + if (!c->freeze_reshape) printf("%s: multi-array reshape continues in background\n", Name); return 0; case 0: /* child */ @@ -3802,12 +3841,12 @@ int reshape_container(char *container, char *devname, flush_mdmon(container); rv = reshape_array(container, fd, adev, st, - content, force, NULL, INVALID_SECTORS, - backup_file, verbose, 1, restart, - freeze_reshape); + content, c->force, NULL, INVALID_SECTORS, + c->backup_file, c->verbose, 1, restart, + c->freeze_reshape); close(fd); - if (freeze_reshape) { + if (c->freeze_reshape) { sysfs_free(cc); exit(0); } @@ -4449,7 +4488,6 @@ int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape, */ char *buf; int degraded = -1; - unsigned long long speed; unsigned long long suspend_point, array_size; unsigned long long backup_point, wait_point; unsigned long long reshape_completed; @@ -4505,10 +4543,6 @@ int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape, if (posix_memalign((void**)&buf, 4096, disks * chunk)) /* Don't start the 'reshape' */ return 0; - if (reshape->before.data_disks == reshape->after.data_disks) { - sysfs_get_ll(sra, NULL, "sync_speed_min", &speed); - sysfs_set_num(sra, NULL, "sync_speed_min", 200000); - } if (increasing) { array_size = sra->component_size * reshape->after.data_disks; @@ -4641,8 +4675,6 @@ int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape, sysfs_set_num(sra, NULL, "suspend_lo", 0); sysfs_set_num(sra, NULL, "sync_min", 0); - if (reshape->before.data_disks == reshape->after.data_disks) - sysfs_set_num(sra, NULL, "sync_speed_min", speed); free(buf); return done; } @@ -4970,8 +5002,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, return 1; } -int Grow_continue_command(char *devname, int fd, - char *backup_file, int verbose) +int Grow_continue_command(char *devname, int fd, struct context *c) { int ret_val = 0; struct supertype *st = NULL; @@ -5140,7 +5171,7 @@ int Grow_continue_command(char *devname, int fd, start_mdmon(container); ping_monitor(container); - if (mdmon_running(container) == false) { + if (wait_for_mdmon(container) != MDADM_STATUS_SUCCESS) { pr_err("No mdmon found. Grow cannot continue.\n"); ret_val = 1; goto Grow_continue_command_exit; @@ -5157,7 +5188,7 @@ int Grow_continue_command(char *devname, int fd, /* continue reshape */ - ret_val = Grow_continue(fd, st, content, backup_file, 1, 0); + ret_val = Grow_continue(fd, st, content, 1, c); Grow_continue_command_exit: if (cfd > -1) @@ -5171,7 +5202,7 @@ Grow_continue_command_exit: } int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info, - char *backup_file, int forked, int freeze_reshape) + int forked, struct context *c) { int ret_val = 2; @@ -5187,14 +5218,12 @@ int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info, st->ss->load_container(st, cfd, st->container_devnm); close(cfd); ret_val = reshape_container(st->container_devnm, NULL, mdfd, - st, info, 0, backup_file, 0, - forked, 1 | info->reshape_active, - freeze_reshape); + st, info, c, forked, 1 | info->reshape_active); } else ret_val = reshape_array(NULL, mdfd, "array", st, info, 1, - NULL, INVALID_SECTORS, backup_file, + NULL, INVALID_SECTORS, c->backup_file, 0, forked, 1 | info->reshape_active, - freeze_reshape); + c->freeze_reshape); return ret_val; } diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 9c79ba8..e5b635f 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,44 +1,29 @@ # Maintainer tools -Useful tools used in daily routines: +Useful tools for mdadm maintenance: - [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html) - [kup](https://korg.docs.kernel.org/kup.html) - [Auto-publishing](https://korg.docs.kernel.org/kup.html#auto-publishing-with-git-archive-signer) - [b4](https://b4.docs.kernel.org/en/latest/) -# Checklist before applying patch - -We don't have CI testing yet, so all those steps must be performed manually: -- Style check with [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html): - - This is the current code style follows. We are not strict to all rules. It must be run - by **checkpatch --no-tree**, see README.md. - -- [Commit style](https://www.kernel.org/doc/html/v4.10/process/submitting-patches.html): - - It doesn't need to be followed as strictly as is in kernel but changes should be logically - separated. Submitter should care at least to mention "It is used in next patches" if unused - externs/files are added in patch. We love: *Reported-by:*, *Suggested-by:*, *Fixes:* tags. - -- Compilation, ideally on various gcc versions. -- Mdadm test suite execution. -- Consider requesting new tests from submitter, especially for new functionalities. -- Ensure that maintainer *sign-off* is added, before pushing. - # Making a release Assuming that maintainer is certain that release is safe, following steps must be done: -- Update versions strings in release commit, please refer to previous releases for examples. +- Make and push release commit: + - Update versions strings, refer to previous releases for examples. + - Update CHANGELOG.md. + +- Create GPG signed tag and push it to both remotes. Use same format as was used previously, + prefixed by **mdadm-**, e.g. **mdadm-3.1.2**, **mdadm-4.1**. -- Create GPG signed tag and push it to repo. Use same format as was used previously, prefixed by - **mdadm-**, e.g. **mdadm-3.1.2**, **mdadm-4.1**. +- Run kernel.org + [Auto-publishing](https://korg.docs.kernel.org/kup.html#auto-publishing-with-git-archive-signer): -- [Auto-publishing](https://korg.docs.kernel.org/kup.html#auto-publishing-with-git-archive-signer): + Adopt script to our release tag model. When ready, push signed note to kernel.org repository. If + it is done correctly, then *(sig)* is added to the package automatically generated by + kernel.org automation. There is no need to upload archive manually. - Adopt script to our release tag model. When ready, push signed note to repository. If it is done - correctly, then *(sig)* is added to the package automatically generated by kernel.org automation. - There is no need to upload archive manually. +- Add release entry on Github. -- Update CHANGELOG.md. - Write "ANNOUNCE" mail to linux-raid@kernel.org to notify community. @@ -56,21 +56,21 @@ CWFLAGS += -Wp -O3 endif ifeq ($(origin FALLTHROUGH), undefined) - FALLTHROUGH := $(shell gcc -Q --help=warnings 2>&1 | grep "implicit-fallthrough" | wc -l) + FALLTHROUGH := $(shell $(CC) -Q --help=warnings 2>&1 | grep "implicit-fallthrough" | wc -l) ifneq "$(FALLTHROUGH)" "0" CWFLAGS += -Wimplicit-fallthrough=0 endif endif ifeq ($(origin FORMATOVERFLOW), undefined) - FORMATOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "format-overflow" | wc -l) + FORMATOVERFLOW := $(shell $(CC) -Q --help=warnings 2>&1 | grep "format-overflow" | wc -l) ifneq "$(FORMATOVERFLOW)" "0" CWFLAGS += -Wformat-overflow endif endif ifeq ($(origin STRINGOPOVERFLOW), undefined) - STRINGOPOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "stringop-overflow" | wc -l) + STRINGOPOVERFLOW := $(shell $(CC) -Q --help=warnings 2>&1 | grep "stringop-overflow" | wc -l) ifneq "$(STRINGOPOVERFLOW)" "0" CWFLAGS += -Wstringop-overflow endif @@ -132,12 +132,12 @@ CFLAGS += -DUSE_PTHREADS MON_LDFLAGS += -pthread endif -LDFLAGS = -Wl,-z,now,-z,noexecstack +LDFLAGS ?= -pie -Wl,-z,now,-z,noexecstack # If you want a static binary, you might uncomment these # LDFLAGS += -static # STRIP = -s -LDLIBS = -ldl -pie +LDLIBS = -ldl # To explicitly disable libudev, set -DNO_LIBUDEV in CXFLAGS ifeq (, $(findstring -DNO_LIBUDEV, $(CXFLAGS))) @@ -157,7 +157,7 @@ ifndef UDEVDIR UDEVDIR = /lib/udev endif -ifeq (,$(findstring s,$(MAKEFLAGS))) +ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS)))) ECHO=echo else ECHO=: @@ -56,7 +56,7 @@ int Manage_ro(char *devname, int fd, int readonly) vers[9] = '-'; sysfs_set_str(mdi, NULL, "metadata_version", vers); - close(fd); + close_fd(&fd); rv = sysfs_set_str(mdi, NULL, "array_state", "readonly"); if (rv < 0) { @@ -165,7 +165,7 @@ int Manage_run(char *devname, int fd, struct context *c) pr_err("Cannot find %s in sysfs!!\n", devname); return 1; } - strcpy(nm, nmp); + snprintf(nm, sizeof(nm), "%s", nmp); return IncrementalScan(c, nm); } @@ -187,7 +187,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) if (will_retry && verbose == 0) verbose = -1; - strcpy(devnm, fd2devnm(fd)); + snprintf(devnm, sizeof(devnm), "%s", fd2devnm(fd)); /* Get EXCL access first. If this fails, then attempting * to stop is probably a bad idea. */ @@ -195,7 +195,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) if (mdi && is_subarray(mdi->text_version)) sysfs_get_container_devnm(mdi, container); - close(fd); + close_fd(&fd); count = 5; while (((fd = ((devname[0] == '/') ?open(devname, O_RDONLY|O_EXCL) @@ -206,14 +206,12 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) * is a container, so we might be racing with mdmon, so * retry for a bit. */ - if (fd >= 0) - close(fd); + close_fd(&fd); flush_mdmon(container); count--; } if (fd < 0 || strcmp(fd2devnm(fd), devnm) != 0) { - if (fd >= 0) - close(fd); + close_fd(&fd); if (verbose >= 0) pr_err("Cannot get exclusive access to %s:Perhaps a running process, mounted filesystem or active volume group?\n", devname); @@ -228,7 +226,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) is_subarray(mdi->text_version)) { int err; /* This is mdmon managed. */ - close(fd); + close_fd(&fd); /* As we had an O_EXCL open, any use of the device * which blocks STOP_ARRAY is probably a transient use, @@ -430,8 +428,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) break; sysfs_wait(scfd, &delay); } - if (scfd >= 0) - close(scfd); + close_fd(&scfd); } done: @@ -463,12 +460,13 @@ done: } if (verbose >= 0) - pr_err("stopped %s\n", devname); + pr_info("stopped %s\n", devname); map_lock(&map); map_remove(&map, devnm); map_unlock(&map); out: sysfs_free(mdi); + close_fd(&fd); return rv; } @@ -664,7 +662,7 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv, devname, verbose, 0, NULL); if (rv == 0) rv = dev_st->ss->store_super(dev_st, tfd); - close(tfd); + close_fd(&tfd); if (rv != 0) { pr_err("failed to update superblock during re-add\n"); return -1; @@ -766,15 +764,15 @@ mdadm_status_t manage_add_external(struct supertype *st, int fd, char *disk_name rv = MDADM_STATUS_SUCCESS; out: - close(container_fd); + close_fd(&container_fd); dev_policy_free(pols); if (sra) sysfs_free(sra); - if (rv != MDADM_STATUS_SUCCESS && is_fd_valid(disk_fd)) + if (rv != MDADM_STATUS_SUCCESS) /* Metadata handler records this descriptor, so release it only on failure. */ - close(disk_fd); + close_fd(&disk_fd); if (st->sb) st->ss->free_super(st); @@ -845,10 +843,10 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, continue; if (tst->ss->load_super(tst, dfd, NULL)) { - close(dfd); + close_fd(&dfd); continue; } - close(dfd); + close_fd(&dfd); break; } /* FIXME this is a bad test to be using */ @@ -1100,7 +1098,8 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, */ int ret; char devnm[32]; - strcpy(devnm, fd2devnm(fd)); + + snprintf(devnm, sizeof(devnm), "%s", fd2devnm(fd)); lfd = open_dev_excl(devnm); if (lfd < 0) { pr_err("Cannot get exclusive access to container - odd\n"); @@ -1134,13 +1133,13 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, if (ret == 0) { pr_err("%s is not a member, cannot remove.\n", dv->devname); - close(lfd); + close_fd(&lfd); return -1; } if (ret >= 2) { pr_err("%s is still in use, cannot remove.\n", dv->devname); - close(lfd); + close_fd(&lfd); return -1; } } @@ -1157,26 +1156,27 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, /* Old kernels rejected this if no personality * is registered */ struct mdinfo *sra = sysfs_read(fd, NULL, GET_DEVS); - struct mdinfo *dv = NULL; - if (sra) - dv = sra->devs; - for ( ; dv ; dv=dv->next) - if (dv->disk.major == (int)major(rdev) && - dv->disk.minor == (int)minor(rdev)) - break; - if (dv) - err = sysfs_set_str(sra, dv, - "state", "remove"); - else + struct mdinfo *dev = NULL; + + if (!sra) { err = -1; - sysfs_free(sra); + } else { + for (dev = sra->devs; dev ; dev = dev->next) + if (dev->disk.major == (int)major(rdev) && + dev->disk.minor == (int)minor(rdev)) + break; + + if (dev) + err = sysfs_set_str(sra, dev, + "state", "remove"); + sysfs_free(sra); + } } } if (err) { pr_err("hot remove failed for %s: %s\n", dv->devname, strerror(errno)); - if (lfd >= 0) - close(lfd); + close_fd(&lfd); return -1; } if (tst->ss->external) { @@ -1190,13 +1190,13 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, if (!devnm) { pr_err("unable to get container name\n"); + close_fd(&lfd); return -1; } ping_manager(devnm); } - if (lfd >= 0) - close(lfd); + close_fd(&lfd); if (verbose >= 0) pr_err("hot removed %s from %s\n", dv->devname, devname); @@ -1218,7 +1218,7 @@ int Manage_replace(struct supertype *tst, int fd, struct mddev_dev *dv, if (!mdi || !mdi->devs) { pr_err("Cannot find status of %s to enable replacement - strange\n", devname); - return -1; + goto abort; } for (di = mdi->devs; di; di = di->next) if (di->disk.major == (int)major(rdev) && @@ -1229,16 +1229,14 @@ int Manage_replace(struct supertype *tst, int fd, struct mddev_dev *dv, if (di->disk.raid_disk < 0) { pr_err("%s is not active and so cannot be replaced.\n", dv->devname); - sysfs_free(mdi); - return -1; + goto abort; } rv = sysfs_set_str(mdi, di, "state", "want_replacement"); if (rv) { - sysfs_free(mdi); pr_err("Failed to request replacement for %s\n", dv->devname); - return -1; + goto abort; } if (verbose >= 0) pr_err("Marked %s (device %d in %s) for replacement\n", @@ -1252,11 +1250,13 @@ int Manage_replace(struct supertype *tst, int fd, struct mddev_dev *dv, dv->disposition = 'w'; dv->used = di->disk.raid_disk; } + sysfs_free(mdi); return 1; } - sysfs_free(mdi); pr_err("%s not found in %s so cannot --replace it\n", dv->devname, devname); +abort: + sysfs_free(mdi); return -1; } @@ -1269,7 +1269,7 @@ int Manage_with(struct supertype *tst, int fd, struct mddev_dev *dv, if (!mdi || !mdi->devs) { pr_err("Cannot find status of %s to enable replacement - strange\n", devname); - return -1; + goto abort; } for (di = mdi->devs; di; di = di->next) if (di->disk.major == (int)major(rdev) && @@ -1280,31 +1280,30 @@ int Manage_with(struct supertype *tst, int fd, struct mddev_dev *dv, if (di->disk.state & (1<<MD_DISK_FAULTY)) { pr_err("%s is faulty and cannot be a replacement\n", dv->devname); - sysfs_free(mdi); - return -1; + goto abort; } if (di->disk.raid_disk >= 0) { pr_err("%s is active and cannot be a replacement\n", dv->devname); - sysfs_free(mdi); - return -1; + goto abort; } rv = sysfs_set_num(mdi, di, "slot", dv->used); if (rv) { - sysfs_free(mdi); pr_err("Failed to set %s as preferred replacement.\n", dv->devname); - return -1; + goto abort; } if (verbose >= 0) pr_err("Marked %s in %s as replacement for device %d\n", dv->devname, devname, dv->used); + sysfs_free(mdi); return 1; } - sysfs_free(mdi); pr_err("%s not found in %s so cannot make it preferred replacement\n", dv->devname, devname); +abort: + sysfs_free(mdi); return -1; } @@ -1324,6 +1323,7 @@ bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const { dev_t devid = devnm2devid(devname + 5); struct mdinfo *mdi = sysfs_read(fd, NULL, GET_DEVS | GET_DISKS | GET_STATE); + struct mdinfo *disk; if (!mdi) { if (verbose) @@ -1333,14 +1333,14 @@ bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const char *avail = xcalloc(array->raid_disks, sizeof(char)); - for (mdi = mdi->devs; mdi; mdi = mdi->next) { - if (mdi->disk.raid_disk < 0) + for (disk = mdi->devs; disk; disk = disk->next) { + if (disk->disk.raid_disk < 0) continue; - if (!(mdi->disk.state & (1 << MD_DISK_SYNC))) + if (!(disk->disk.state & (1 << MD_DISK_SYNC))) continue; - if (makedev(mdi->disk.major, mdi->disk.minor) == devid) + if (makedev(disk->disk.major, disk->disk.minor) == devid) continue; - avail[mdi->disk.raid_disk] = 1; + avail[disk->disk.raid_disk] = 1; } sysfs_free(mdi); @@ -1550,7 +1550,7 @@ int Manage_subdevs(char *devname, int fd, rdev = makedev(mj,mn); found = 1; } - close(sysfd); + close_fd(&sysfd); sysfd = -1; } if (!found) { @@ -1572,7 +1572,7 @@ int Manage_subdevs(char *devname, int fd, tfd = dev_open(dv->devname, O_RDONLY); if (tfd >= 0) { fstat_is_blkdev(tfd, dv->devname, &rdev); - close(tfd); + close_fd(&tfd); } else { int open_err = errno; if (!stat_is_blkdev(dv->devname, &rdev)) { @@ -1635,7 +1635,7 @@ int Manage_subdevs(char *devname, int fd, * need non-exclusive access to add it, so * do that now. */ - close(tfd); + close_fd(&tfd); tfd = dev_open(dv->devname, O_RDONLY); } if (tfd < 0) { @@ -1654,8 +1654,7 @@ int Manage_subdevs(char *devname, int fd, rv = Manage_add(fd, tfd, dv, tst, &array, force, verbose, devname, update, rdev, array_size, raid_slot); - close(tfd); - tfd = -1; + close_fd(&tfd); if (rv < 0) goto abort; if (rv > 0) @@ -1672,7 +1671,7 @@ int Manage_subdevs(char *devname, int fd, rdev, verbose, force, devname); if (sysfd >= 0) - close(sysfd); + close_fd(&sysfd); sysfd = -1; if (rv < 0) goto abort; @@ -1684,8 +1683,7 @@ int Manage_subdevs(char *devname, int fd, if (!is_remove_safe(&array, fd, dv->devname, verbose)) { pr_err("Cannot remove %s from %s, array will be failed.\n", dv->devname, devname); - if (sysfd >= 0) - close(sysfd); + close_fd(&sysfd); goto abort; } case 'I': /* incremental fail */ @@ -1696,13 +1694,10 @@ int Manage_subdevs(char *devname, int fd, busy = 1; pr_err("set device faulty failed for %s: %s\n", dv->devname, strerror(errno)); - if (sysfd >= 0) - close(sysfd); + close_fd(&sysfd); goto abort; } - if (sysfd >= 0) - close(sysfd); - sysfd = -1; + close_fd(&sysfd); count++; if (verbose >= 0) pr_err("set %s faulty in %s\n", @@ -1762,7 +1757,7 @@ int autodetect(void) if (fd >= 0) { if (ioctl(fd, RAID_AUTORUN, 0) == 0) rv = 0; - close(fd); + close_fd(&fd); } return rv; } @@ -1825,7 +1820,7 @@ free_super: if (info) free(info); st->ss->free_super(st); - close(fd); + close_fd(&fd); return rv; } @@ -1843,10 +1838,8 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid) int fd2 = open(from_devname, O_RDONLY); if (fd1 < 0 || fd2 < 0) { - if (fd1 >= 0) - close(fd1); - if (fd2 >= 0) - close(fd2); + close_fd(&fd1); + close_fd(&fd2); return 0; } @@ -1865,15 +1858,15 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid) /* make sure manager is aware of changes */ ping_manager(to_devname); ping_manager(from_devname); - close(fd1); - close(fd2); + close_fd(&fd1); + close_fd(&fd2); return 1; } else Manage_subdevs(from_devname, fd2, &devlist, -1, 0, UOPT_UNDEFINED, 0); } - close(fd1); - close(fd2); + close_fd(&fd1); + close_fd(&fd2); return 0; } @@ -782,7 +782,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, if (!is_container && !md_array_active(fd)) goto disappeared; - fcntl(fd, F_SETFD, FD_CLOEXEC); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) + goto out; + if (md_get_array_info(fd, &array) < 0) goto disappeared; @@ -997,7 +999,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) snprintf(st->parent_devnm, MD_NAME_MAX, "%s", mse->metadata_version + 10); sl = strchr(st->parent_devnm, '/'); - *sl = 0; + if (sl) + *sl = 0; } else st->parent_devnm[0] = 0; *statelist = st; @@ -1261,7 +1264,7 @@ int Wait(char *dev) return 2; } - strcpy(devnm, tmp); + snprintf(devnm, sizeof(devnm), "%s", tmp); while(1) { struct mdstat_ent *ms = mdstat_read(1, 0); @@ -1332,7 +1335,8 @@ int WaitClean(char *dev, int verbose) return 1; } - strcpy(devnm, fd2devnm(fd)); + snprintf(devnm, sizeof(devnm), "%s", fd2devnm(fd)); + mdi = sysfs_read(fd, devnm, GET_VERSION|GET_LEVEL|GET_SAFEMODE); if (!mdi) { if (verbose) @@ -39,7 +39,7 @@ int Query(char *dev) struct mdinfo info; struct mdinfo *sra; struct supertype *st = NULL; - unsigned long long larray_size; + unsigned long long larray_size = 0; struct stat stb; char *mddev; mdu_disk_info_t disc; @@ -136,5 +136,7 @@ int Query(char *dev) if (st->ss == &super0) put_md_name(mddev); } + free(sra); + return 0; } @@ -20,58 +20,68 @@ **IMPORTANT:** DDF is in **maintenance only** mode. There is no active development around it. Please do not use it in new solutions. -# How to Contribute - - **mdadm** is hosted on [kernel.org](https://kernel.org/). You can access repository -[here](https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git). +# Questions and Support + +This Github site is **not** right place to ask if your are looking for: +- support from Linux Raid Community; +- support with kernel issues; + +This is the place where development of mdadm application is done. Please, do not use for +looking for support. You should always ask on [Mailing List](https://lore.kernel.org/linux-raid/). + +Please use issues if you have confirmation that issue you are experiencing is related to mdadm +components: +- mdadm; +- mdmon; +- raid6check; +- swap_super; +- test_stripe; +- systemd services ( see systemd/); +- udev rules; +- manual pages (including md.man) + +For example: +- mdadm issues (e.g segfaults, memory leaks, crashes, bad communication with MD driver); +- feature requests for mdadm; +- suggestions or minor fixes requested (e.g. better error messages); + +Generally, if you are not sure it is better to ask on +[Mailing List](https://lore.kernel.org/linux-raid/) first. -It is maintained similarly to kernel, using *mailing list*. Patches must be send through email. -Please familiarize with general kernel -[submitting patches](https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html) -documentation. Formatting, tags and commit message guidelines applies to **mdadm**. +# How to Contribute -## Sending patches step-by-step +Effective immediately [Github](https://github.com/md-raid-utilities/mdadm) is the primary +location for **mdadm**. Use pull request to contribute. -To maximize change of patches being taken, follow this instruction when submitting: +It was originally hosted on [kernel.org](https://kernel.org/). You can access the old repository +[here](https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git). -1. Create possibly logically separated commits and generate patches: +Patches sent through Mailing list are accepted but Github is preferred. Sent then to ML only +if you cannot use Github. Please add "mdadm:" to the subject to allow automation to create Github +Pull Request and run checks. - Use ``git format-patch --cover-letter --signoff -v <nr>`` to create patches: - * ``--cover-letter`` can be skipped if it is only one patch; - * ``--signoff`` adds sign-off tag; - * ``-v <nr>`` indicates review revision number, sender should increment it before resending. +**NOTE:** Maintainers may ask you to send RFC to mailing list if the proposed code requires +consultation with kernel developers. -2. Check style of every patch with kernel - [checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html) script: +Kernel coding style is used. Please familiarize with general kernel +[submitting patches](https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html) +documentation. Formatting, tags and commit message guidelines applies to **mdadm**. - It is important to keep same coding style that is why in **mdadm** - [kernel coding style](https://www.kernel.org/doc/html/v4.10/process/coding-style.html) - is preferred. ``checkpath --no-tree <patch_file>`` can be used to verify patches. - Following checkpatch issues can be ignored: - - New typedefs. - - comparing with *True/False*. - - kernel *MAINTAINERS* file warning. - - *extern* keyword in headers. +[Checkpatch](https://docs.kernel.org/dev-tools/checkpatch.html) script is run on +every patch in pull request so be sure that your commits are not generating +issues. There are some excludes, so the best is to follow github checkpatch action result. -3. Send patches using ``git send-mail --to=linux-raid@vger.kernel.org <cover-letter> <patch1> <patch2> (...)`` +Pull Request are closed by `Rebase and Merge` option, so it requires to keep every commit +meaningful. Kernel style requires that. The review changes must be pushed with **push --force** +to the chosen branch, then Pull Request will be automatically updated. -# Maintainers +# Maintainers of mdadm repository on kernel.org -It is good practice to add **mdadm maintainers** to recipients for patches: +If there are differences between github and kernel.org, please contact kernel.org mdadm maintainers: - Jes Sorensen <jes@trained-monkey.org>; - Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>; -Adding **MD maintainers** could be reasonable, especially if patches may affect MD driver: - -- Song Liu <song@kernel.org>; -- Yu Kuai <yukuai3@huawei.com>; - -# Reviewers - -**mdadm** utility is not part of kernel tree, so there is no certificated *Reviewers* list. Everyone -can comment on mailing list, last decision (and merging) belongs to maintainers. - # Minimal supported kernel version We do not support kernel versions below **v3.10**. Please be aware that maintainers may remove diff --git a/clustermd_tests/02r10_Manage_re-add b/clustermd_tests/02r10_Manage_re-add index 2288a00..d876466 100644 --- a/clustermd_tests/02r10_Manage_re-add +++ b/clustermd_tests/02r10_Manage_re-add @@ -9,7 +9,8 @@ check all state UU check all dmesg mdadm --manage $md0 --fail $dev0 --remove $dev0 mdadm --manage $md0 --re-add $dev0 -check $NODE1 recovery +#non-clustered array also doesn't do sync job +#check $NODE1 recovery check all wait check all state UU check all dmesg diff --git a/clustermd_tests/02r1_Manage_re-add b/clustermd_tests/02r1_Manage_re-add index d0d13e5..811df87 100644 --- a/clustermd_tests/02r1_Manage_re-add +++ b/clustermd_tests/02r1_Manage_re-add @@ -9,6 +9,7 @@ check all state UU check all dmesg mdadm --manage $md0 --fail $dev0 --remove $dev0 mdadm --manage $md0 --re-add $dev0 +check all wait check all state UU check all dmesg stop_md all $md0 diff --git a/clustermd_tests/03r10_switch-recovery b/clustermd_tests/03r10_switch-recovery index 867388d..7d0b881 100644 --- a/clustermd_tests/03r10_switch-recovery +++ b/clustermd_tests/03r10_switch-recovery @@ -10,9 +10,9 @@ check all state UU check all dmesg mdadm --manage $md0 --fail $dev0 sleep 0.2 -check $NODE1 recovery +check $NODE1 recovery-remote stop_md $NODE1 $md0 -check $NODE2 recovery +check $NODE2 recovery-remote check $NODE2 wait check $NODE2 state UU check all dmesg diff --git a/clustermd_tests/03r1_switch-recovery b/clustermd_tests/03r1_switch-recovery index a1a7cbe..d8483c4 100644 --- a/clustermd_tests/03r1_switch-recovery +++ b/clustermd_tests/03r1_switch-recovery @@ -10,9 +10,9 @@ check all state UU check all dmesg mdadm --manage $md0 --fail $dev0 sleep 0.3 -check $NODE1 recovery +check $NODE1 recovery-remote stop_md $NODE1 $md0 -check $NODE2 recovery +check $NODE2 recovery-remote check $NODE2 wait check $NODE2 state UU check all dmesg diff --git a/clustermd_tests/func.sh b/clustermd_tests/func.sh index 801d604..e659c0b 100644 --- a/clustermd_tests/func.sh +++ b/clustermd_tests/func.sh @@ -1,5 +1,22 @@ #!/bin/bash +COLOR_FAIL='\033[0;31m' #RED +COLOR_WARN='\033[1;33m' #YELLOW +COLOR_SUCCESS='\033[0;32m' #GREEN +COLOR_NONE='\033[0m' + +fail() { + printf "${COLOR_FAIL}$1${COLOR_NONE}" +} + +warn() { + printf "${COLOR_WARN}$1${COLOR_NONE}" +} + +succeed() { + printf "${COLOR_SUCCESS}$1${COLOR_NONE}" +} + check_ssh() { NODE1="$(grep '^NODE1' $CLUSTER_CONF | cut -d'=' -f2)" @@ -151,6 +168,33 @@ stop_md() fi } +record_system_speed_limit() { + system_speed_limit_max=`cat /proc/sys/dev/raid/speed_limit_max` + system_speed_limit_min=`cat /proc/sys/dev/raid/speed_limit_min` +} + +# To avoid sync action finishes before checking it, it needs to limit +# the sync speed +control_system_speed_limit() { + echo $test_speed_limit_min > /proc/sys/dev/raid/speed_limit_min + echo $test_speed_limit_max > /proc/sys/dev/raid/speed_limit_max +} + +restore_system_speed_limit() { + echo $system_speed_limit_min > /proc/sys/dev/raid/speed_limit_max + echo $system_speed_limit_max > /proc/sys/dev/raid/speed_limit_max +} + +record_selinux() { + # empty + return 0 +} + +restore_selinux() { + # empty + return 0 +} + # $1/optional, it shows why to save log save_log() { @@ -240,6 +284,22 @@ check() die "$ip: check '$2' failed." done ;; + recovery-remote ) + cnt=5 + for ip in ${NODES[@]} + do + while ! ssh $ip "grep -sqE 'recovery|REMOTE' /proc/mdstat" + do + if [ "$cnt" -gt '0' ] + then + sleep 0.2 + cnt=$[cnt-1] + else + die "$ip: no '$2' happening!" + fi + done + done + ;; PENDING | recovery | resync | reshape ) cnt=5 for ip in ${NODES[@]} @@ -188,8 +188,36 @@ inline void ident_init(struct mddev_ident *ident) ident->uuid_set = 0; } +/** ident_check_name() - helper function to verify name. + * @name: name to check. + * @prop_name: the name of the property it is validated against, used for logging. + * @cmdline: context dependent actions. + * + * @name must follow name's criteria, be POSIX compatible and does not have leading dot. + */ +static mdadm_status_t ident_check_name(const char *name, const char *prop_name, const bool cmdline) +{ + if (!is_string_lq(name, MD_NAME_MAX + 1)) { + ident_log(prop_name, name, "Too long or empty", cmdline); + return MDADM_STATUS_ERROR; + } + + if (*name == '.') { + /* MD device should not be considered as hidden. */ + ident_log(prop_name, name, "Leading dot forbidden", cmdline); + return MDADM_STATUS_ERROR; + } + + if (!is_name_posix_compatible(name)) { + ident_log(prop_name, name, "Not POSIX compatible", cmdline); + return MDADM_STATUS_ERROR; + } + + return MDADM_STATUS_SUCCESS; +} + /** - * _ident_set_devname()- verify devname and set it in &mddev_ident. + * _ident_set_devname() - verify devname and set it in &mddev_ident. * @ident: pointer to &mddev_ident. * @devname: devname to be set. * @cmdline: context dependent actions. If set, ignore keyword is not allowed. @@ -202,8 +230,7 @@ inline void ident_init(struct mddev_ident *ident) * /dev/md/{name} * {name} * - * {name} must follow name's criteria and be POSIX compatible. - * If criteria passed, duplicate memory and set devname in @ident. + * If verification passed, duplicate memory and set devname in @ident. * * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR. */ @@ -216,6 +243,7 @@ mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname static const char named_dev_pref[] = DEV_NUM_PREF "_"; static const int named_dev_pref_size = sizeof(named_dev_pref) - 1; const char *prop_name = "devname"; + mdadm_status_t ret; const char *name; if (ident->devname) { @@ -242,53 +270,40 @@ mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname else name = devname; - if (is_name_posix_compatible(name) == false) { - ident_log(prop_name, name, "Not POSIX compatible", cmdline); - return MDADM_STATUS_ERROR; - } - - if (is_string_lq(name, MD_NAME_MAX + 1) == false) { - ident_log(prop_name, devname, "Invalid length", cmdline); - return MDADM_STATUS_ERROR; - } + ret = ident_check_name(name, prop_name, cmdline); + if (ret) + return ret; pass: ident->devname = xstrdup(devname); return MDADM_STATUS_SUCCESS; } /** - * _ident_set_name()- set name in &mddev_ident. + * _ident_set_name() - set name in &mddev_ident. * @ident: pointer to &mddev_ident. * @name: name to be set. - * @cmdline: context dependent actions. * * If criteria passed, set name in @ident. * Note: name is not used by config file, it for cmdline only. * * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR. */ -static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *name, - const bool cmdline) +mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name) { assert(name); assert(ident); const char *prop_name = "name"; + mdadm_status_t ret; if (ident->name[0]) { - ident_log(prop_name, name, "Already defined", cmdline); - return MDADM_STATUS_ERROR; - } - - if (is_string_lq(name, MD_NAME_MAX + 1) == false) { - ident_log(prop_name, name, "Too long or empty", cmdline); + ident_log(prop_name, name, "Already defined", true); return MDADM_STATUS_ERROR; } - if (is_name_posix_compatible(name) == false) { - ident_log(prop_name, name, "Not POSIX compatible", cmdline); - return MDADM_STATUS_ERROR; - } + ret = ident_check_name(name, prop_name, true); + if (ret) + return ret; snprintf(ident->name, MD_NAME_MAX + 1, "%s", name); return MDADM_STATUS_SUCCESS; @@ -302,14 +317,6 @@ mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *name) return _ident_set_devname(ident, name, true); } -/** - * ident_set_name()- exported, for cmdline. - */ -mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name) -{ - return _ident_set_name(ident, name, true); -} - struct conf_dev { struct conf_dev *next; char *name; @@ -379,6 +386,7 @@ struct mddev_dev *load_containers(void) map = NULL; } free_mdstat(mdstat); + map_free(map); return rv; } @@ -949,7 +957,8 @@ void conf_file_or_dir(FILE *f) struct dirent *dp; struct fname *list = NULL; - fstat(fileno(f), &st); + if (fstat(fileno(f), &st) != 0) + return; if (S_ISREG(st.st_mode)) conf_file(f); else if (!S_ISDIR(st.st_mode)) diff --git a/drive_encryption.c b/drive_encryption.c index 27da962..63bdab1 100644 --- a/drive_encryption.c +++ b/drive_encryption.c @@ -65,6 +65,7 @@ #define SENSE_DATA_CURRENT_FIXED (0x70) #define SENSE_DATA_CURRENT_DESC (0x72) #define SENSE_CURRENT_RES_DESC_POS (8) +#define SENSE_RESPONSE_CODE_MASK (0x7f) #define SG_DRIVER_SENSE (0x08) typedef enum drive_feature_support_status { @@ -233,7 +234,7 @@ nvme_security_recv_ioctl(int disk_fd, __u8 sec_protocol, __u16 comm_id, void *re nvme_cmd.cdw10 = sec_protocol << 24 | comm_id << 8; nvme_cmd.cdw11 = buf_size; nvme_cmd.data_len = buf_size; - nvme_cmd.addr = (__u64)response_buffer; + nvme_cmd.addr = (__u64)(uintptr_t)response_buffer; status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd); if (status != 0) { @@ -268,7 +269,7 @@ nvme_identify_ioctl(int disk_fd, void *response_buffer, size_t buf_size, const i nvme_cmd.opcode = NVME_IDENTIFY; nvme_cmd.cdw10 = NVME_IDENTIFY_CONTROLLER_DATA; nvme_cmd.data_len = buf_size; - nvme_cmd.addr = (__u64)response_buffer; + nvme_cmd.addr = (__u64)(uintptr_t)response_buffer; status = ioctl(disk_fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd); if (status != 0) { @@ -473,6 +474,7 @@ ata_pass_through12_ioctl(int disk_fd, __u8 ata_command, __u8 sec_protocol, __u1 { __u8 cdb[ATA_INQUIRY_LENGTH] = {0}; __u8 sense[SG_SENSE_SIZE] = {0}; + __u8 sense_response_code; __u8 *sense_desc = NULL; sg_io_hdr_t sg = {0}; @@ -517,15 +519,17 @@ ata_pass_through12_ioctl(int disk_fd, __u8 ata_command, __u8 sec_protocol, __u1 return MDADM_STATUS_ERROR; } + sense_response_code = sense[0] & SENSE_RESPONSE_CODE_MASK; /* verify expected sense response code */ - if (!(sense[0] == SENSE_DATA_CURRENT_DESC || sense[0] == SENSE_DATA_CURRENT_FIXED)) { + if (!(sense_response_code == SENSE_DATA_CURRENT_DESC || + sense_response_code == SENSE_DATA_CURRENT_FIXED)) { pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s.\n", fd2kname(disk_fd)); return MDADM_STATUS_ERROR; } sense_desc = sense + SENSE_CURRENT_RES_DESC_POS; /* verify sense data current response with descriptor format */ - if (sense[0] == SENSE_DATA_CURRENT_DESC && + if (sense_response_code == SENSE_DATA_CURRENT_DESC && !(sense_desc[0] == ATA_STATUS_RETURN_DESCRIPTOR && sense_desc[1] == ATA_INQUIRY_LENGTH)) { pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s. Sense data ASC: %d, ASCQ: %d.\n", @@ -534,7 +538,7 @@ ata_pass_through12_ioctl(int disk_fd, __u8 ata_command, __u8 sec_protocol, __u1 } /* verify sense data current response with fixed format */ - if (sense[0] == SENSE_DATA_CURRENT_FIXED && + if (sense_response_code == SENSE_DATA_CURRENT_FIXED && !(sense[12] == ATA_PT_INFORMATION_AVAILABLE_ASC && sense[13] == ATA_PT_INFORMATION_AVAILABLE_ASCQ)) { pr_vrb("Failed ata passthrough12 ioctl. Device: /dev/%s. Sense data ASC: %d, ASCQ: %d.\n", @@ -109,7 +109,7 @@ char *devid2kname(dev_t devid) link[n] = 0; cp = strrchr(link, '/'); if (cp) { - strcpy(devnm, cp + 1); + snprintf(devnm, sizeof(devnm), "%s", cp + 1); return devnm; } } @@ -159,7 +159,7 @@ char *devid2devnm(dev_t devid) ep = strchr(cp, '/'); if (ep) *ep = 0; - strcpy(devnm, cp); + snprintf(devnm, sizeof(devnm), "%s", cp); return devnm; } } @@ -165,8 +165,8 @@ void map_add(struct map_ent **melp, { struct map_ent *me = xmalloc(sizeof(*me)); - strcpy(me->devnm, devnm); - strcpy(me->metadata, metadata); + snprintf(me->devnm, sizeof(me->devnm), "%s", devnm); + snprintf(me->metadata, sizeof(me->metadata), "%s", metadata); memcpy(me->uuid, uuid, 16); me->path = path ? xstrdup(path) : NULL; me->next = *melp; @@ -227,7 +227,7 @@ int map_update(struct map_ent **mpp, char *devnm, char *metadata, for (mp = map ; mp ; mp=mp->next) if (strcmp(mp->devnm, devnm) == 0) { - strcpy(mp->metadata, metadata); + snprintf(mp->metadata, sizeof(mp->metadata), "%s", metadata); memcpy(mp->uuid, uuid, 16); free(mp->path); mp->path = path ? xstrdup(path) : NULL; @@ -727,29 +727,25 @@ same as .TP .BR \-b ", " \-\-bitmap= -Specify a file to store a write-intent bitmap in. The file should not -exist unless -.B \-\-force -is also given. The same file should be provided -when assembling the array. If the word -.B "internal" -is given, then the bitmap is stored with the metadata on the array, -and so is replicated on all devices. If the word -.B "none" -is given with -.B \-\-grow -mode, then any bitmap that is present is removed. If the word -.B "clustered" -is given, the array is created for a clustered environment. One bitmap -is created for each node as defined by the +Specify how to store a write-intent bitmap. Following values are supported: + +.B internal +- the bitmap is stored with the metadata on the array and so is replicated on all devices. + +.B clustered +- the array is created for a clustered environment. One bitmap is created for each node as defined +by the .B \-\-nodes parameter and are stored internally. -To help catch typing errors, the filename must contain at least one -slash ('/') if it is a real file (not 'internal' or 'none'). +.B none +- create array with no bitmap or remove any present bitmap (grow mode). -Note: external bitmaps are only known to work on ext2 and ext3. -Storing bitmap files on other filesystems may result in serious problems. +Setting bitmap for file is deprecated and should not be used. The file should not exist unless +.B \-\-force +is also given. The same file should be provided when assembling the array. The file name must +contain at least one slash ('/'). Bitmap files are only known to work on ext2 and ext3. Storing +bitmap files on other filesystems may result in serious problems. When creating an array on devices which are 100G or larger, .I mdadm @@ -29,6 +29,51 @@ #include "md_p.h" #include <ctype.h> +/** + * set_bitmap_value() - set bitmap value. + * @s: Shape. + * @c: Context. + * @val: value to set. + * + * Validate and set bitmap. Context is needed for setting nodes for clustered bitmap. + */ +static mdadm_status_t set_bitmap_value(struct shape *s, struct context *c, char *val) +{ + if (s->bitmap_file) { + pr_err("--bitmap cannot be set twice. Second value: \"%s\".\n", val); + return MDADM_STATUS_ERROR; + } + + if (strcmp(val, "internal") == 0 || strcmp(optarg, STR_COMMON_NONE) == 0) { + s->bitmap_file = val; + return MDADM_STATUS_SUCCESS; + } + + if (strcmp(val, "clustered") == 0) { + s->bitmap_file = val; + /* Set the default number of cluster nodes + * to 4 if not already set by user + */ + if (c->nodes < 1) + c->nodes = 4; + return MDADM_STATUS_SUCCESS; + } + + if (strchr(val, '/')) { + pr_info("Custom write-intent bitmap file option is deprecated.\n"); + if (ask("Do you want to continue? (y/n)")) { + s->bitmap_file = val; + return MDADM_STATUS_SUCCESS; + } + + return MDADM_STATUS_ERROR; + } + + pr_err("--bitmap value must contain a '/' or be 'internal', 'clustered' or 'none'\n"); + pr_err("Current value is \"%s\"", val); + return MDADM_STATUS_ERROR; +} + static int scan_assemble(struct supertype *ss, struct context *c, struct mddev_ident *ident); @@ -1094,30 +1139,9 @@ int main(int argc, char *argv[]) case O(CREATE,Bitmap): /* here we create the bitmap */ case O(GROW,'b'): case O(GROW,Bitmap): - if (s.bitmap_file) { - pr_err("bitmap cannot be set twice. Second value: %s.\n", optarg); + if (set_bitmap_value(&s, &c, optarg)) exit(2); - } - if (strcmp(optarg, "internal") == 0 || - strcmp(optarg, STR_COMMON_NONE) == 0 || - strchr(optarg, '/') != NULL) { - s.bitmap_file = optarg; - continue; - } - if (strcmp(optarg, "clustered") == 0) { - s.bitmap_file = optarg; - /* Set the default number of cluster nodes - * to 4 if not already set by user - */ - if (c.nodes < 1) - c.nodes = 4; - continue; - } - /* probable typo */ - pr_err("bitmap file must contain a '/', or be 'internal', or be 'clustered', or 'none'\n" - " not '%s'\n", optarg); - exit(2); - + continue; case O(GROW,BitmapChunk): case O(BUILD,BitmapChunk): case O(CREATE,BitmapChunk): /* bitmap chunksize */ @@ -1636,7 +1660,7 @@ int main(int argc, char *argv[]) c.delay = DEFAULT_BITMAP_DELAY; rv = Grow_addbitmap(ident.devname, mdfd, &c, &s); } else if (grow_continue) - rv = Grow_continue_command(ident.devname, mdfd, c.backup_file, c.verbose); + rv = Grow_continue_command(ident.devname, mdfd, &c); else if (s.size > 0 || s.raiddisks || s.layout_str || s.chunk != 0 || s.level != UnSet || s.data_offset != INVALID_SECTORS) { @@ -223,6 +223,14 @@ struct dlm_lksb { struct __una_u16 { __u16 x; } __attribute__ ((packed)); struct __una_u32 { __u32 x; } __attribute__ ((packed)); +/* + * Ensure GNU basename behavior on GLIBC less systems. + */ +#ifndef __GLIBC__ +#define basename(path) \ + (strrchr((path), '/') ? strrchr((path),'/') + 1 : (path)) +#endif + static inline __u16 __get_unaligned16(const void *p) { const struct __una_u16 *ptr = (const struct __una_u16 *)p; @@ -535,7 +543,8 @@ enum special_options { }; enum update_opt { - UOPT_NAME = 1, + UOPT_UNDEFINED = 0, + UOPT_NAME, UOPT_PPL, UOPT_NO_PPL, UOPT_BITMAP, @@ -575,7 +584,6 @@ enum update_opt { UOPT_SPEC_FAILFAST, UOPT_SPEC_NOFAILFAST, UOPT_SPEC_REVERT_RESHAPE_NOBACKUP, - UOPT_UNDEFINED }; extern void fprint_update_options(FILE *outf, enum update_opt update_mode); @@ -594,6 +602,11 @@ enum flag_mode { FlagDefault, FlagSet, FlagClear, }; +typedef enum { + ROLLBACK_METADATA_CHANGES, + APPLY_METADATA_CHANGES +} change_dir_t; + /* structures read from config file */ /* List of mddevice names and identifiers * Identifiers can be: @@ -667,7 +680,9 @@ struct context { }; struct shape { + char *dev; int raiddisks; + int delta_disks; int sparedisks; int journaldisks; int level; @@ -682,6 +697,7 @@ struct shape { unsigned long long size; unsigned long long data_offset; int consistency_policy; + change_dir_t direction; }; /* List of device names - wildcards expanded */ @@ -1229,15 +1245,8 @@ extern struct superswitch { * initialized to indicate if reshape is being performed at the * container or subarray level */ -#define APPLY_METADATA_CHANGES 1 -#define ROLLBACK_METADATA_CHANGES 0 - - int (*reshape_super)(struct supertype *st, - unsigned long long size, int level, - int layout, int chunksize, int raid_disks, - int delta_disks, char *backup, char *dev, - int direction, - int verbose); /* optional */ + + int (*reshape_super)(struct supertype *st, struct shape *shape, struct context *c); int (*manage_reshape)( /* optional */ int afd, struct mdinfo *sra, struct reshape *reshape, struct supertype *st, unsigned long blocks, @@ -1541,8 +1550,7 @@ extern int Grow_reshape(char *devname, int fd, extern int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt, char *backup_file, int verbose); extern int Grow_continue(int mdfd, struct supertype *st, - struct mdinfo *info, char *backup_file, - int forked, int freeze_reshape); + struct mdinfo *info, int forked, struct context *c); extern int Grow_consistency_policy(char *devname, int fd, struct context *c, struct shape *s); @@ -1552,8 +1560,7 @@ extern int restore_backup(struct supertype *st, int spares, char **backup_filep, int verbose); -extern int Grow_continue_command(char *devname, int fd, - char *backup_file, int verbose); +extern int Grow_continue_command(char *devname, int fd, struct context *c); extern int Assemble(struct supertype *st, char *mddev, struct mddev_ident *ident, @@ -1769,8 +1776,11 @@ extern int is_subarray_active(char *subarray, char *devname); extern int open_subarray(char *dev, char *subarray, struct supertype *st, int quiet); extern struct superswitch *version_to_superswitch(char *vers); -extern int mdmon_running(char *devnm); -extern int mdmon_pid(char *devnm); +extern mdadm_status_t wait_for_mdmon_control_socket(const char *container_devnm); +extern int mdmon_running(const char *devnm); +extern int mdmon_pid(const char *devnm); +extern mdadm_status_t wait_for_mdmon(const char *devnm); + extern int check_env(char *name); extern __u32 random32(void); extern void random_uuid(__u8 *buf); @@ -348,7 +348,8 @@ void mdstat_wait_fd(int fd, const sigset_t *sigmask) if (fd >= 0) { struct stat stb; - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) + return; if ((stb.st_mode & S_IFMT) == S_IFREG) /* Must be a /proc or /sys fd, so expect * POLLPRI @@ -170,7 +170,7 @@ int connect_monitor(char *devname) addr.sun_family = PF_LOCAL; strcpy(addr.sun_path, path); - if (connect(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { close(sfd); return -1; } diff --git a/platform-intel.c b/platform-intel.c index ac282bc..d6a5353 100644 --- a/platform-intel.c +++ b/platform-intel.c @@ -32,6 +32,64 @@ #define NVME_SUBSYS_PATH "/sys/devices/virtual/nvme-subsystem/" +static bool imsm_orom_has_raid0(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID0); +} + +static bool imsm_orom_has_raid1(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID1); +} + +static bool imsm_orom_has_raid10(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID10); +} + +static bool imsm_orom_has_raid5(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID5); +} + +/* IMSM platforms do not define how many disks are allowed for each level, + * but there are some global limitations we need to follow. + */ +static bool imsm_orom_support_raid_disks_count_raid0(const int raid_disks) +{ + return true; +} + +static bool imsm_orom_support_raid_disks_count_raid1(const int raid_disks) +{ + if (raid_disks == 2) + return true; + return false; +} + +static bool imsm_orom_support_raid_disks_count_raid5(const int raid_disks) +{ + if (raid_disks > 2) + return true; + return false; +} + +static bool imsm_orom_support_raid_disks_count_raid10(const int raid_disks) +{ + /* raid_disks count must be higher than 4 and even */ + if (raid_disks >= 4 && (raid_disks & 1) == 0) + return true; + return false; +} + +struct imsm_level_ops imsm_level_ops[] = { + {0, imsm_orom_has_raid0, imsm_orom_support_raid_disks_count_raid0, "raid0"}, + {1, imsm_orom_has_raid1, imsm_orom_support_raid_disks_count_raid1, "raid1"}, + {5, imsm_orom_has_raid5, imsm_orom_support_raid_disks_count_raid5, "raid5"}, + {10, imsm_orom_has_raid10, imsm_orom_support_raid_disks_count_raid10, "raid10"}, + {-1, NULL, NULL, NULL} +}; + static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val); @@ -849,14 +907,14 @@ char *get_nvme_multipath_dev_hw_path(const char *dev_path) return NULL; for (ent = readdir(dir); ent; ent = readdir(dir)) { - char buf[strlen(dev_path) + strlen(ent->d_name) + 1]; + char buf[PATH_MAX]; /* Check if dir is a controller, ignore namespaces*/ if (!(strncmp(ent->d_name, "nvme", 4) == 0) || (strrchr(ent->d_name, 'n') != &ent->d_name[0])) continue; - sprintf(buf, "%s/%s", dev_path, ent->d_name); + snprintf(buf, PATH_MAX, "%s/%s", dev_path, ent->d_name); rp = realpath(buf, NULL); break; } diff --git a/platform-intel.h b/platform-intel.h index 3c2bc59..dcc5aaa 100644 --- a/platform-intel.h +++ b/platform-intel.h @@ -109,25 +109,21 @@ struct imsm_orom { #define IMSM_OROM_CAPABILITIES_TPV (1 << 10) } __attribute__((packed)); -static inline int imsm_orom_has_raid0(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID0); -} -static inline int imsm_orom_has_raid1(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID1); -} -static inline int imsm_orom_has_raid1e(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID1E); -} -static inline int imsm_orom_has_raid10(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID10); -} -static inline int imsm_orom_has_raid5(const struct imsm_orom *orom) +/* IMSM metadata requirements for each level */ +struct imsm_level_ops { + int level; + bool (*is_level_supported)(const struct imsm_orom *); + bool (*is_raiddisks_count_supported)(const int); + char *name; +}; + +extern struct imsm_level_ops imsm_level_ops[]; + +static inline bool imsm_rlc_has_bit(const struct imsm_orom *orom, const unsigned short bit) { - return !!(orom->rlc & IMSM_OROM_RLC_RAID5); + if (orom->rlc & bit) + return true; + return false; } /** diff --git a/super-ddf.c b/super-ddf.c index 21426c7..d870102 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -809,7 +809,7 @@ static int load_ddf_header(int fd, unsigned long long lba, if (lba >= size-1) return 0; - if (lseek64(fd, lba<<9, 0) < 0) + if (lseek64(fd, lba << 9, 0) == -1L) return 0; if (read(fd, hdr, 512) != 512) @@ -828,8 +828,7 @@ static int load_ddf_header(int fd, unsigned long long lba, !be64_eq(anchor->primary_lba, hdr->primary_lba) || !be64_eq(anchor->secondary_lba, hdr->secondary_lba) || hdr->type != type || - memcmp(anchor->pad2, hdr->pad2, 512 - - offsetof(struct ddf_header, pad2)) != 0) { + memcmp(anchor->pad2, hdr->pad2, sizeof(anchor->pad2)) != 0) { pr_err("header mismatch\n"); return 0; } @@ -863,7 +862,7 @@ static void *load_section(int fd, struct ddf_super *super, void *buf, else offset += be64_to_cpu(super->active->secondary_lba); - if ((unsigned long long)lseek64(fd, offset<<9, 0) != (offset<<9)) { + if ((unsigned long long)lseek64(fd, offset << 9, 0) != (offset << 9)) { if (dofree) free(buf); return NULL; @@ -882,7 +881,7 @@ static int load_ddf_headers(int fd, struct ddf_super *super, char *devname) get_dev_size(fd, NULL, &dsize); - if (lseek64(fd, dsize-512, 0) < 0) { + if (lseek64(fd, dsize - 512, 0) == -1L) { if (devname) pr_err("Cannot seek to anchor block on %s: %s\n", devname, strerror(errno)); @@ -909,8 +908,7 @@ static int load_ddf_headers(int fd, struct ddf_super *super, char *devname) if (memcmp(super->anchor.revision, DDF_REVISION_0, 8) != 0 && memcmp(super->anchor.revision, DDF_REVISION_2, 8) != 0) { if (devname) - pr_err("can only support super revision %.8s and earlier, not %.8s on %s\n", - DDF_REVISION_2, super->anchor.revision,devname); + pr_err("The DDF revision on %s\n is not supported", devname); return 2; } super->active = NULL; @@ -1053,7 +1051,10 @@ static int load_ddf_local(int fd, struct ddf_super *super, 0); dl->devname = devname ? xstrdup(devname) : NULL; - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) { + free(dl); + return 1; + } dl->major = major(stb.st_rdev); dl->minor = minor(stb.st_rdev); dl->next = super->dlist; @@ -1607,6 +1608,7 @@ static unsigned int get_vd_num_of_subarray(struct supertype *st) return DDF_NOTFOUND; } + sysfs_free(sra); return vcnum; } @@ -1614,11 +1616,11 @@ static void brief_examine_super_ddf(struct supertype *st, int verbose) { /* We just write a generic DDF ARRAY entry */ - struct mdinfo info; + struct mdinfo info = {0}; char nbuf[64]; + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(&info, nbuf); - printf("ARRAY metadata=ddf UUID=%s\n", nbuf + 5); } @@ -1628,9 +1630,10 @@ static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) * by uuid and member by unit number and uuid. */ struct ddf_super *ddf = st->sb; - struct mdinfo info; + struct mdinfo info = {0}; unsigned int i; char nbuf[64]; + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(&info, nbuf); @@ -1655,8 +1658,9 @@ static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) static void export_examine_super_ddf(struct supertype *st) { - struct mdinfo info; + struct mdinfo info = {0}; char nbuf[64]; + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(&info, nbuf); printf("MD_METADATA=ddf\n"); @@ -1689,10 +1693,12 @@ static int copy_metadata_ddf(struct supertype *st, int from, int to) if (!get_dev_size(from, NULL, &dsize)) goto err; - if (lseek64(from, dsize-512, 0) < 0) + if (lseek64(from, dsize - 512, 0) == -1L) goto err; + if (read(from, buf, 512) != 512) goto err; + ddf = buf; if (!be32_eq(ddf->magic, DDF_HEADER_MAGIC) || !be32_eq(calc_crc(ddf, 512), ddf->crc) || @@ -1708,9 +1714,9 @@ static int copy_metadata_ddf(struct supertype *st, int from, int to) bytes = dsize - offset; - if (lseek64(from, offset, 0) < 0 || - lseek64(to, offset, 0) < 0) + if (lseek64(from, offset, 0) == -1L || lseek64(to, offset, 0) == -1L) goto err; + while (written < bytes) { int n = bytes - written; if (n > 4096) @@ -1792,6 +1798,7 @@ static void brief_detail_super_ddf(struct supertype *st, char *subarray) char nbuf[64]; struct ddf_super *ddf = st->sb; unsigned int vcnum = get_vd_num_of_subarray(st); + if (vcnum == DDF_CONTAINER) uuid_from_super_ddf(st, info.uuid); else if (vcnum == DDF_NOTFOUND) @@ -2786,7 +2793,8 @@ static int add_to_super_ddf(struct supertype *st, /* This is device numbered dk->number. We need to create * a phys_disk entry and a more detailed disk_data entry. */ - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) + return 1; n = find_unused_pde(ddf); if (n == DDF_NOTFOUND) { pr_err("No free slot in array, cannot add disk\n"); @@ -2967,7 +2975,9 @@ static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type) header->openflag = 1; header->crc = calc_crc(header, 512); - lseek64(fd, sector<<9, 0); + if (lseek64(fd, sector << 9, 0) == -1L) + goto out; + if (write(fd, header, 512) < 0) goto out; @@ -2978,6 +2988,7 @@ static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type) ddf->phys->crc = calc_crc(ddf->phys, ddf->pdsize); if (write(fd, ddf->phys, ddf->pdsize) < 0) goto out; + ddf->virt->crc = calc_crc(ddf->virt, ddf->vdsize); if (write(fd, ddf->virt, ddf->vdsize) < 0) goto out; @@ -3031,7 +3042,9 @@ out: header->openflag = 0; header->crc = calc_crc(header, 512); - lseek64(fd, sector<<9, 0); + if (lseek64(fd, sector << 9, 0) == -1L) + return 0; + if (write(fd, header, 512) < 0) ret = 0; @@ -3084,7 +3097,9 @@ static int _write_super_to_disk(struct ddf_super *ddf, struct dl *d) if (!__write_ddf_structure(d, ddf, DDF_HEADER_SECONDARY)) return 0; - lseek64(fd, (size-1)*512, SEEK_SET); + if (lseek64(fd, (size - 1) * 512, SEEK_SET) == -1L) + return 0; + if (write(fd, &ddf->anchor, 512) < 0) return 0; @@ -3295,9 +3310,10 @@ static int validate_geometry_ddf(struct supertype *st, char *dev, unsigned long long *freesize, int consistency_policy, int verbose) { - int fd; - struct mdinfo *sra; + struct mdinfo *sra = NULL; + int ret = 1; int cfd; + int fd; /* ddf potentially supports lots of things, but it depends on * what devices are offered (and maybe kernel version?) @@ -3365,7 +3381,7 @@ static int validate_geometry_ddf(struct supertype *st, * Later we should check for a BVD and make an SVD. */ fd = open(dev, O_RDONLY|O_EXCL, 0); - if (fd >= 0) { + if (is_fd_valid(fd)) { close(fd); /* Just a bare device, no good to us */ if (verbose) @@ -3373,44 +3389,58 @@ static int validate_geometry_ddf(struct supertype *st, dev); return 0; } + if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) { if (verbose) pr_err("ddf: Cannot open %s: %s\n", dev, strerror(errno)); return 0; } + /* Well, it is in use by someone, maybe a 'ddf' container. */ cfd = open_container(fd); - if (cfd < 0) { - close(fd); + close(fd); + + if (!is_fd_valid(cfd)) { if (verbose) - pr_err("ddf: Cannot use %s: %s\n", - dev, strerror(EBUSY)); + pr_err("ddf: Cannot use %s\n", dev); return 0; } + sra = sysfs_read(cfd, NULL, GET_VERSION); - close(fd); - if (sra && sra->array.major_version == -1 && - strcmp(sra->text_version, "ddf") == 0) { + if (!sra) { + pr_err("Cannot read sysfs for /dev/%s\n", fd2kname(cfd)); + goto error; + } + + if (sra->array.major_version == -1 && strcmp(sra->text_version, "ddf") == 0) { /* This is a member of a ddf container. Load the container * and try to create a bvd */ - struct ddf_super *ddf; + struct ddf_super *ddf = NULL; + if (load_super_ddf_all(st, cfd, (void **)&ddf, NULL) == 0) { st->sb = ddf; - strcpy(st->container_devnm, fd2devnm(cfd)); + snprintf(st->container_devnm, sizeof(st->container_devnm), + "%s", fd2kname(cfd)); close(cfd); - return validate_geometry_ddf_bvd(st, level, layout, - raiddisks, chunk, size, - data_offset, - dev, freesize, - verbose); + free(sra); + + return validate_geometry_ddf_bvd(st, level, layout, raiddisks, + chunk, size, data_offset, dev, + freesize, verbose); } - close(cfd); - } else /* device may belong to a different container */ - return 0; + free(ddf); + } - return 1; + /* device may belong to a different container */ + ret = 0; + +error: + free(sra); + close(cfd); + + return ret; } static int validate_geometry_ddf_bvd(struct supertype *st, @@ -3479,35 +3509,42 @@ static int validate_geometry_ddf_bvd(struct supertype *st, static int load_super_ddf_all(struct supertype *st, int fd, void **sbp, char *devname) { - struct mdinfo *sra; - struct ddf_super *super; struct mdinfo *sd, *best = NULL; + struct ddf_super *super = NULL; + struct mdinfo *sra; int bestseq = 0; - int seq; + int ret = 1; char nm[20]; + int seq; int dfd; sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE); if (!sra) return 1; - if (sra->array.major_version != -1 || - sra->array.minor_version != -2 || + if (sra->array.major_version != -1 || sra->array.minor_version != -2 || strcmp(sra->text_version, "ddf") != 0) - return 1; + goto out; if (posix_memalign((void**)&super, 512, sizeof(*super)) != 0) - return 1; + goto out; + memset(super, 0, sizeof(*super)); /* first, try each device, and choose the best ddf */ for (sd = sra->devs ; sd ; sd = sd->next) { int rv; + sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); + dfd = dev_open(nm, O_RDONLY); - if (dfd < 0) - return 2; + if (!is_fd_valid(dfd)) { + ret = 2; + goto out; + } + rv = load_ddf_headers(dfd, super, NULL); close(dfd); + if (rv == 0) { seq = be32_to_cpu(super->active->seq); if (super->active->openflag) @@ -3519,28 +3556,39 @@ static int load_super_ddf_all(struct supertype *st, int fd, } } if (!best) - return 1; + goto out; + /* OK, load this ddf */ sprintf(nm, "%d:%d", best->disk.major, best->disk.minor); + dfd = dev_open(nm, O_RDONLY); if (dfd < 0) - return 1; + goto out; + load_ddf_headers(dfd, super, NULL); load_ddf_global(dfd, super, NULL); close(dfd); + /* Now we need the device-local bits */ for (sd = sra->devs ; sd ; sd = sd->next) { int rv; sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); + dfd = dev_open(nm, O_RDWR); - if (dfd < 0) - return 2; + if (dfd < 0) { + ret = 2; + goto out; + } + rv = load_ddf_headers(dfd, super, NULL); if (rv == 0) rv = load_ddf_local(dfd, super, NULL, 1); - if (rv) - return 1; + + if (rv) { + close(dfd); + goto out; + } } *sbp = super; @@ -3549,8 +3597,16 @@ static int load_super_ddf_all(struct supertype *st, int fd, st->minor_version = 0; st->max_devs = 512; } - strcpy(st->container_devnm, fd2devnm(fd)); - return 0; + + snprintf(st->container_devnm, sizeof(st->container_devnm), "%s", fd2devnm(fd)); + ret = 0; + +out: + if (sra) + free(sra); + if (super && ret != 0) + free(super); + return ret; } static int load_container_ddf(struct supertype *st, int fd, @@ -3787,7 +3843,7 @@ static struct mdinfo *container_content_ddf(struct supertype *st, char *subarray be64_to_cpu(LBA_OFFSET(ddf, bvd)[iphys]); dev->component_size = be64_to_cpu(bvd->blocks); if (d->devname) - strcpy(dev->name, d->devname); + snprintf(dev->name, sizeof(dev->name), "%s", d->devname); } } return rest; @@ -3836,11 +3892,15 @@ static int store_super_ddf(struct supertype *st, int fd) return 1; memset(buf, 0, 512); - lseek64(fd, dsize-512, 0); + if (lseek64(fd, dsize - 512, 0) == -1L) { + free(buf); + return 1; + } rc = write(fd, buf, 512); free(buf); if (rc < 0) return 1; + return 0; } @@ -3955,6 +4015,7 @@ static int compare_super_ddf(struct supertype *st, struct supertype *tst, if (posix_memalign((void **)&dl1->spare, 512, first->conf_rec_len*512) != 0) { pr_err("could not allocate spare info buf\n"); + free(dl1); return 3; } memcpy(dl1->spare, dl2->spare, first->conf_rec_len*512); @@ -4176,6 +4237,7 @@ static int get_bvd_state(const struct ddf_super *ddf, state = DDF_state_part_optimal; break; } + free(avail); return state; } diff --git a/super-intel.c b/super-intel.c index 1faab60..713bfcc 100644 --- a/super-intel.c +++ b/super-intel.c @@ -32,14 +32,19 @@ /* MPB == Metadata Parameter Block */ #define MPB_SIGNATURE "Intel Raid ISM Cfg Sig. " #define MPB_SIG_LEN (strlen(MPB_SIGNATURE)) -#define MPB_VERSION_RAID0 "1.0.00" -#define MPB_VERSION_RAID1 "1.1.00" -#define MPB_VERSION_MANY_VOLUMES_PER_ARRAY "1.2.00" -#define MPB_VERSION_3OR4_DISK_ARRAY "1.2.01" -#define MPB_VERSION_RAID5 "1.2.02" -#define MPB_VERSION_5OR6_DISK_ARRAY "1.2.04" -#define MPB_VERSION_CNG "1.2.06" + +/* Legacy IMSM versions: + * MPB_VERSION_RAID0 1.0.00 + * MPB_VERSION_RAID1 1.1.00 + * MPB_VERSION_MANY_VOLUMES_PER_ARRAY 1.2.00 + * MPB_VERSION_3OR4_DISK_ARRAY 1.2.01 + * MPB_VERSION_RAID5 1.2.02 + * MPB_VERSION_5OR6_DISK_ARRAY 1.2.04 + * MPB_VERSION_CNG 1.2.06 + */ + #define MPB_VERSION_ATTRIBS "1.3.00" +#define MPB_VERSION_ATTRIBS_JD "2.0.00" #define MAX_SIGNATURE_LENGTH 32 #define MAX_RAID_SERIAL_LEN 16 @@ -57,6 +62,8 @@ #define MPB_ATTRIB_RAIDCNG __cpu_to_le32(0x00000020) /* supports expanded stripe sizes of 256K, 512K and 1MB */ #define MPB_ATTRIB_EXP_STRIPE_SIZE __cpu_to_le32(0x00000040) +/* supports RAID10 with more than 4 drives */ +#define MPB_ATTRIB_RAID10_EXT __cpu_to_le32(0x00000080) /* The OROM Support RST Caching of Volumes */ #define MPB_ATTRIB_NVM __cpu_to_le32(0x02000000) @@ -84,6 +91,7 @@ MPB_ATTRIB_RAID10 | \ MPB_ATTRIB_RAID5 | \ MPB_ATTRIB_EXP_STRIPE_SIZE | \ + MPB_ATTRIB_RAID10_EXT | \ MPB_ATTRIB_BBM) /* Define attributes that are unused but not harmful */ @@ -166,7 +174,8 @@ struct imsm_map { __u8 raid_level; #define IMSM_T_RAID0 0 #define IMSM_T_RAID1 1 -#define IMSM_T_RAID5 5 /* since metadata version 1.2.02 ? */ +#define IMSM_T_RAID5 5 +#define IMSM_T_RAID10 10 __u8 num_members; /* number of member disks */ __u8 num_domains; /* number of parity domains */ __u8 failed_disk_num; /* valid only when state is degraded */ @@ -514,6 +523,7 @@ enum imsm_reshape_type { CH_TAKEOVER, CH_MIGRATION, CH_ARRAY_SIZE, + CH_ABORT }; /* definition of messages passed to imsm_process_update */ @@ -1259,14 +1269,42 @@ static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx) return IMSM_STATUS_ERROR; } +/** + * update_imsm_raid_level() - update raid level appropriately in &imsm_map. + * @map: &imsm_map pointer. + * @new_level: MD style level. + * + * For backward compatibility reasons we need to differentiate RAID10. + * In the past IMSM RAID10 was presented as RAID1. + * Keep compatibility unless it is not explicitly updated by UEFI driver. + * + * Routine needs num_members to be set and (optionally) raid_level. + */ +static void update_imsm_raid_level(struct imsm_map *map, int new_level) +{ + if (new_level != IMSM_T_RAID10) { + map->raid_level = new_level; + return; + } + + if (map->num_members == 4) { + if (map->raid_level == IMSM_T_RAID10 || map->raid_level == IMSM_T_RAID1) + return; + + map->raid_level = IMSM_T_RAID1; + return; + } + + map->raid_level = IMSM_T_RAID10; +} static int get_imsm_raid_level(struct imsm_map *map) { - if (map->raid_level == 1) { + if (map->raid_level == IMSM_T_RAID1) { if (map->num_members == 2) - return 1; + return IMSM_T_RAID1; else - return 10; + return IMSM_T_RAID10; } return map->raid_level; @@ -2098,91 +2136,18 @@ void convert_from_4k(struct intel_super *super) mpb->check_sum = __gen_imsm_checksum(mpb); } -/******************************************************************************* - * function: imsm_check_attributes - * Description: Function checks if features represented by attributes flags - * are supported by mdadm. - * Parameters: - * attributes - Attributes read from metadata - * Returns: - * 0 - passed attributes contains unsupported features flags - * 1 - all features are supported - ******************************************************************************/ -static int imsm_check_attributes(__u32 attributes) +/** + * imsm_check_attributes() - Check if features represented by attributes flags are supported. + * + * @attributes: attributes read from metadata. + * Returns: true if all features are supported, false otherwise. + */ +static bool imsm_check_attributes(__u32 attributes) { - int ret_val = 1; - __u32 not_supported = MPB_ATTRIB_SUPPORTED^0xffffffff; - - not_supported &= ~MPB_ATTRIB_IGNORED; - - not_supported &= attributes; - if (not_supported) { - pr_err("(IMSM): Unsupported attributes : %x\n", - (unsigned)__le32_to_cpu(not_supported)); - if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) { - dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n"); - not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY; - } - if (not_supported & MPB_ATTRIB_2TB) { - dprintf("\t\tMPB_ATTRIB_2TB\n"); - not_supported ^= MPB_ATTRIB_2TB; - } - if (not_supported & MPB_ATTRIB_RAID0) { - dprintf("\t\tMPB_ATTRIB_RAID0\n"); - not_supported ^= MPB_ATTRIB_RAID0; - } - if (not_supported & MPB_ATTRIB_RAID1) { - dprintf("\t\tMPB_ATTRIB_RAID1\n"); - not_supported ^= MPB_ATTRIB_RAID1; - } - if (not_supported & MPB_ATTRIB_RAID10) { - dprintf("\t\tMPB_ATTRIB_RAID10\n"); - not_supported ^= MPB_ATTRIB_RAID10; - } - if (not_supported & MPB_ATTRIB_RAID1E) { - dprintf("\t\tMPB_ATTRIB_RAID1E\n"); - not_supported ^= MPB_ATTRIB_RAID1E; - } - if (not_supported & MPB_ATTRIB_RAID5) { - dprintf("\t\tMPB_ATTRIB_RAID5\n"); - not_supported ^= MPB_ATTRIB_RAID5; - } - if (not_supported & MPB_ATTRIB_RAIDCNG) { - dprintf("\t\tMPB_ATTRIB_RAIDCNG\n"); - not_supported ^= MPB_ATTRIB_RAIDCNG; - } - if (not_supported & MPB_ATTRIB_BBM) { - dprintf("\t\tMPB_ATTRIB_BBM\n"); - not_supported ^= MPB_ATTRIB_BBM; - } - if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) { - dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY (== MPB_ATTRIB_LEGACY)\n"); - not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY; - } - if (not_supported & MPB_ATTRIB_EXP_STRIPE_SIZE) { - dprintf("\t\tMPB_ATTRIB_EXP_STRIP_SIZE\n"); - not_supported ^= MPB_ATTRIB_EXP_STRIPE_SIZE; - } - if (not_supported & MPB_ATTRIB_2TB_DISK) { - dprintf("\t\tMPB_ATTRIB_2TB_DISK\n"); - not_supported ^= MPB_ATTRIB_2TB_DISK; - } - if (not_supported & MPB_ATTRIB_NEVER_USE2) { - dprintf("\t\tMPB_ATTRIB_NEVER_USE2\n"); - not_supported ^= MPB_ATTRIB_NEVER_USE2; - } - if (not_supported & MPB_ATTRIB_NEVER_USE) { - dprintf("\t\tMPB_ATTRIB_NEVER_USE\n"); - not_supported ^= MPB_ATTRIB_NEVER_USE; - } - - if (not_supported) - dprintf("(IMSM): Unknown attributes : %x\n", not_supported); - - ret_val = 0; - } + if ((attributes & (MPB_ATTRIB_SUPPORTED | MPB_ATTRIB_IGNORED)) == attributes) + return true; - return ret_val; + return false; } static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map); @@ -2210,11 +2175,10 @@ static void examine_super_imsm(struct supertype *st, char *homehost) creation_time = __le64_to_cpu(mpb->creation_time); printf(" Creation Time : %.24s\n", creation_time ? ctime(&creation_time) : "Unknown"); - printf(" Attributes : "); - if (imsm_check_attributes(mpb->attributes)) - printf("All supported\n"); - else - printf("not supported\n"); + + printf(" Attributes : %08x (%s)\n", mpb->attributes, + imsm_check_attributes(mpb->attributes) ? "supported" : "not supported"); + getinfo_super_imsm(st, &info, NULL); fname_from_uuid(&info, nbuf); printf(" UUID : %s\n", nbuf + 5); @@ -2354,7 +2318,7 @@ void print_encryption_information(int disk_fd, enum sys_dev_type hba_type) { struct encryption_information information = {0}; mdadm_status_t status = MDADM_STATUS_SUCCESS; - const char *indent = " "; + const char *indent = " "; switch (hba_type) { case SYS_DEV_VMD: @@ -2379,7 +2343,8 @@ void print_encryption_information(int disk_fd, enum sys_dev_type hba_type) get_encryption_status_string(information.status)); } -static int ahci_enumerate_ports(struct sys_dev *hba, int port_count, int host_base, int verbose) +static int ahci_enumerate_ports(struct sys_dev *hba, unsigned long port_count, int host_base, + int verbose) { /* dump an unsorted list of devices attached to AHCI Intel storage * controller, as well as non-connected ports @@ -2393,7 +2358,7 @@ static int ahci_enumerate_ports(struct sys_dev *hba, int port_count, int host_ba if (port_count > (int)sizeof(port_mask) * 8) { if (verbose > 0) - pr_err("port_count %d out of range\n", port_count); + pr_err("port_count %ld out of range\n", port_count); return 2; } @@ -2535,11 +2500,11 @@ static int ahci_enumerate_ports(struct sys_dev *hba, int port_count, int host_ba if (dir) closedir(dir); if (err == 0) { - int i; + unsigned long i; for (i = 0; i < port_count; i++) - if (port_mask & (1 << i)) - printf(" Port%d : - no device attached -\n", i); + if (port_mask & (1L << i)) + printf(" Port%ld : - no device attached -\n", i); } return err; @@ -2652,6 +2617,15 @@ static int ahci_get_port_count(const char *hba_path, int *port_count) return host_base; } +static void print_imsm_level_capability(const struct imsm_orom *orom) +{ + int idx; + + for (idx = 0; imsm_level_ops[idx].name; idx++) + if (imsm_level_ops[idx].is_level_supported(orom)) + printf("%s ", imsm_level_ops[idx].name); +} + static void print_imsm_capability(const struct imsm_orom *orom) { printf(" Platform : Intel(R) "); @@ -2670,12 +2644,11 @@ static void print_imsm_capability(const struct imsm_orom *orom) printf(" Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, orom->hotfix_ver, orom->build); } - printf(" RAID Levels :%s%s%s%s%s\n", - imsm_orom_has_raid0(orom) ? " raid0" : "", - imsm_orom_has_raid1(orom) ? " raid1" : "", - imsm_orom_has_raid1e(orom) ? " raid1e" : "", - imsm_orom_has_raid10(orom) ? " raid10" : "", - imsm_orom_has_raid5(orom) ? " raid5" : ""); + + printf(" RAID Levels : "); + print_imsm_level_capability(orom); + printf("\n"); + printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", imsm_orom_has_chunk(orom, 2) ? " 2k" : "", imsm_orom_has_chunk(orom, 4) ? " 4k" : "", @@ -2710,12 +2683,11 @@ static void print_imsm_capability_export(const struct imsm_orom *orom) if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) printf("IMSM_VERSION=%d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, orom->hotfix_ver, orom->build); - printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n", - imsm_orom_has_raid0(orom) ? "raid0 " : "", - imsm_orom_has_raid1(orom) ? "raid1 " : "", - imsm_orom_has_raid1e(orom) ? "raid1e " : "", - imsm_orom_has_raid5(orom) ? "raid10 " : "", - imsm_orom_has_raid10(orom) ? "raid5 " : ""); + + printf("IMSM_SUPPORTED_RAID_LEVELS="); + print_imsm_level_capability(orom); + printf("\n"); + printf("IMSM_SUPPORTED_CHUNK_SIZES=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", imsm_orom_has_chunk(orom, 2) ? "2k " : "", imsm_orom_has_chunk(orom, 4) ? "4k " : "", @@ -4268,7 +4240,10 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd) dl = xcalloc(1, sizeof(*dl)); - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) { + free(dl); + return 1; + } dl->major = major(stb.st_rdev); dl->minor = minor(stb.st_rdev); dl->next = super->disks; @@ -5476,51 +5451,48 @@ static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info, return (size * 2) & ~(info_to_blocks_per_strip(info) - 1); } +static void imsm_write_signature(struct imsm_super *mpb) +{ + /* It is safer to eventually truncate version rather than left it not NULL ended */ + snprintf((char *) mpb->sig, MAX_SIGNATURE_LENGTH, MPB_SIGNATURE MPB_VERSION_ATTRIBS); +} + static void imsm_update_version_info(struct intel_super *super) { /* update the version and attributes */ struct imsm_super *mpb = super->anchor; - char *version; struct imsm_dev *dev; struct imsm_map *map; int i; + mpb->attributes |= MPB_ATTRIB_CHECKSUM_VERIFY; + for (i = 0; i < mpb->num_raid_devs; i++) { dev = get_imsm_dev(super, i); map = get_imsm_map(dev, MAP_0); + if (__le32_to_cpu(dev->size_high) > 0) mpb->attributes |= MPB_ATTRIB_2TB; - /* FIXME detect when an array spans a port multiplier */ - #if 0 - mpb->attributes |= MPB_ATTRIB_PM; - #endif - - if (mpb->num_raid_devs > 1 || - mpb->attributes != MPB_ATTRIB_CHECKSUM_VERIFY) { - version = MPB_VERSION_ATTRIBS; - switch (get_imsm_raid_level(map)) { - case 0: mpb->attributes |= MPB_ATTRIB_RAID0; break; - case 1: mpb->attributes |= MPB_ATTRIB_RAID1; break; - case 10: mpb->attributes |= MPB_ATTRIB_RAID10; break; - case 5: mpb->attributes |= MPB_ATTRIB_RAID5; break; - } - } else { - if (map->num_members >= 5) - version = MPB_VERSION_5OR6_DISK_ARRAY; - else if (dev->status == DEV_CLONE_N_GO) - version = MPB_VERSION_CNG; - else if (get_imsm_raid_level(map) == 5) - version = MPB_VERSION_RAID5; - else if (map->num_members >= 3) - version = MPB_VERSION_3OR4_DISK_ARRAY; - else if (get_imsm_raid_level(map) == 1) - version = MPB_VERSION_RAID1; - else - version = MPB_VERSION_RAID0; + switch (get_imsm_raid_level(map)) { + case IMSM_T_RAID0: + mpb->attributes |= MPB_ATTRIB_RAID0; + break; + case IMSM_T_RAID1: + mpb->attributes |= MPB_ATTRIB_RAID1; + break; + case IMSM_T_RAID5: + mpb->attributes |= MPB_ATTRIB_RAID5; + break; + case IMSM_T_RAID10: + mpb->attributes |= MPB_ATTRIB_RAID10; + if (map->num_members > 4) + mpb->attributes |= MPB_ATTRIB_RAID10_EXT; + break; } - strcpy(((char *) mpb->sig) + strlen(MPB_SIGNATURE), version); } + + imsm_write_signature(mpb); } /** @@ -5678,7 +5650,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, set_pba_of_lba0(map, super->create_offset); map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info)); map->failed_disk_num = ~0; - if (info->level > 0) + if (info->level > IMSM_T_RAID0) map->map_state = (info->state ? IMSM_T_STATE_NORMAL : IMSM_T_STATE_UNINITIALIZED); else @@ -5686,16 +5658,15 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, IMSM_T_STATE_NORMAL; map->ddf = 1; - if (info->level == 1 && info->raid_disks > 2) { + if (info->level == IMSM_T_RAID1 && info->raid_disks > 2) { free(dev); free(dv); - pr_err("imsm does not support more than 2 disksin a raid1 volume\n"); + pr_err("imsm does not support more than 2 disks in a raid1 volume\n"); return 0; } + map->num_members = info->raid_disks; - map->raid_level = info->level; - if (info->level == 10) - map->raid_level = 1; + update_imsm_raid_level(map, info->level); set_num_domains(map); size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION; @@ -5703,7 +5674,6 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, size_per_member / BLOCKS_PER_KB)); - map->num_members = info->raid_disks; update_num_data_stripes(map, array_blocks); for (i = 0; i < map->num_members; i++) { /* initialized in add_to_super */ @@ -5751,7 +5721,6 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info, struct intel_super *super; struct imsm_super *mpb; size_t mpb_size; - char *version; if (data_offset != INVALID_SECTORS) { pr_err("data-offset not supported by imsm\n"); @@ -5794,13 +5763,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info, return 0; } - mpb->attributes = MPB_ATTRIB_CHECKSUM_VERIFY; - - version = (char *) mpb->sig; - strcpy(version, MPB_SIGNATURE); - version += strlen(MPB_SIGNATURE); - strcpy(version, MPB_VERSION_RAID0); - + imsm_update_version_info(super); return 1; } @@ -6022,7 +5985,8 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, if (super->current_vol >= 0) return add_to_super_imsm_volume(st, dk, fd, devname); - fstat(fd, &stb); + if (fstat(fd, &stb) != 0) + return 1; dd = xcalloc(sizeof(*dd), 1); dd->major = major(stb.st_rdev); dd->minor = minor(stb.st_rdev); @@ -6174,7 +6138,6 @@ static union { static int write_super_imsm_spare(struct intel_super *super, struct dl *d) { - struct imsm_super *mpb = super->anchor; struct imsm_super *spare = &spare_record.anchor; __u32 sum; @@ -6183,14 +6146,11 @@ static int write_super_imsm_spare(struct intel_super *super, struct dl *d) spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super)); spare->generation_num = __cpu_to_le32(1UL); - spare->attributes = MPB_ATTRIB_CHECKSUM_VERIFY; spare->num_disks = 1; spare->num_raid_devs = 0; - spare->cache_size = mpb->cache_size; spare->pwr_cycle_count = __cpu_to_le32(1); - snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH, - MPB_SIGNATURE MPB_VERSION_RAID0); + imsm_write_signature(spare); spare->disk[0] = d->disk; if (__le32_to_cpu(d->disk.total_blocks_hi) > 0) @@ -6965,26 +6925,41 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex return free_size - reservation_size; } -static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) +/** + * is_raid_level_supported() - check if this count of drives and level is supported by platform. + * @orom: hardware properties, could be NULL. + * @level: requested raid level. + * @raiddisks: requested disk count. + * + * IMSM UEFI/OROM does not provide information about supported count of raid disks + * for particular level. That is why it is hardcoded. + * It is recommended to not allow of usage other levels than supported, + * IMSM code is not tested against different level implementations. + * + * Return: true if supported, false otherwise. + */ +static bool is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) { - if (level < 0 || level == 6 || level == 4) - return 0; + int idx; - /* if we have an orom prevent invalid raid levels */ - if (orom) - switch (level) { - case 0: return imsm_orom_has_raid0(orom); - case 1: - if (raiddisks > 2) - return imsm_orom_has_raid1e(orom); - return imsm_orom_has_raid1(orom) && raiddisks == 2; - case 10: return imsm_orom_has_raid10(orom) && raiddisks == 4; - case 5: return imsm_orom_has_raid5(orom) && raiddisks > 2; - } - else - return 1; /* not on an Intel RAID platform so anything goes */ + for (idx = 0; imsm_level_ops[idx].name; idx++) { + if (imsm_level_ops[idx].level == level) + break; + } - return 0; + if (!imsm_level_ops[idx].name) + return false; + + if (!imsm_level_ops[idx].is_raiddisks_count_supported(raiddisks)) + return false; + + if (!orom) + return true; + + if (imsm_level_ops[idx].is_level_supported(orom)) + return true; + + return false; } static int @@ -7072,7 +7047,6 @@ get_devices(const char *hba_path) struct md_list *dv; struct dirent *ent; DIR *dir; - int err = 0; #if DEBUG_LOOP devlist = get_loop_devices(); @@ -7114,14 +7088,6 @@ get_devices(const char *hba_path) dv->next = devlist; devlist = dv; } - if (err) { - while(devlist) { - dv = devlist; - devlist = devlist->next; - free(dv->devname); - free(dv); - } - } closedir(dir); return devlist; } @@ -7740,9 +7706,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, char *dev, unsigned long long *freesize, int consistency_policy, int verbose) { - int fd, cfd; + struct intel_super *super = st->sb; struct mdinfo *sra; int is_member = 0; + imsm_status_t rv; + int fd, cfd; /* load capability * if given unused devices create a container @@ -7767,11 +7735,10 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, } if (!dev) { - struct intel_super *super = st->sb; - /* * Autolayout mode, st->sb must be set. */ + if (!super) { pr_vrb("superblock must be set for autolayout, aborting\n"); return 0; @@ -7782,21 +7749,22 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, verbose)) return 0; - if (super->orom && freesize) { - imsm_status_t rv; - int count = count_volumes(super->hba, super->orom->dpa, - verbose); + if (super->orom) { + int count = count_volumes(super->hba, super->orom->dpa, verbose); + if (super->orom->vphba <= count) { pr_vrb("platform does not support more than %d raid volumes.\n", super->orom->vphba); return 0; } + } - rv = autolayout_imsm(super, raiddisks, size, *chunk, - freesize); - if (rv != IMSM_STATUS_OK) - return 0; + if (freesize) { + rv = autolayout_imsm(super, raiddisks, size, *chunk, freesize); + if (rv != IMSM_STATUS_OK) + return 0; } + return 1; } if (st->sb) { @@ -8139,9 +8107,9 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra int current_vol = super->current_vol; /* do not assemble arrays when not all attributes are supported */ - if (imsm_check_attributes(mpb->attributes) == 0) { + if (imsm_check_attributes(mpb->attributes) == false) { sb_errors = 1; - pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n"); + pr_err("Unsupported attributes in IMSM metadata. Arrays activation is blocked.\n"); } /* count spare devices, not used in maps @@ -8275,7 +8243,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra info_d->data_offset = pba_of_lba0(map); info_d->component_size = calc_component_size(map, dev); - if (map->raid_level == 5) { + if (map->raid_level == IMSM_T_RAID5) { info_d->ppl_sector = this->ppl_sector; info_d->ppl_size = this->ppl_size; if (this->consistency_policy == CONSISTENCY_POLICY_PPL && @@ -9533,7 +9501,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration * } to_state = map->map_state; - if ((u->new_level == 5) && (map->raid_level == 0)) { + if ((u->new_level == IMSM_T_RAID5) && (map->raid_level == IMSM_T_RAID0)) { map->num_members++; /* this should not happen */ if (u->new_disks[0] < 0) { @@ -9544,11 +9512,13 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration * to_state = IMSM_T_STATE_NORMAL; } migrate(new_dev, super, to_state, MIGR_GEN_MIGR); + if (u->new_level > -1) - map->raid_level = u->new_level; + update_imsm_raid_level(map, u->new_level); + migr_map = get_imsm_map(new_dev, MAP_1); - if ((u->new_level == 5) && - (migr_map->raid_level == 0)) { + if ((u->new_level == IMSM_T_RAID5) && + (migr_map->raid_level == IMSM_T_RAID0)) { int ord = map->num_members - 1; migr_map->num_members--; if (u->new_disks[0] < 0) @@ -9584,7 +9554,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration * /* add disk */ - if (u->new_level != 5 || migr_map->raid_level != 0 || + if (u->new_level != IMSM_T_RAID5 || migr_map->raid_level != IMSM_T_RAID0 || migr_map->raid_level == map->raid_level) goto skip_disk_add; @@ -9963,7 +9933,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u, /* update map */ map->num_members /= map->num_domains; map->map_state = IMSM_T_STATE_NORMAL; - map->raid_level = 0; + update_imsm_raid_level(map, IMSM_T_RAID0); set_num_domains(map); update_num_data_stripes(map, imsm_dev_size(dev)); map->failed_disk_num = -1; @@ -10007,7 +9977,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u, map = get_imsm_map(dev_new, MAP_0); map->map_state = IMSM_T_STATE_DEGRADED; - map->raid_level = 1; + update_imsm_raid_level(map, IMSM_T_RAID10); set_num_domains(map); map->num_members = map->num_members * map->num_domains; update_num_data_stripes(map, imsm_dev_size(dev)); @@ -11352,7 +11322,7 @@ check_policy: return MDADM_STATUS_SUCCESS; fd2devname(disk_fd, devname); - pr_vrb("Encryption status \"%s\" detected for disk %s, but \"%s\" status was detected eariler.\n", + pr_vrb("Encryption status \"%s\" detected for disk %s, but \"%s\" status was detected earlier.\n", encryption_state, devname, expected_policy->value); pr_vrb("Disks with different encryption status cannot be used.\n"); return MDADM_STATUS_ERROR; @@ -11927,24 +11897,23 @@ success: ****************************************************************************/ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, struct geo_params *geo, - int direction) + int direction, struct context *c) { struct mdinfo info; int change = -1; int check_devs = 0; int chunk; - /* number of added/removed disks in operation result */ - int devNumChange = 0; /* imsm compatible layout value for array geometry verification */ int imsm_layout = -1; + int raid_disks = geo->raid_disks; imsm_status_t rv; getinfo_super_imsm_volume(st, &info, NULL); - if (geo->level != info.array.level && geo->level >= 0 && + if (geo->level != info.array.level && geo->level >= IMSM_T_RAID0 && geo->level != UnSet) { switch (info.array.level) { - case 0: - if (geo->level == 5) { + case IMSM_T_RAID0: + if (geo->level == IMSM_T_RAID5) { change = CH_MIGRATION; if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) { pr_err("Error. Requested Layout not supported (left-asymmetric layout is supported only)!\n"); @@ -11953,20 +11922,28 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, } imsm_layout = geo->layout; check_devs = 1; - devNumChange = 1; /* parity disk added */ - } else if (geo->level == 10) { + raid_disks += 1; /* parity disk added */ + } else if (geo->level == IMSM_T_RAID10) { + if (geo->level == IMSM_T_RAID10 && geo->raid_disks > 2 && + !c->force) { + pr_err("Warning! VROC UEFI driver does not support RAID10 in requested layout.\n"); + pr_err("Array won't be suitable as boot device.\n"); + pr_err("Note: You can omit this check with \"--force\"\n"); + if (ask("Do you want to continue") < 1) + return CH_ABORT; + } change = CH_TAKEOVER; check_devs = 1; - devNumChange = 2; /* two mirrors added */ + raid_disks *= 2; /* mirrors added */ imsm_layout = 0x102; /* imsm supported layout */ } break; - case 1: - case 10: + case IMSM_T_RAID1: + case IMSM_T_RAID10: if (geo->level == 0) { change = CH_TAKEOVER; check_devs = 1; - devNumChange = -(geo->raid_disks/2); + raid_disks /= 2; imsm_layout = 0; /* imsm raid0 layout */ } break; @@ -11982,10 +11959,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if (geo->layout != info.array.layout && (geo->layout != UnSet && geo->layout != -1)) { change = CH_MIGRATION; - if (info.array.layout == 0 && info.array.level == 5 && + if (info.array.layout == 0 && info.array.level == IMSM_T_RAID5 && geo->layout == 5) { /* reshape 5 -> 4 */ - } else if (info.array.layout == 5 && info.array.level == 5 && + } else if (info.array.layout == 5 && info.array.level == IMSM_T_RAID5 && geo->layout == 0) { /* reshape 4 -> 5 */ geo->layout = 0; @@ -12004,7 +11981,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if (geo->chunksize > 0 && geo->chunksize != UnSet && geo->chunksize != info.array.chunk_size) { - if (info.array.level == 10) { + if (info.array.level == IMSM_T_RAID10) { pr_err("Error. Chunk size change for RAID 10 is not supported.\n"); change = -1; goto analyse_change_exit; @@ -12029,14 +12006,16 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, rv = imsm_analyze_expand(st, geo, &info, direction); if (rv != IMSM_STATUS_OK) goto analyse_change_exit; + raid_disks = geo->raid_disks; change = CH_ARRAY_SIZE; } chunk = geo->chunksize / 1024; + if (!validate_geometry_imsm(st, geo->level, imsm_layout, - geo->raid_disks + devNumChange, + raid_disks, &chunk, geo->size, INVALID_SECTORS, 0, 0, info.consistency_policy, 1)) @@ -12152,28 +12131,37 @@ exit: return ret_val; } -static int imsm_reshape_super(struct supertype *st, unsigned long long size, - int level, - int layout, int chunksize, int raid_disks, - int delta_disks, char *backup, char *dev, - int direction, int verbose) +/** + * shape_to_geo() - fill geo_params from shape. + * + * @shape: array details. + * @geo: new geometry params. + * Returns: 0 on success, 1 otherwise. + */ +static void shape_to_geo(struct shape *shape, struct geo_params *geo) +{ + assert(shape); + assert(geo); + + geo->dev_name = shape->dev; + geo->size = shape->size; + geo->level = shape->level; + geo->layout = shape->layout; + geo->chunksize = shape->chunk; + geo->raid_disks = shape->raiddisks; +} + +static int imsm_reshape_super(struct supertype *st, struct shape *shape, struct context *c) { int ret_val = 1; - struct geo_params geo; + struct geo_params geo = {0}; dprintf("(enter)\n"); - memset(&geo, 0, sizeof(struct geo_params)); - - geo.dev_name = dev; + shape_to_geo(shape, &geo); strcpy(geo.devnm, st->devnm); - geo.size = size; - geo.level = level; - geo.layout = layout; - geo.chunksize = chunksize; - geo.raid_disks = raid_disks; - if (delta_disks != UnSet) - geo.raid_disks += delta_disks; + if (shape->delta_disks != UnSet) + geo.raid_disks += shape->delta_disks; dprintf("for level : %i\n", geo.level); dprintf("for raid_disks : %i\n", geo.raid_disks); @@ -12184,7 +12172,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size, int old_raid_disks = 0; if (imsm_reshape_is_allowed_on_container( - st, &geo, &old_raid_disks, direction)) { + st, &geo, &old_raid_disks, shape->direction)) { struct imsm_update_reshape *u = NULL; int len; @@ -12238,7 +12226,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size, goto exit_imsm_reshape_super; } super->current_vol = dev->index; - change = imsm_analyze_change(st, &geo, direction); + change = imsm_analyze_change(st, &geo, shape->direction, c); switch (change) { case CH_TAKEOVER: ret_val = imsm_takeover(st, &geo); @@ -12281,6 +12269,7 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size, free(u); } break; + case CH_ABORT: default: ret_val = 1; } @@ -6,8 +6,21 @@ targetdir="/var/tmp" logdir="$targetdir" config=/tmp/mdadm.conf testdir=$PWD/tests -system_speed_limit=`cat /proc/sys/dev/raid/speed_limit_max` +system_speed_limit_max=0 +system_speed_limit_min=0 +test_speed_limit_min=100 +test_speed_limit_max=500 devlist= +# If super1 metadata name doesn't have the same hostname with machine, +# it's treated as foreign. +# For example, /dev/md0 is created, stops it, then assemble it, the +# device node will be /dev/md127 (127 is choosed by mdadm autumatically) +is_foreign="no" +#disable selinux +sys_selinux="Permissive" + +skipping_linear="no" +skipping_multipath="no" savelogs=0 exitonerror=1 @@ -25,6 +38,11 @@ LVM_VOLGROUP=mdtest md0=/dev/md0 md1=/dev/md1 md2=/dev/md2 +# if user doesn't specify minor number, mdadm chooses minor number +# automatically from 127. +md127=/dev/md127 +md126=/dev/md126 +md125=/dev/md125 mdp0=/dev/md_d0 mdp1=/dev/md_d1 @@ -39,10 +57,6 @@ ctrl_c() { ctrl_c_error=1 } -restore_system_speed_limit() { - echo $system_speed_limit > /proc/sys/dev/raid/speed_limit_max -} - mdadm() { rm -f $targetdir/stderr case $* in @@ -103,16 +117,17 @@ do_test() { do_clean # source script in a subshell, so it has access to our # namespace, but cannot change it. + control_system_speed_limit echo -ne "$_script... " if ( set -ex ; . $_script ) &> $targetdir/log then if [ -f "${_script}.inject_error" ]; then echo "dmesg checking is skipped because test inject error" else - dmesg | grep -iq "error\|call trace\|segfault" && + dmesg | grep -iq "error\|call trace\|segfault" | grep -v "systemd" && die "dmesg prints errors when testing $_basename!" fi - echo "succeeded" + succeed "succeeded\n" _fail=0 else save_log fail @@ -300,10 +315,8 @@ parse_args() { } print_warning() { - cat <<-EOF - Warning! Tests are performed on system level mdadm! - If you want to test local build, you need to install it first! - EOF + warn "Warning! Tests are performed on system level mdadm!\n" + echo "If you want to test local build, you need to install it first!" } main() { @@ -338,6 +351,7 @@ main() { fi done + restore_selinux exit 0 } diff --git a/tests/01r5fail b/tests/01r5fail index 873dba5..c210d6e 100644 --- a/tests/01r5fail +++ b/tests/01r5fail @@ -17,11 +17,7 @@ check wait mdadm $md0 --fail $dev0 mdadm $md0 --remove $dev3 $dev0 check recovery -check state _UUU - -mdadm $md0 -a $dev3 -check recovery check wait check state UUUU -mdadm -S $md0
\ No newline at end of file +mdadm -S $md0 diff --git a/tests/01r5integ.broken b/tests/01r5integ.broken deleted file mode 100644 index 2073763..0000000 --- a/tests/01r5integ.broken +++ /dev/null @@ -1,7 +0,0 @@ -fails rarely - -Fails about 1 in every 30 runs with a sha mismatch error: - - c49ab26e1b01def7874af9b8a6d6d0c29fdfafe6 /dev/md0 does not match - 15dc2f73262f811ada53c65e505ceec9cf025cb9 /dev/md0 with /dev/loop3 - missing diff --git a/tests/01raid6integ.broken b/tests/01raid6integ.broken deleted file mode 100644 index 1df735f..0000000 --- a/tests/01raid6integ.broken +++ /dev/null @@ -1,7 +0,0 @@ -fails infrequently - -Fails about 1 in 5 with a sha mismatch: - - 8286c2bc045ae2cfe9f8b7ae3a898fa25db6926f /dev/md0 does not match - a083a0738b58caab37fd568b91b177035ded37df /dev/md0 with /dev/loop2 and - /dev/loop3 missing diff --git a/tests/03assem-incr b/tests/03assem-incr index 38880a7..56afbf2 100644 --- a/tests/03assem-incr +++ b/tests/03assem-incr @@ -9,15 +9,23 @@ set -x -e levels=(raid0 raid1 raid5) if [ "$LINEAR" == "yes" ]; then - levels+=( linear ) + levels+=( linear ) fi +is_raid_foreign $md0 + for l in ${levels[@]} do - mdadm -CR $md0 -l $l -n5 $dev0 $dev1 $dev2 $dev3 $dev4 --assume-clean - mdadm -S md0 - mdadm -I $dev1 - mdadm -I $dev3 - mdadm -A /dev/md0 $dev0 $dev1 $dev2 $dev3 $dev4 - mdadm -S /dev/md0 + mdadm -CR $md0 -l $l -n5 $dev0 $dev1 $dev2 $dev3 $dev4 --assume-clean + mdadm -S $md0 + mdadm -I $dev1 + mdadm -I $dev3 + mdadm -A $md0 $dev0 $dev1 $dev2 $dev3 $dev4 + # If one array is foreign (metadata name doesn't have the machine's + # hostname), mdadm chooses a minor number automatically from 127 + if [ $is_foreign == "no" ]; then + mdadm -S $md0 + else + mdadm -S $md127 + fi done diff --git a/tests/03r0assem b/tests/03r0assem index f7c29e8..4bf8b9e 100644 --- a/tests/03r0assem +++ b/tests/03r0assem @@ -35,16 +35,6 @@ mdadm -S $md2 { echo DEVICE $devlist - echo array $md2 name=2 -} > $conf - -mdadm -As -c $conf $md2 -$tst -mdadm -S $md2 - - -{ - echo DEVICE $devlist echo array $md2 devices=$dev0,$dev1,$dev2 } > $conf diff --git a/tests/03r5assem-failed b/tests/03r5assem-failed deleted file mode 100644 index d38241d..0000000 --- a/tests/03r5assem-failed +++ /dev/null @@ -1,12 +0,0 @@ - -# Create an array, fail one device while array is active, stop array, -# then re-assemble listing the failed device first. - -mdadm -CR $md1 -l5 -n4 $dev0 $dev1 $dev2 $dev3 -check wait - -echo 2000 > /sys/block/md1/md/safe_mode_delay -mkfs $md1 -mdadm $md1 -f $dev0 -mdadm -S $md1 -mdadm -A $md1 $dev0 $dev1 $dev2 $dev3 || exit 1 diff --git a/tests/03r5assemV1 b/tests/03r5assemV1 index bca0c58..6026011 100644 --- a/tests/03r5assemV1 +++ b/tests/03r5assemV1 @@ -33,14 +33,6 @@ eval $tst { echo DEVICE $devlist - echo array $md1 name=one -} > $conf - -mdadm -As -c $conf -eval $tst - -{ - echo DEVICE $devlist echo array $md1 devices=$dev0,$dev1,$dev2,$dev3,$dev4 } > $conf @@ -90,15 +82,6 @@ eval $tst { echo DEVICE $devlist - echo array $md1 name=one -} > $conf - -mdadm -As -c $conf -check state U_U -eval $tst - -{ - echo DEVICE $devlist echo array $md1 devices=$dev0,$dev1,$dev2 } > $conf diff --git a/tests/04r5swap.broken b/tests/04r5swap.broken deleted file mode 100644 index e38987d..0000000 --- a/tests/04r5swap.broken +++ /dev/null @@ -1,7 +0,0 @@ -always fails - -Fails with errors: - - mdadm: /dev/loop0 has no superblock - assembly aborted - - ERROR: no recovery happening diff --git a/tests/04update-metadata b/tests/04update-metadata index 2b72a30..c748770 100644 --- a/tests/04update-metadata +++ b/tests/04update-metadata @@ -8,24 +8,29 @@ set -xe dlist="$dev0 $dev1 $dev2 $dev3" -for ls in linear/4 raid1/1 raid5/3 raid6/2 +if [ $skipping_linear == "yes" ]; then + level_list="raid1/1 raid5/3 raid6/2" +else + level_list="linear/4 raid1/1 raid5/3 raid6/2" +fi +for ls in $level_list do - s=${ls#*/} l=${ls%/*} - if [[ $l == 'raid1' ]]; then - mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 $dlist - else - mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist - fi - testdev $md0 $s 19904 64 - mdadm -S $md0 - mdadm -A $md0 --update=metadata $dlist - testdev $md0 $s 19904 64 check - mdadm -S $md0 + s=${ls#*/} l=${ls%/*} + if [[ $l == 'raid1' ]]; then + mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 $dlist + else + mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist + fi + testdev $md0 $s 19904 64 + mdadm -S $md0 + mdadm -A $md0 --update=metadata $dlist + testdev $md0 $s 19904 64 check + mdadm -S $md0 done if mdadm -A $md0 --update=metadata $dlist then echo >&2 should fail with v1.0 metadata - exit 1 + exit 1 fi mdadm -CR -e 0.90 $md0 --level=6 -n4 -c32 $dlist @@ -33,7 +38,7 @@ mdadm -S $md0 if mdadm -A $md0 --update=metadata $dlist then echo >&2 should fail during resync - exit 1 + exit 1 fi mdadm -A $md0 $dlist mdadm --wait $md0 || true @@ -48,5 +53,5 @@ mdadm -S $md0 if mdadm -A $md0 --update=metadata $dlist then echo >&2 should fail when bitmap present - exit 1 + exit 1 fi diff --git a/tests/04update-uuid b/tests/04update-uuid index a4409e7..25314ab 100644 --- a/tests/04update-uuid +++ b/tests/04update-uuid @@ -25,7 +25,7 @@ mdadm -S /dev/md0 # now if we have a bitmap, that needs updating too. rm -f $targetdir/bitmap -mdadm -CR --assume-clean -b $targetdir/bitmap $md0 -l5 -n3 $dev0 $dev1 $dev2 +yes | mdadm -CR --assume-clean -b $targetdir/bitmap $md0 -l5 -n3 $dev0 $dev1 $dev2 mdadm -S /dev/md0 mdadm -A /dev/md0 -b $targetdir/bitmap --update=uuid --uuid=0123456789abcdef:fedcba9876543210 $dev0 $dev1 $dev2 no_errors @@ -41,7 +41,7 @@ mdadm -S /dev/md0 # and bitmap for version1 rm -f $targetdir/bitmap -mdadm -CR --assume-clean -e1.1 -b $targetdir/bitmap $md0 -l5 -n3 $dev0 $dev1 $dev2 +yes | mdadm -CR --assume-clean -e1.1 -b $targetdir/bitmap $md0 -l5 -n3 $dev0 $dev1 $dev2 mdadm -S /dev/md0 mdadm -A /dev/md0 -b $targetdir/bitmap --update=uuid --uuid=0123456789abcdef:fedcba9876543210 $dev0 $dev1 $dev2 no_errors diff --git a/tests/05r1-bitmapfile b/tests/05r1-bitmapfile deleted file mode 100644 index f384f0e..0000000 --- a/tests/05r1-bitmapfile +++ /dev/null @@ -1,49 +0,0 @@ - -# -# create a raid1 with a bitmap file -# -bmf=$targetdir/bitmap -rm -f $bmf -mdadm --create --run $md0 --level=1 -n2 --delay=1 --bitmap $bmf $dev1 $dev2 -check wait -testdev $md0 1 $mdsize1a 64 -mdadm -S $md0 - -mdadm --assemble $md0 --bitmap=$bmf $dev1 $dev2 -testdev $md0 1 $mdsize1a 64 -dirty1=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty2=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" - exit 1 -fi -mdadm $md0 -f $dev1 -testdev $md0 1 $mdsize1a 64 -sleep 4 -dirty3=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" - exit 2 -fi - -mdadm -S $md0 - -mdadm --assemble -R $md0 --bitmap=$bmf $dev2 -dirty4=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -mdadm --zero $dev1 # force --add, not --re-add -mdadm $md0 --add $dev1 -#it is too fast# check recovery - -check wait -sleep 4 -dirty5=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" - exit 1 -fi - -mdadm -S $md0 diff --git a/tests/05r1-grow-external b/tests/05r1-grow-external deleted file mode 100644 index 69da3e9..0000000 --- a/tests/05r1-grow-external +++ /dev/null @@ -1,33 +0,0 @@ - -# -# create a raid1 array, add an external bitmap -# -mdadm --create --run $md0 -l 1 -n 2 $dev1 $dev2 -check wait -testdev $md0 1 $mdsize1a 64 - -bmf=$targetdir/bm -rm -f $bmf -#mdadm -E $dev1 -mdadm --grow $md0 --bitmap=$bmf --delay=1 || { mdadm -X $bmf ; exit 1; } -dirty1=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty2=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -testdev $md0 1 $mdsize1a 64 -dirty3=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty4=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -#echo $dirty1 $dirty2 $dirty3 $dirty4 -if [ $dirty2 -ne 0 -o $dirty4 -ne 0 -o $dirty3 -lt 400 ] -then - echo bad dirty counts - exit 1 -fi - -# now to remove the bitmap -check bitmap -mdadm --grow $md0 --bitmap=none -check nobitmap -mdadm -S $md0 diff --git a/tests/05r1-grow-internal b/tests/05r1-grow-internal index 24b3aec..f7fff98 100644 --- a/tests/05r1-grow-internal +++ b/tests/05r1-grow-internal @@ -8,18 +8,15 @@ testdev $md0 1 $mdsize1a 64 #mdadm -E $dev1 mdadm --grow $md0 --bitmap=internal --bitmap-chunk=4 --delay=1 || { mdadm -X $dev2 ; exit 1; } -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` testdev $md0 1 $mdsize1a 64 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -#echo $dirty1 $dirty2 $dirty3 $dirty4 -if [ $dirty2 -ne 0 -o $dirty4 -ne 0 -o $dirty3 -lt 400 ] -then +if [ $dirty1 -ne 0 -o $dirty2 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: dirty1 $dirty1, dirty2 $dirty2" echo bad dirty counts exit 1 fi diff --git a/tests/05r1-grow-internal-1 b/tests/05r1-grow-internal-1 index 2f0d823..f0f8349 100644 --- a/tests/05r1-grow-internal-1 +++ b/tests/05r1-grow-internal-1 @@ -8,19 +8,15 @@ testdev $md0 1 $mdsize1b 64 #mdadm -E $dev1 mdadm --grow $md0 --bitmap=internal --bitmap-chunk=4 --delay=1 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` testdev $md0 1 $mdsize1b 64 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -#echo $dirty1 $dirty2 $dirty3 $dirty4 -if [ $dirty2 -ne 0 -o $dirty4 -ne 0 -o $dirty3 -lt 400 ] -then - echo bad dirty counts +if [ $dirty1 -ne 0 -o $dirty2 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: dirty1 $dirty1, dirty2 $dirty2" exit 1 fi diff --git a/tests/05r1-internalbitmap b/tests/05r1-internalbitmap index dd7232a..f1a2843 100644 --- a/tests/05r1-internalbitmap +++ b/tests/05r1-internalbitmap @@ -9,21 +9,20 @@ mdadm -S $md0 mdadm --assemble $md0 $dev1 $dev2 testdev $md0 1 $mdsize0 64 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" +if [ $dirty1 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty1" exit 1 fi mdadm $md0 -f $dev1 testdev $md0 1 $mdsize0 64 sleep 4 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" +total=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) bits.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +if [ $dirty2 -ne $total ] +then echo >&2 "ERROR bad 'dirty' counts: total $total, dirty2 $dirty2" exit 2 fi @@ -34,13 +33,12 @@ mdadm --zero-superblock $dev1 mdadm $md0 --add $dev1 check recovery -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` check wait sleep 4 -dirty5=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" +if [ $dirty3 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty3" exit 1 fi diff --git a/tests/05r1-internalbitmap-v1a b/tests/05r1-internalbitmap-v1a index 3ddc082..cf3f397 100644 --- a/tests/05r1-internalbitmap-v1a +++ b/tests/05r1-internalbitmap-v1a @@ -10,21 +10,20 @@ mdadm -S $md0 mdadm --assemble $md0 $dev1 $dev2 testdev $md0 1 $mdsize1b 64 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" +if [ $dirty1 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty1" exit 1 fi mdadm $md0 -f $dev1 testdev $md0 1 $mdsize1b 64 sleep 4 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" +total=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) bits.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +if [ $dirty2 -ne $total ] +then echo >&2 "ERROR bad 'dirty' counts: total $total, dirty2 $dirty2" exit 2 fi @@ -35,13 +34,12 @@ mdadm --assemble -R $md0 $dev2 mdadm $md0 --add $dev1 check recovery -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` check wait sleep 4 -dirty5=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" +if [ $dirty3 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty3" exit 1 fi diff --git a/tests/05r1-internalbitmap-v1b b/tests/05r1-internalbitmap-v1b index 40f7abe..4952887 100644 --- a/tests/05r1-internalbitmap-v1b +++ b/tests/05r1-internalbitmap-v1b @@ -11,21 +11,20 @@ mdadm -S $md0 mdadm --assemble $md0 $dev1 $dev2 check bitmap testdev $md0 1 $mdsize11 64 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" +if [ $dirty1 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty1" exit 1 fi mdadm $md0 -f $dev1 testdev $md0 1 $mdsize11 64 sleep 4 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" +total=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) bits.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +if [ $dirty2 -ne $total ] +then echo >&2 "ERROR bad 'dirty' counts: total $total, dirty2 $dirty2" exit 2 fi @@ -35,14 +34,12 @@ mdadm --zero-superblock $dev1 mdadm --assemble -R $md0 $dev2 mdadm $md0 --add $dev1 check recovery - -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` check wait sleep 4 -dirty5=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" +if [ $dirty3 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty3" exit 1 fi diff --git a/tests/05r1-internalbitmap-v1c b/tests/05r1-internalbitmap-v1c index 2eaea59..e1e4472 100644 --- a/tests/05r1-internalbitmap-v1c +++ b/tests/05r1-internalbitmap-v1c @@ -10,21 +10,20 @@ mdadm -S $md0 mdadm --assemble $md0 $dev1 $dev2 testdev $md0 1 $mdsize12 64 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" +if [ $dirty1 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty1" exit 1 fi mdadm $md0 -f $dev1 testdev $md0 1 $mdsize12 64 sleep 4 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" +total=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) bits.*/\1/p'` +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +if [ $dirty2 -ne $total ] +then echo >&2 "ERROR bad 'dirty' counts: total $total, dirty2 $dirty2" exit 2 fi @@ -35,13 +34,12 @@ mdadm --assemble -R $md0 $dev2 mdadm $md0 --add $dev1 check recovery -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` check wait sleep 4 -dirty5=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" +if [ $dirty3 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty3" exit 1 fi diff --git a/tests/05r1-n3-bitmapfile b/tests/05r1-n3-bitmapfile deleted file mode 100644 index f1c3f1e..0000000 --- a/tests/05r1-n3-bitmapfile +++ /dev/null @@ -1,53 +0,0 @@ - -# -# create a raid1 with 3 devices and a bitmap file -# make sure resync does right thing. -# -# -bmf=$targetdir/bitmap -rm -f $bmf -mdadm --create -e0.90 --run $md0 --level=1 -n3 --delay=1 --bitmap $bmf $dev1 $dev2 $dev3 -check wait -testdev $md0 1 $mdsize0 64 -mdadm -S $md0 - -mdadm --assemble $md0 --bitmap=$bmf $dev1 $dev2 $dev3 -testdev $md0 1 $mdsize0 64 -dirty1=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty2=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" - exit 1 -fi -mdadm $md0 -f $dev2 -testdev $md0 1 $mdsize0 64 -sleep 4 -dirty3=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" - exit 2 -fi - -mdadm -S $md0 - -mdadm --assemble -R $md0 --bitmap=$bmf $dev1 $dev3 -check nosync -mdadm --zero-superblock $dev2 -mdadm $md0 --add $dev2 -check recovery - -dirty4=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -check wait -sleep 4 -dirty5=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" - exit 1 -fi - -mdadm -S $md0 -exit 0 diff --git a/tests/05r1-re-add-nosuper b/tests/05r1-re-add-nosuper index 058d602..7d41fd7 100644 --- a/tests/05r1-re-add-nosuper +++ b/tests/05r1-re-add-nosuper @@ -6,7 +6,7 @@ # bmf=$targetdir/bitmap2 rm -f $bmf -mdadm -B $md0 -l1 -n2 -b$bmf -d1 $dev1 $dev2 +yes | mdadm -B $md0 -l1 -n2 -b$bmf -d1 $dev1 $dev2 check resync check wait testdev $md0 1 $size 1 diff --git a/tests/05r5-bitmapfile b/tests/05r5-bitmapfile deleted file mode 100644 index 6d173d8..0000000 --- a/tests/05r5-bitmapfile +++ /dev/null @@ -1,49 +0,0 @@ - -# -# create a raid1 with a bitmap file -# -bmf=$targetdir/bitmap -rm -f $bmf -mdadm --create --run $md0 --level=5 -n3 --delay=1 --bitmap $bmf $dev1 $dev2 $dev3 -check wait -testdev $md0 2 $mdsize1 512 -mdadm -S $md0 - -mdadm --assemble $md0 --bitmap=$bmf $dev1 $dev2 $dev3 -testdev $md0 2 $mdsize1 512 -dirty1=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty2=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" - exit 1 -fi -mdadm $md0 -f $dev1 -testdev $md0 2 $mdsize1 512 -sleep 4 -dirty3=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" - exit 2 -fi - -mdadm -S $md0 - -mdadm --assemble -R $md0 --bitmap=$bmf $dev2 $dev3 -mdadm --zero $dev1 # force add, not re-add -mdadm $md0 --add $dev1 -check recovery - -dirty4=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -check wait -sleep 4 -dirty5=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" - exit 1 -fi - -mdadm -S $md0 diff --git a/tests/05r5-internalbitmap b/tests/05r5-internalbitmap index 13dc592..1a64482 100644 --- a/tests/05r5-internalbitmap +++ b/tests/05r5-internalbitmap @@ -9,21 +9,20 @@ mdadm -S $md0 mdadm --assemble $md0 $dev1 $dev2 $dev3 testdev $md0 2 $mdsize1 512 -dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` sleep 4 -dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty1=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" +if [ $dirty1 -ne 0 ] +then echo >&2 "ERROR bad 'dirty' counts: $dirty1" exit 1 fi mdadm $md0 -f $dev1 testdev $md0 2 $mdsize1 512 sleep 4 -dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] +dirty2=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +if [ $dirty2 -lt 400 ] then - echo >&2 "ERROR dirty count $dirty3 is too small" + echo >&2 "ERROR dirty count $dirty2 is too small" exit 2 fi @@ -33,14 +32,12 @@ mdadm --assemble -R $md0 $dev2 $dev3 mdadm --zero $dev1 # force --add, not --re-add mdadm $md0 --add $dev1 check recovery - -dirty4=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` check wait sleep 4 -dirty5=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` +dirty3=`mdadm -X $dev2 | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" +if [ $dirty3 -ne 0 ] +then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty3" exit 1 fi diff --git a/tests/05r6-bitmapfile b/tests/05r6-bitmapfile deleted file mode 100644 index d11896d..0000000 --- a/tests/05r6-bitmapfile +++ /dev/null @@ -1,49 +0,0 @@ - -# -# create a raid1 with a bitmap file -# -bmf=$targetdir/bitmap -rm -f $bmf -mdadm --create --run $md0 --level=6 -n4 --delay=1 --bitmap $bmf $dev1 $dev2 $dev3 $dev4 -check wait -testdev $md0 2 $mdsize1 512 -mdadm -S $md0 - -mdadm --assemble $md0 --bitmap=$bmf $dev1 $dev2 $dev3 $dev4 -testdev $md0 2 $mdsize1 512 -dirty1=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -sleep 4 -dirty2=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty1 -lt 400 -o $dirty2 -ne 0 ] -then echo >&2 "ERROR bad 'dirty' counts: $dirty1 and $dirty2" - exit 1 -fi -mdadm $md0 -f $dev3 -testdev $md0 2 $mdsize1 512 -sleep 4 -dirty3=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -if [ $dirty3 -lt 400 ] -then - echo >&2 "ERROR dirty count $dirty3 is too small" - exit 2 -fi - -mdadm -S $md0 - -mdadm --assemble -R $md0 --bitmap=$bmf $dev1 $dev2 $dev4 -mdadm --zero $dev3 # force --add, not --re-add -mdadm $md0 --add $dev3 -check recovery - -dirty4=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` -check wait -sleep 4 -dirty5=`mdadm -X $bmf | sed -n -e 's/.*Bitmap.* \([0-9]*\) dirty.*/\1/p'` - -if [ $dirty4 -lt 400 -o $dirty5 -ne 0 ] -then echo echo >&2 "ERROR bad 'dirty' counts at end: $dirty4 $dirty5" - exit 1 -fi - -mdadm -S $md0 diff --git a/tests/06name b/tests/06name index 86eaab6..9ec3437 100644 --- a/tests/06name +++ b/tests/06name @@ -2,9 +2,17 @@ set -x # create an array with a name +is_raid_foreign $md0 + mdadm -CR $md0 -l0 -n2 --metadata=1 --name="Fred" $dev0 $dev1 -mdadm -E $dev0 | grep 'Name : Fred' > /dev/null || exit 1 -mdadm -D $md0 | grep 'Name : Fred' > /dev/null || exit 1 + +if [ $is_foreign == "no" ]; then + mdadm -E $dev0 | grep "Name : $(hostname):Fred" > /dev/null || exit 1 + mdadm -D $md0 | grep "Name : $(hostname):Fred" > /dev/null || exit 1 +else + mdadm -E $dev0 | grep "Name : Fred" > /dev/null || exit 1 + mdadm -D $md0 | grep "Name : Fred" > /dev/null || exit 1 +fi mdadm -S $md0 mdadm -A $md0 --name="Fred" $devlist diff --git a/tests/07autoassemble b/tests/07autoassemble index e689be7..b6630e1 100644 --- a/tests/07autoassemble +++ b/tests/07autoassemble @@ -2,6 +2,9 @@ # create two raid1s, build a raid0 on top, then # tear it down and get auto-assemble to rebuild it. +#the length of md0/md1/md2 is same. So use md0 here. +is_raid_foreign $md0 + mdadm -CR $md1 -l1 -n2 $dev0 $dev1 --homehost=testing mdadm -CR $md2 -l1 -n2 $dev2 $dev3 --homehost=testing mdadm -CR $md0 -l0 -n2 $md1 $md2 --homehost=testing @@ -10,7 +13,14 @@ mdadm -Ss mdadm -As -c /dev/null --homehost=testing -vvv testdev $md1 1 $mdsize1a 64 testdev $md2 1 $mdsize1a 64 -testdev $md0 2 $mdsize11a 512 +# md1 and md2 will be incremental assemble by udev rule. And +# the testing machines' hostname is not testing. The md0 will +# be considered as a foreign array. It can use 0 as metadata +# name. md127 will be used +testdev $md127 2 $mdsize11a 512 +mdadm --stop $md127 +mdadm --zero-superblock $md1 +mdadm --zero-superblock $md2 mdadm -Ss mdadm --zero-superblock $dev0 $dev1 $dev2 $dev3 @@ -20,5 +30,31 @@ mdadm -CR $md0 -l0 -n2 $md1 $dev2 --homehost=testing mdadm -Ss mdadm -As -c /dev/null --homehost=testing -vvv testdev $md1 1 $mdsize1a 64 -testdev $md0 1 $[mdsize1a+mdsize11a] 512 +testdev $md127 1 $[mdsize1a+mdsize11a] 512 +mdadm --stop $md127 +mdadm --zero-superblock $md1 +mdadm -Ss + +# Don't specify homehost when creating raid and use the test +# machine's homehost. For super1.2, if homehost name's length +# is > 32, it doesn't use homehost name in metadata name and +# the array will be treated as foreign array +mdadm --zero-superblock $dev0 $dev1 $dev2 $dev3 +mdadm -CR $md1 -l1 -n2 $dev0 $dev1 +mdadm -CR $md2 -l1 -n2 $dev2 $dev3 +mdadm -CR $md0 -l0 -n2 $md1 $md2 +mdadm -Ss +mdadm -As -c /dev/null +if [ $is_foreign == "yes" ]; then + # md127 is md1 + testdev $md127 1 $mdsize1a 64 + # md126 is md0, udev rule incremental assemble it + testdev $md126 2 $mdsize11a 512 + # md125 is md2 + testdev $md125 1 $mdsize1a 64 +else + testdev $md1 1 $mdsize1a 64 + testdev $md2 1 $mdsize1a 64 + testdev $md0 2 $mdsize11a 512 +fi mdadm -Ss diff --git a/tests/07autoassemble.broken b/tests/07autoassemble.broken deleted file mode 100644 index 8be0940..0000000 --- a/tests/07autoassemble.broken +++ /dev/null @@ -1,8 +0,0 @@ -always fails - -Prints lots of messages, but the array doesn't assemble. Error -possibly related to: - - mdadm: /dev/md/1 is busy - skipping - mdadm: no recogniseable superblock on /dev/md/testing:0 - mdadm: /dev/md/2 is busy - skipping diff --git a/tests/07autodetect.broken b/tests/07autodetect.broken deleted file mode 100644 index 294954a..0000000 --- a/tests/07autodetect.broken +++ /dev/null @@ -1,5 +0,0 @@ -always fails - -Fails with error: - - ERROR: no resync happening diff --git a/tests/07changelevelintr b/tests/07changelevelintr index 18c6309..d921f2b 100644 --- a/tests/07changelevelintr +++ b/tests/07changelevelintr @@ -27,11 +27,9 @@ checkgeo() { } restart() { - sleep 0.5 check reshape mdadm -S $md0 mdadm -A $md0 $devs --backup-file=$bu - sleep 0.5 check reshape } @@ -49,13 +47,16 @@ mdadm -G $md0 --layout rs --backup-file=$bu restart checkgeo md0 raid5 5 $[128*1024] 3 -mdadm -G $md0 --array-size 58368 +# It needs to shrink array size first. Choose a value that +# is power of 2 for array size. If not, it can't change +# chunk size. +mdadm -G $md0 --array-size 51200 mdadm -G $md0 --raid-disks 4 -c 64 --backup-file=$bu restart checkgeo md0 raid5 4 $[64*1024] 3 devs="$dev0 $dev1 $dev2 $dev3" -mdadm -G $md0 --array-size 19456 +mdadm -G $md0 --array-size 18432 mdadm -G $md0 -n 2 -c 256 --backup-file=$bu restart checkgeo md0 raid5 2 $[256*1024] 3 diff --git a/tests/07changelevelintr.broken b/tests/07changelevelintr.broken deleted file mode 100644 index 284b490..0000000 --- a/tests/07changelevelintr.broken +++ /dev/null @@ -1,9 +0,0 @@ -always fails - -Fails with errors: - - mdadm: this change will reduce the size of the array. - use --grow --array-size first to truncate array. - e.g. mdadm --grow /dev/md0 --array-size 56832 - - ERROR: no reshape happening diff --git a/tests/07revert-grow b/tests/07revert-grow index c8c4e85..333483d 100644 --- a/tests/07revert-grow +++ b/tests/07revert-grow @@ -43,7 +43,7 @@ testdev $md0 2 $mdsize1 512 mdadm -G $md0 -n 5 sleep 3 mdadm -S $md0 -strace -o /tmp/str ./mdadm -A $md0 --update=revert-reshape $devlist4 +mdadm -A $md0 --update=revert-reshape $devlist4 check wait check raid10 testdev $md0 2 $mdsize1 512 diff --git a/tests/07revert-inplace b/tests/07revert-inplace index a73eb97..776324a 100644 --- a/tests/07revert-inplace +++ b/tests/07revert-inplace @@ -37,7 +37,7 @@ testdev $md0 3 $mdsize1 64 mdadm -G $md0 -c 32 sleep 2 mdadm -S $md0 -strace -o /tmp/str ./mdadm -A $md0 --update=revert-reshape $devlist5 +mdadm -A $md0 --update=revert-reshape $devlist5 check wait check raid10 testdev $md0 3 $mdsize1 64 diff --git a/tests/23rdev-lifetime b/tests/23rdev-lifetime index 1750b0d..03b61de 100644 --- a/tests/23rdev-lifetime +++ b/tests/23rdev-lifetime @@ -4,7 +4,7 @@ pid="" runtime=2 clean_up_test() { - pill -9 $pid + kill -9 $pid echo clear > /sys/block/md0/md/array_state } diff --git a/tests/func.sh b/tests/func.sh index b474442..e7ccc4f 100644 --- a/tests/func.sh +++ b/tests/func.sh @@ -23,6 +23,28 @@ mdsize12=19988 # ddf needs bigger devices as 32Meg is reserved! ddfsize=65536 +# Systemd flags +devname_as_serial_flag="IMSM_DEVNAME_AS_SERIAL=1" +no_platform_flag="IMSM_NO_PLATFORM=1" + +# Common colors +COLOR_FAIL='\033[0;31m' #RED +COLOR_WARN='\033[1;33m' #YELLOW +COLOR_SUCCESS='\033[0;32m' #GREEN +COLOR_NONE='\033[0m' + +fail() { + printf "${COLOR_FAIL}$1${COLOR_NONE}" +} + +warn() { + printf "${COLOR_WARN}$1${COLOR_NONE}" +} + +succeed() { + printf "${COLOR_SUCCESS}$1${COLOR_NONE}" +} + # $1 is optional parameter, it shows why to save log save_log() { status=$1 @@ -36,7 +58,8 @@ save_log() { cat /proc/mdstat >> $logdir/$logfile array=($(mdadm -Ds | cut -d' ' -f2)) [ "$1" == "fail" ] && - echo "FAILED - see $logdir/$_basename.log and $logdir/$logfile for details" + fail "FAILED" + echo " - see $logdir/$_basename.log and $logdir/$logfile for details\n" if [ $DEVTYPE == 'lvm' ] then # not supported lvm type yet @@ -86,6 +109,7 @@ cleanup() { $mdadm --zero ${disks[@]} &> /dev/null ;; esac + clean_systemd_env } do_clean() @@ -125,6 +149,7 @@ check_env() { MULTIPATH="yes" if [ "$MULTIPATH" != "yes" ]; then echo "test: skipping tests for multipath, which is removed in upstream 6.8+ kernels" + skipping_multipath="yes" fi # Check whether to run linear tests @@ -133,14 +158,75 @@ check_env() { LINEAR="yes" if [ "$LINEAR" != "yes" ]; then echo "test: skipping tests for linear, which is removed in upstream 6.8+ kernels" + skipping_linear="yes" + fi +} + +record_system_speed_limit() { + system_speed_limit_max=`cat /proc/sys/dev/raid/speed_limit_max` + system_speed_limit_min=`cat /proc/sys/dev/raid/speed_limit_min` +} + +# To avoid sync action finishes before checking it, it needs to limit +# the sync speed +control_system_speed_limit() { + echo $test_speed_limit_min > /proc/sys/dev/raid/speed_limit_min + echo $test_speed_limit_max > /proc/sys/dev/raid/speed_limit_max +} + +restore_system_speed_limit() { + echo $system_speed_limit_min > /proc/sys/dev/raid/speed_limit_max + echo $system_speed_limit_max > /proc/sys/dev/raid/speed_limit_max +} + +is_raid_foreign() { + + name=$1 + # super1 uses this formula strlen(homehost)+1+strlen(name) < 32 + # to decide if an array is foreign or local. It adds homehost if + # one array is local + hostname=$(hostname) + if [ `expr length "$(hostname)$name"` -lt 31 ]; then + is_foreign="no" + else + is_foreign="yes" fi } +record_selinux() { + sys_selinux=`getenforce` + setenforce Permissive +} + +restore_selinux() { + setenforce $sys_selinux +} + +setup_systemd_env() { + warn "Warning! Test suite will set up systemd environment!\n" + echo "Use \"systemctl show-environment\" to show systemd environment variables" + for env_var in $devname_as_serial_flag $no_platform_flag + do + systemctl set-environment $env_var + echo "Added $env_var" to systemd environment, use \ + \"systemctl unset-environment $env_var\" to remove it. + done +} + +clean_systemd_env() { + for env_var in $devname_as_serial_flag $no_platform_flag + do + systemctl unset-environment $env_var + echo "Removed $env_var from systemd environment." + done +} + do_setup() { trap cleanup 0 1 3 15 trap ctrl_c 2 check_env + setup_systemd_env [ -d $logdir ] || mkdir -p $logdir devlist= @@ -214,6 +300,8 @@ do_setup() { ulimit -c unlimited [ -f /proc/mdstat ] || modprobe md_mod echo 0 > /sys/module/md_mod/parameters/start_ro + record_system_speed_limit + record_selinux } # check various things @@ -265,15 +353,17 @@ check() { fi ;; wait ) - p=`cat /proc/sys/dev/raid/speed_limit_max` - echo 2000000 > /proc/sys/dev/raid/speed_limit_max + min=`cat /proc/sys/dev/raid/speed_limit_min` + max=`cat /proc/sys/dev/raid/speed_limit_max` + echo 200000 > /proc/sys/dev/raid/speed_limit_max sleep 0.1 while grep -Eq '(resync|recovery|reshape|check|repair) *=' /proc/mdstat || grep -v idle > /dev/null /sys/block/md*/md/sync_action do sleep 0.5 done - echo $p > /proc/sys/dev/raid/speed_limit_max + echo $min > /proc/sys/dev/raid/speed_limit_min + echo $max > /proc/sys/dev/raid/speed_limit_max ;; state ) grep -sq "blocks.*\[$2\]\$" /proc/mdstat || diff --git a/tests/templates/names_template b/tests/templates/names_template index 1b6cd14..c94245e 100644 --- a/tests/templates/names_template +++ b/tests/templates/names_template @@ -4,6 +4,8 @@ function names_create() { local NAME=$2 local NEG_TEST=$3 + is_raid_foreign $DEVNAME + if [[ -z "$NAME" ]]; then mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force else @@ -30,6 +32,7 @@ function names_verify() { local DEVNODE_NAME="$1" local WANTED_LINK="$2" local WANTED_NAME="$3" + local EXPECTED="" local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)" if [[ "$?" != "0" ]]; then @@ -38,7 +41,12 @@ function names_verify() { fi if [[ "$WANTED_LINK" != "empty" ]]; then - local EXPECTED="MD_DEVNAME=$WANTED_LINK" + EXPECTED="MD_DEVNAME=$WANTED_LINK" + + if [ ! -b /dev/md/$WANTED_LINK ]; then + echo "/dev/md/$WANTED_LINK doesn't exit" + exit 1 + fi fi if [[ "$RES" != "$EXPECTED" ]]; then @@ -52,7 +60,11 @@ function names_verify() { exit 1 fi - local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME" + if [ $is_foreign == "no" ]; then + EXPECTED="MD_NAME=$(hostname):$WANTED_NAME" + else + EXPECTED="MD_NAME=$WANTED_NAME" + fi if [[ "$RES" != "$EXPECTED" ]]; then echo "$RES doesn't match $EXPECTED." exit 1 @@ -633,9 +633,9 @@ int check_ext2(int fd, char *name) bsize = sb[24]|(sb[25]|(sb[26]|sb[27]<<8)<<8)<<8; size = sb[4]|(sb[5]|(sb[6]|sb[7]<<8)<<8)<<8; size <<= bsize; - pr_err("%s appears to contain an ext2fs file system\n", + pr_info("%s appears to contain an ext2fs file system\n", name); - cont_err("size=%lluK mtime=%s", size, ctime(&mtime)); + pr_info("size=%lluK mtime=%s", size, ctime(&mtime)); return 1; } @@ -725,23 +725,33 @@ int stat_is_blkdev(char *devname, dev_t *rdev) return 1; } +/** + * ask() - prompt user for "yes/no" dialog. + * @mesg: message to be printed, without '?' sign. + * Returns: 1 if 'Y/y', 0 otherwise. + * + * The default value is 'N/n', thus the caps on "N" on prompt. + */ int ask(char *mesg) { - char *add = ""; - int i; - for (i = 0; i < 5; i++) { - char buf[100]; - fprintf(stderr, "%s%s", mesg, add); - fflush(stderr); - if (fgets(buf, 100, stdin)==NULL) - return 0; - if (buf[0]=='y' || buf[0]=='Y') - return 1; - if (buf[0]=='n' || buf[0]=='N') - return 0; - add = "(y/n) "; + char buf[3] = {0}; + + fprintf(stderr, "%s [y/N]? ", mesg); + fflush(stderr); + if (fgets(buf, 3, stdin) == NULL) + return 0; + if (strlen(buf) == 1) { + pr_err("assuming no.\n"); + return 0; } - pr_err("assuming 'no'\n"); + if (buf[1] != '\n') + goto bad_option; + if (toupper(buf[0]) == 'Y') + return 1; + if (toupper(buf[0]) == 'N') + return 0; +bad_option: + pr_err("bad option.\n"); return 0; } @@ -1868,6 +1878,7 @@ int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info) if (st->ss->external) return sysfs_set_array(info); + memset(&inf, 0, sizeof(inf)); inf.major_version = info->array.major_version; inf.minor_version = info->array.minor_version; @@ -1891,7 +1902,7 @@ unsigned long long min_recovery_start(struct mdinfo *array) return recovery_start; } -int mdmon_pid(char *devnm) +int mdmon_pid(const char *devnm) { char path[100]; char pid[10]; @@ -1911,7 +1922,7 @@ int mdmon_pid(char *devnm) return atoi(pid); } -int mdmon_running(char *devnm) +int mdmon_running(const char *devnm) { int pid = mdmon_pid(devnm); if (pid <= 0) @@ -1921,6 +1932,80 @@ int mdmon_running(char *devnm) return 0; } +/* + * wait_for_mdmon_control_socket() - Waits for mdmon control socket + * to be created within specified time. + * @container_devnm: Device for which mdmon control socket should start. + * + * In foreground mode, when mdadm is trying to connect to control + * socket it is possible that the mdmon has not created it yet. + * Give some time to mdmon to create socket. Timeout set to 2 sec. + * + * Return: MDADM_STATUS_SUCCESS if connect succeed, otherwise return + * error code. + */ +mdadm_status_t wait_for_mdmon_control_socket(const char *container_devnm) +{ + enum mdadm_status status = MDADM_STATUS_SUCCESS; + int sfd, rv, retry_count = 0; + struct sockaddr_un addr; + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "%s/%s.sock", MDMON_DIR, container_devnm); + sfd = socket(PF_LOCAL, SOCK_STREAM, 0); + if (!is_fd_valid(sfd)) + return MDADM_STATUS_ERROR; + + addr.sun_family = PF_LOCAL; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; + + for (retry_count = 0; retry_count < 10; retry_count++) { + rv = connect(sfd, (struct sockaddr*)&addr, sizeof(addr)); + if (rv < 0) { + sleep_for(0, MSEC_TO_NSEC(200), true); + continue; + } + break; + } + + if (rv < 0) { + pr_err("Failed to connect to control socket.\n"); + status = MDADM_STATUS_ERROR; + } + close(sfd); + return status; +} + +/* + * wait_for_mdmon() - Waits for mdmon within specified time. + * @devnm: Device for which mdmon should start. + * + * Function waits for mdmon to start. It may need few seconds + * to start, we set timeout to 5, it should be sufficient. + * Do not wait if mdmon has been started. + * + * Return: MDADM_STATUS_SUCCESS if mdmon is running, error code otherwise. + */ +mdadm_status_t wait_for_mdmon(const char *devnm) +{ + const time_t mdmon_timeout = 5; + time_t start_time = time(0); + + if (mdmon_running(devnm)) + return MDADM_STATUS_SUCCESS; + + pr_info("Waiting for mdmon to start\n"); + while (time(0) - start_time < mdmon_timeout) { + sleep_for(0, MSEC_TO_NSEC(200), true); + if (mdmon_running(devnm)) + return MDADM_STATUS_SUCCESS; + }; + + pr_err("Timeout waiting for mdmon\n"); + return MDADM_STATUS_ERROR; +} + int start_mdmon(char *devnm) { int i; |