From f656201188d73cdc2726265f1348f8ffbf7587be Mon Sep 17 00:00:00 2001 From: Mariusz Tkaczyk Date: Thu, 29 Feb 2024 12:52:06 +0100 Subject: [PATCH 22/41] mdadm: drop get_required_spare_criteria() Only IMSM implements get_spare_criteria, so load_super() in get_required_spare_criteria() is dead code. It is moved inside metadata handler, because only IMSM implements it. Give possibility to provide devnode to be opened. With that we can hide load_container() used only to fill spare criteria inside handler and simplify implementation in generic code. Add helper function for testing spare criteria in Incremental and error messages. File descriptor in get_spare_criteria_imsm() is always opened on purpose. New functionality added in next patches will require it. For the same reason, function is moved to other place. No functional changes. Signed-off-by: Mariusz Tkaczyk --- Incremental.c | 77 ++++++++++++++++++++++---------- Monitor.c | 35 +++------------ mdadm.h | 5 +-- super-intel.c | 120 +++++++++++++++++++++++++++++++++----------------- 4 files changed, 140 insertions(+), 97 deletions(-) diff --git a/Incremental.c b/Incremental.c index 2b5a5859..66c2cc86 100644 --- a/Incremental.c +++ b/Incremental.c @@ -833,6 +833,53 @@ container_members_max_degradation(struct map_ent *map, struct map_ent *me) return max_degraded; } +/** + * incremental_external_test_spare_criteria() - helper to test spare criteria. + * @st: supertype, must be not NULL, it is duplicated here. + * @container_devnm: devnm of the container. + * @disk_fd: file descriptor of device to tested. + * @verbose: verbose flag. + * + * The function is used on new drive verification path to check if it can be added to external + * container. To test spare criteria, metadata must be loaded. It duplicates super to not mess in + * original one. + * Function is executed if superblock supports get_spare_criteria(), otherwise success is returned. + */ +mdadm_status_t incremental_external_test_spare_criteria(struct supertype *st, char *container_devnm, + int disk_fd, int verbose) +{ + mdadm_status_t rv = MDADM_STATUS_ERROR; + char container_devname[PATH_MAX]; + struct spare_criteria sc = {0}; + struct supertype *dup; + + if (!st->ss->get_spare_criteria) + return MDADM_STATUS_SUCCESS; + + dup = dup_super(st); + snprintf(container_devname, PATH_MAX, "/dev/%s", container_devnm); + + if (dup->ss->get_spare_criteria(dup, container_devname, &sc) != 0) { + if (verbose > 1) + pr_err("Failed to get spare criteria for %s\n", container_devname); + goto out; + } + + if (!disk_fd_matches_criteria(disk_fd, &sc)) { + if (verbose > 1) + pr_err("Disk does not match spare criteria for %s\n", container_devname); + goto out; + } + + rv = MDADM_STATUS_SUCCESS; + +out: + dup->ss->free_super(dup); + free(dup); + + return rv; +} + static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, struct map_ent *target, int bare, struct supertype *st, int verbose) @@ -873,8 +920,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, struct supertype *st2; struct domainlist *dl = NULL; struct mdinfo *sra; - unsigned long long devsize, freesize = 0; - struct spare_criteria sc = {0}; + unsigned long long freesize = 0; if (is_subarray(mp->metadata)) continue; @@ -925,34 +971,19 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, if (sra->array.failed_disks == -1) sra->array.failed_disks = container_members_max_degradation(map, mp); - get_dev_size(dfd, NULL, &devsize); if (sra->component_size == 0) { - /* true for containers, here we must read superblock - * to obtain minimum spare size */ - struct supertype *st3 = dup_super(st2); - int mdfd = open_dev(mp->devnm); - if (mdfd < 0) { - free(st3); + /* true for containers */ + if (incremental_external_test_spare_criteria(st2, mp->devnm, dfd, verbose)) goto next; - } - if (st3->ss->load_container && - !st3->ss->load_container(st3, mdfd, mp->path)) { - if (st3->ss->get_spare_criteria) - st3->ss->get_spare_criteria(st3, &sc); - st3->ss->free_super(st3); - } - free(st3); - close(mdfd); } - if ((sra->component_size > 0 && - st2->ss->validate_geometry(st2, sra->array.level, sra->array.layout, + + if (sra->component_size > 0 && + st2->ss->validate_geometry(st2, sra->array.level, sra->array.layout, sra->array.raid_disks, &sra->array.chunk_size, sra->component_size, sra->devs ? sra->devs->data_offset : INVALID_SECTORS, devname, &freesize, sra->consistency_policy, - 0) && - freesize < sra->component_size) || - (sra->component_size == 0 && devsize < sc.min_size)) { + 0) && freesize < sra->component_size) { if (verbose > 1) pr_err("not adding %s to %s as it is too small\n", devname, mp->path); diff --git a/Monitor.c b/Monitor.c index 1ece8712..6b4560ae 100644 --- a/Monitor.c +++ b/Monitor.c @@ -1008,34 +1008,6 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) return new_found; } -static int get_required_spare_criteria(struct state *st, - struct spare_criteria *sc) -{ - int fd; - - if (!st->metadata || !st->metadata->ss->get_spare_criteria) { - sc->min_size = 0; - sc->sector_size = 0; - return 0; - } - - fd = open(st->devname, O_RDONLY); - if (fd < 0) - return 1; - if (st->metadata->ss->external) - st->metadata->ss->load_container(st->metadata, fd, st->devname); - else - st->metadata->ss->load_super(st->metadata, fd, st->devname); - close(fd); - if (!st->metadata->sb) - return 1; - - st->metadata->ss->get_spare_criteria(st->metadata, sc); - st->metadata->ss->free_super(st->metadata); - - return 0; -} - static int check_donor(struct state *from, struct state *to) { struct state *sub; @@ -1178,8 +1150,11 @@ static void try_spare_migration(struct state *statelist) /* member of a container */ to = to->parent; - if (get_required_spare_criteria(to, &sc)) - continue; + if (to->metadata->ss->get_spare_criteria) + if (to->metadata->ss->get_spare_criteria(to->metadata, to->devname, + &sc)) + continue; + if (to->metadata->ss->external) { /* We must make sure there is * no suitable spare in container already. diff --git a/mdadm.h b/mdadm.h index e8abd730..cbc586f5 100644 --- a/mdadm.h +++ b/mdadm.h @@ -1116,10 +1116,9 @@ extern struct superswitch { * Return spare criteria for array: * - minimum disk size can be used in array; * - sector size can be used in array. - * Return values: 0 - for success and -EINVAL on error. */ - int (*get_spare_criteria)(struct supertype *st, - struct spare_criteria *sc); + mdadm_status_t (*get_spare_criteria)(struct supertype *st, char *mddev_path, + struct spare_criteria *sc); /* Find somewhere to put a bitmap - possibly auto-size it - and * update the metadata to record this. The array may be newly * created, in which case data_size may be updated, or it might diff --git a/super-intel.c b/super-intel.c index 39ec4754..7ad391ac 100644 --- a/super-intel.c +++ b/super-intel.c @@ -1736,46 +1736,6 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super) return (remainder < rv) ? remainder : rv; } -/* - * Return minimum size of a spare and sector size - * that can be used in this array - */ -int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c) -{ - struct intel_super *super = st->sb; - struct dl *dl; - struct extent *e; - int i; - unsigned long long size = 0; - - if (!super) - return -EINVAL; - /* find first active disk in array */ - dl = super->disks; - while (dl && (is_failed(&dl->disk) || dl->index == -1)) - dl = dl->next; - if (!dl) - return -EINVAL; - /* find last lba used by subarrays */ - e = get_extents(super, dl, 0); - if (!e) - return -EINVAL; - for (i = 0; e[i].size; i++) - continue; - if (i > 0) - size = e[i-1].start + e[i-1].size; - free(e); - - /* add the amount of space needed for metadata */ - size += imsm_min_reserved_sectors(super); - - c->min_size = size * 512; - c->sector_size = super->sector_size; - c->criteria_set = true; - - return 0; -} - static bool is_gen_migration(struct imsm_dev *dev); #define IMSM_4K_DIV 8 @@ -11295,6 +11255,84 @@ static const char *imsm_get_disk_controller_domain(const char *path) return drv; } +/** + * get_spare_criteria_imsm() - set spare criteria. + * @st: supertype. + * @mddev_path: path to md device devnode, it must be container. + * @c: spare_criteria struct to fill, not NULL. + * + * If superblock is not loaded, use mddev_path to load_container. It must be given in this case. + * Filles size and sector size accordingly to superblock. + */ +mdadm_status_t get_spare_criteria_imsm(struct supertype *st, char *mddev_path, + struct spare_criteria *c) +{ + mdadm_status_t ret = MDADM_STATUS_ERROR; + bool free_superblock = false; + unsigned long long size = 0; + struct intel_super *super; + struct extent *e; + struct dl *dl; + int i; + + /* If no superblock and no mddev_path, we cannot load superblock. */ + assert(st->sb || mddev_path); + + if (mddev_path) { + int fd = open(mddev_path, O_RDONLY); + + if (!is_fd_valid(fd)) + return MDADM_STATUS_ERROR; + + if (!st->sb) { + if (load_container_imsm(st, fd, st->devnm)) { + close(fd); + return MDADM_STATUS_ERROR; + } + free_superblock = true; + } + close(fd); + } + + super = st->sb; + + /* find first active disk in array */ + dl = super->disks; + while (dl && (is_failed(&dl->disk) || dl->index == -1)) + dl = dl->next; + + if (!dl) + goto out; + + /* find last lba used by subarrays */ + e = get_extents(super, dl, 0); + if (!e) + goto out; + + for (i = 0; e[i].size; i++) + continue; + if (i > 0) + size = e[i - 1].start + e[i - 1].size; + free(e); + + /* add the amount of space needed for metadata */ + size += imsm_min_reserved_sectors(super); + + c->min_size = size * 512; + c->sector_size = super->sector_size; + c->criteria_set = true; + ret = MDADM_STATUS_SUCCESS; + +out: + if (free_superblock) + free_super_imsm(st); + + if (ret != MDADM_STATUS_SUCCESS) + c->criteria_set = false; + + return ret; +} + static char *imsm_find_array_devnm_by_subdev(int subdev, char *container) { static char devnm[32]; @@ -11425,7 +11463,7 @@ static struct mdinfo *get_spares_for_grow(struct supertype *st) { struct spare_criteria sc; - get_spare_criteria_imsm(st, &sc); + get_spare_criteria_imsm(st, NULL, &sc); return container_choose_spares(st, &sc, NULL, NULL, NULL, 0); } -- 2.40.1