diff --git a/Assemble.c b/Assemble.c index c7563ab2..fa5ad07e 100644 --- a/Assemble.c +++ b/Assemble.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "xmalloc.h" #include @@ -120,7 +121,7 @@ static int is_member_busy(char *metadata_version) continue; /* Skip first char - it can be '/' or '-' */ - if (strcmp(&ent->metadata_version[10], metadata_version + 1) == 0) { + if (strcmp(&ent->metadata_version[MD_VER_EXT_LEN + 1], metadata_version + 1) == 0) { busy = 1; break; } diff --git a/Detail.c b/Detail.c index 108e9ba8..d9924b03 100644 --- a/Detail.c +++ b/Detail.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "xmalloc.h" #include @@ -683,10 +684,10 @@ int Detail(char *dev, struct context *c) de->d_name); if (load_sys(path, vbuf, sizeof(vbuf)) < 0) continue; - if (strncmp(vbuf, "external:", 9) || - !is_subarray(vbuf + 9) || - strncmp(vbuf + 10, sra->sys_name, nlen) || - vbuf[10 + nlen] != '/') + if (strncmp(vbuf, MD_VER_EXT, MD_VER_EXT_LEN) || + !is_subarray(vbuf + MD_VER_EXT_LEN) || + strncmp(vbuf + MD_VER_EXT_LEN + 1, sra->sys_name, nlen) || + vbuf[MD_VER_EXT_LEN + 1 + nlen] != '/') continue; devid = devnm2devid(de->d_name); printf(" %s", diff --git a/Grow.c b/Grow.c index 083b1c26..f28abfee 100644 --- a/Grow.c +++ b/Grow.c @@ -22,6 +22,7 @@ * Email: */ #include "mdadm.h" +#include "mdstat.h" #include "dlink.h" #include "xmalloc.h" @@ -696,7 +697,7 @@ static int check_idle(struct supertype *st) if (!is_container_member(e, container)) continue; /* frozen array is not idle*/ - if (e->percent >= 0 || e->metadata_version[9] == '-') { + if (e->percent >= 0 || e->metadata_version[MD_VER_BLOCKED_IDX] == '-') { is_idle = 0; break; } diff --git a/Incremental.c b/Incremental.c index f717c9c3..8b748041 100644 --- a/Incremental.c +++ b/Incremental.c @@ -29,6 +29,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "xmalloc.h" #include "udev.h" diff --git a/Kill.c b/Kill.c index 9f05a1ac..b41896c5 100644 --- a/Kill.c +++ b/Kill.c @@ -26,6 +26,7 @@ */ #include "mdadm.h" +#include "mdstat.h" int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) { diff --git a/Manage.c b/Manage.c index b53e65e9..539c05e8 100644 --- a/Manage.c +++ b/Manage.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "udev.h" #include "xmalloc.h" @@ -48,12 +49,12 @@ int Manage_ro(char *devname, int fd, int readonly) mdi->array.major_version == -1 && is_subarray(mdi->text_version)) { char vers[64]; - strcpy(vers, "external:"); + strcpy(vers, MD_VER_EXT); strcat(vers, mdi->text_version); if (readonly > 0) { int rv; /* We set readonly ourselves. */ - vers[9] = '-'; + vers[MD_VER_BLOCKED_IDX] = '-'; sysfs_set_str(mdi, NULL, "metadata_version", vers); close_fd(&fd); @@ -63,7 +64,7 @@ int Manage_ro(char *devname, int fd, int readonly) pr_err("failed to set readonly for %s: %s\n", devname, strerror(errno)); - vers[9] = mdi->text_version[0]; + vers[MD_VER_BLOCKED_IDX] = mdi->text_version[0]; sysfs_set_str(mdi, NULL, "metadata_version", vers); rv = 1; goto out; @@ -71,13 +72,13 @@ int Manage_ro(char *devname, int fd, int readonly) } else { char *cp; /* We cannot set read/write - must signal mdmon */ - vers[9] = '/'; + vers[MD_VER_BLOCKED_IDX] = '/'; sysfs_set_str(mdi, NULL, "metadata_version", vers); - cp = strchr(vers+10, '/'); + cp = strchr(vers + MD_VER_BLOCKED_IDX + 1, '/'); if (cp) *cp = 0; - ping_monitor(vers+10); + ping_monitor(vers + MD_VER_BLOCKED_IDX + 1); if (mdi->array.level <= 0) sysfs_set_str(mdi, NULL, "array_state", "active"); } @@ -278,7 +279,8 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) mds = mdstat_read(0, 0); for (m = mds; m; m = m->next) if (is_mdstat_ent_external(m) && - metadata_container_matches(m->metadata_version + 9, devnm)) { + metadata_container_matches(m->metadata_version + MD_VER_EXT_LEN, + devnm)) { if (verbose >= 0) pr_err("Cannot stop container %s: member %s still active\n", devname, m->devnm); diff --git a/config.c b/config.c index 373acd48..71f5718c 100644 --- a/config.c +++ b/config.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "dlink.h" #include "xmalloc.h" diff --git a/managemon.c b/managemon.c index 74b64bfc..cdeadf3a 100644 --- a/managemon.c +++ b/managemon.c @@ -103,6 +103,7 @@ #define _GNU_SOURCE #endif #include "mdadm.h" +#include "mdstat.h" #include "mdmon.h" #include "xmalloc.h" diff --git a/mapfile.c b/mapfile.c index 33d40d9e..981a1aa9 100644 --- a/mapfile.c +++ b/mapfile.c @@ -43,6 +43,7 @@ * at compile time via MAP_DIR and MAP_FILE. */ #include "mdadm.h" +#include "mdstat.h" #include "xmalloc.h" #include diff --git a/md_common.h b/md_common.h new file mode 100644 index 00000000..7e0c5d7d --- /dev/null +++ b/md_common.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * md_common - constants shared between md driver abstractions. + */ + +#ifndef MD_COMMON_H +#define MD_COMMON_H + +/* + * Prefix used by the md driver version to mark an externally-managed array or + * container. The full form is: + * + * "external:" [/-] containername [/subarray] + * + * The '/' or '-' separator distinguishes normal read-write arrays from those + * that mdmon must not reconfigure (read-only, reshaping, etc.). + */ +#define MD_EXT "external" /* The external keyword used in various contexts */ + +#define MD_VER_EXT "external:" /* The "external:" version const prefix */ +#define MD_VER_EXT_LEN (sizeof(MD_VER_EXT) - 1) /* Length of external prefix */ + +/* Index of the character that blocks the version. + * It is the one after the prefix so the array index is MD_VER_EXT_LEN + */ +#define MD_VER_BLOCKED_IDX (MD_VER_EXT_LEN) + +#endif diff --git a/mdadm.c b/mdadm.c index b3b66cdb..81e8c0a3 100644 --- a/mdadm.c +++ b/mdadm.c @@ -26,6 +26,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "md_p.h" #include "xmalloc.h" diff --git a/mdadm.h b/mdadm.h index 78f498a7..f2cbbe8a 100644 --- a/mdadm.h +++ b/mdadm.h @@ -684,36 +684,6 @@ typedef struct mapping { int num; } mapping_t; -struct mdstat_ent { - char devnm[32]; - int active; - char *level; - char *pattern; /* U for up, _ for down */ - int percent; /* -1 if no resync */ - int resync; /* 3 if check, 2 if reshape, 1 if resync, 0 if recovery */ - int devcnt; - int raid_disks; - char * metadata_version; - struct dev_member { - char *name; - struct dev_member *next; - } *members; - struct mdstat_ent *next; -}; - -extern struct mdstat_ent *mdstat_read(int hold, int start); -extern void mdstat_close(void); -extern void free_mdstat(struct mdstat_ent *ms); -extern int mdstat_wait(int seconds); -extern void mdstat_wait_fd(int fd, const sigset_t *sigmask); -extern int mddev_busy(char *devnm); -extern struct mdstat_ent *mdstat_by_component(char *name); -extern struct mdstat_ent *mdstat_find_by_member_name(struct mdstat_ent *mdstat, char *member_devnm); -extern struct mdstat_ent *mdstat_by_subdev(char *subdev, char *container); - -extern bool is_mdstat_ent_external(struct mdstat_ent *ent); -extern bool is_mdstat_ent_subarray(struct mdstat_ent *ent); - struct map_ent { struct map_ent *next; char devnm[32]; @@ -1727,8 +1697,6 @@ extern int is_mddev(char *dev); extern int open_container(int fd); extern int metadata_container_matches(char *metadata, char *devnm); extern int metadata_subdev_matches(char *metadata, char *devnm); -extern bool is_container_member(struct mdstat_ent *ent, char *devname); -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); @@ -1823,11 +1791,6 @@ static inline int is_subarray(char *vers) return (*vers == '/' || *vers == '-'); } -static inline char *to_subarray(struct mdstat_ent *ent, char *container) -{ - return &ent->metadata_version[10+strlen(container)+1]; -} - /** * signal_s() - Wrapper for sigaction() with signal()-like interface. * @sig: The signal to set the signal handler to. diff --git a/mdmon.c b/mdmon.c index 302d0248..037602ab 100644 --- a/mdmon.c +++ b/mdmon.c @@ -64,6 +64,7 @@ #endif #include "mdadm.h" +#include "mdstat.h" #include "mdmon.h" #include "xmalloc.h" diff --git a/mdmon.h b/mdmon.h index 37f5841a..a68499b1 100644 --- a/mdmon.h +++ b/mdmon.h @@ -84,9 +84,6 @@ void do_manager(struct supertype *container); extern volatile sig_atomic_t sigterm; int read_dev_state(int fd); -bool is_container_member(struct mdstat_ent *mdstat, char *container); - -struct mdstat_ent *mdstat_read(int hold, int start); extern int exit_now, manager_ready; extern int mon_tid, mgr_tid; diff --git a/mdmonitor.c b/mdmonitor.c index 314dafb4..b06fa46a 100644 --- a/mdmonitor.c +++ b/mdmonitor.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "udev.h" #include "xmalloc.h" @@ -892,7 +893,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, if (is_mdstat_ent_subarray(mse)) { char *sl; - snprintf(st->parent_devnm, MD_NAME_MAX, "%s", mse->metadata_version + 10); + snprintf(st->parent_devnm, MD_NAME_MAX, "%s", + mse->metadata_version + MD_VER_EXT_LEN + 1); sl = strchr(st->parent_devnm, '/'); if (sl) *sl = 0; @@ -1005,7 +1007,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) char *sl; snprintf(st->parent_devnm, MD_NAME_MAX, "%s", - mse->metadata_version + 10); + mse->metadata_version + MD_VER_EXT_LEN + 1); sl = strchr(st->parent_devnm, '/'); if (sl) *sl = 0; @@ -1306,8 +1308,8 @@ int Wait(char *dev) } if (!e || e->percent == RESYNC_NONE) { if (e && is_mdstat_ent_external(e)) { - if (is_subarray(&e->metadata_version[9])) - ping_monitor(&e->metadata_version[9]); + if (is_subarray(&e->metadata_version[MD_VER_EXT_LEN])) + ping_monitor(&e->metadata_version[MD_VER_EXT_LEN]); else ping_monitor(devnm); } diff --git a/mdopen.c b/mdopen.c index 9af0284b..e196aa80 100644 --- a/mdopen.c +++ b/mdopen.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "udev.h" #include "md_p.h" #include "xmalloc.h" diff --git a/mdstat.c b/mdstat.c index 8d97a2fc..f7f89ea8 100644 --- a/mdstat.c +++ b/mdstat.c @@ -79,6 +79,7 @@ */ #include "mdadm.h" +#include "mdstat.h" #include "dlink.h" #include "xmalloc.h" @@ -155,14 +156,14 @@ bool is_mdstat_ent_external(struct mdstat_ent *ent) if (!ent->metadata_version) return false; - if (strncmp(ent->metadata_version, "external:", 9) == 0) + if (strncmp(ent->metadata_version, MD_VER_EXT, MD_VER_EXT_LEN) == 0) return true; return false; } bool is_mdstat_ent_subarray(struct mdstat_ent *ent) { - if (is_mdstat_ent_external(ent) && is_subarray(ent->metadata_version + 9)) + if (is_mdstat_ent_external(ent) && is_subarray(ent->metadata_version + MD_VER_EXT_LEN)) return true; return false; } @@ -170,12 +171,27 @@ bool is_mdstat_ent_subarray(struct mdstat_ent *ent) bool is_container_member(struct mdstat_ent *mdstat, char *container) { if (is_mdstat_ent_external(mdstat) && - metadata_container_matches(mdstat->metadata_version + 9, container)) + metadata_container_matches(mdstat->metadata_version + MD_VER_EXT_LEN, container)) return true; return false; } +int is_subarray_active(char *subarray, char *container) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + struct mdstat_ent *ent; + + for (ent = mdstat; ent; ent = ent->next) + if (is_container_member(ent, container)) + if (strcmp(to_subarray(ent, container), subarray) == 0) + break; + + free_mdstat(mdstat); + + return ent != NULL; +} + static int mdstat_fd = -1; struct mdstat_ent *mdstat_read(int hold, int start) { @@ -493,9 +509,9 @@ struct mdstat_ent *mdstat_by_subdev(char *subdev, char *container) if (!is_mdstat_ent_external(ent)) continue; - if (!metadata_container_matches(ent->metadata_version + 9, container)) + if (!metadata_container_matches(ent->metadata_version + MD_VER_EXT_LEN, container)) continue; - if (!metadata_subdev_matches(ent->metadata_version + 9, subdev)) + if (!metadata_subdev_matches(ent->metadata_version + MD_VER_EXT_LEN, subdev)) continue; break; diff --git a/mdstat.h b/mdstat.h new file mode 100644 index 00000000..227a68b2 --- /dev/null +++ b/mdstat.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef MDSTAT_H +#define MDSTAT_H + +#include +#include +#include + +#include "md_common.h" + +struct mdstat_ent { + char devnm[32]; + + char *metadata_version; + int raid_disks; + char *pattern; /* U for up, _ for down */ + char *level; + int percent; /* -1 if no resync */ + int active; + int resync; /* 3 if check, 2 if reshape, 1 if resync, 0 if recovery */ + int devcnt; + + struct dev_member { + char *name; + struct dev_member *next; + } *members; + struct mdstat_ent *next; +}; + +struct mdstat_ent *mdstat_find_by_member_name(struct mdstat_ent *mdstat, char *member_devnm); +struct mdstat_ent *mdstat_by_subdev(char *subdev, char *container); +struct mdstat_ent *mdstat_by_component(char *name); +struct mdstat_ent *mdstat_read(int hold, int start); + +void free_mdstat(struct mdstat_ent *ms); +void mdstat_close(void); + +void mdstat_wait_fd(int fd, const sigset_t *sigmask); +int mdstat_wait(int seconds); +int mddev_busy(char *devnm); + +bool is_mdstat_ent_external(struct mdstat_ent *ent); +bool is_mdstat_ent_subarray(struct mdstat_ent *ent); +bool is_container_member(struct mdstat_ent *ent, char *devname); + +int is_subarray_active(char *subarray, char *container); + +static inline char *to_subarray(struct mdstat_ent *ent, char *container) +{ + /* Skip: "external:" prefix, [/-] separator, container name, '/'. */ + return &ent->metadata_version[MD_VER_EXT_LEN + 1 + strlen(container) + 1]; +} + +#endif diff --git a/msg.c b/msg.c index 0cc7fc5d..19e59186 100644 --- a/msg.c +++ b/msg.c @@ -29,6 +29,7 @@ #include #include #include "mdadm.h" +#include "mdstat.h" #include "mdmon.h" #include "xmalloc.h" @@ -251,7 +252,7 @@ int unblock_subarray(struct mdinfo *sra, const int unfreeze) int rc = 0; if (sra) { - sprintf(buf, "external:%s\n", sra->text_version); + sprintf(buf, MD_VER_EXT "%s\n", sra->text_version); buf[9] = '/'; } else buf[9] = '-'; @@ -270,7 +271,7 @@ int block_subarray(struct mdinfo *sra) char buf[64]; int rc = 0; - sprintf(buf, "external:%s\n", sra->text_version); + sprintf(buf, MD_VER_EXT "%s\n", sra->text_version); buf[9] = '-'; if (sysfs_set_str(sra, NULL, "metadata_version", buf)) rc = -1; diff --git a/super-intel.c b/super-intel.c index c158a271..dd268d23 100644 --- a/super-intel.c +++ b/super-intel.c @@ -19,6 +19,7 @@ #define HAVE_STDINT_H 1 #include "mdadm.h" +#include "mdstat.h" #include "mdmon.h" #include "dlink.h" #include "drive_encryption.h" @@ -7082,8 +7083,9 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist, int found; for (memb = mdstat ; memb ; memb = memb->next) { - if (is_mdstat_ent_external(memb) && !is_subarray(memb->metadata_version + 9) && - strcmp(&memb->metadata_version[9], name) == 0 && memb->members) { + if (is_mdstat_ent_external(memb) && + !is_subarray(memb->metadata_version + MD_VER_EXT_LEN) && + strcmp(&memb->metadata_version[MD_VER_EXT_LEN], name) == 0 && memb->members) { struct dev_member *dev = memb->members; int fd = -1; @@ -13190,7 +13192,7 @@ static int set_bitmap_sysfs(struct mdinfo *info, unsigned long long chunksize, * related to the device's first lba (in opposition to the "internal" case * when this value is related to the beginning of the superblock). */ - if (sysfs_set_str(info, NULL, "bitmap/metadata", "external")) { + if (sysfs_set_str(info, NULL, "bitmap/metadata", MD_EXT)) { dprintf("failed to set bitmap/metadata\n"); return -1; } diff --git a/sysfs.c b/sysfs.c index 7589e944..96bfd5a7 100644 --- a/sysfs.c +++ b/sysfs.c @@ -24,6 +24,7 @@ */ #include "mdadm.h" +#include "md_common.h" #include "dlink.h" #include "xmalloc.h" @@ -293,10 +294,10 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options) sra->array.major_version = sra->array.minor_version = -1; strcpy(sra->text_version, ""); - } else if (strncmp(buf, "external:", 9) == 0) { + } else if (strncmp(buf, MD_VER_EXT, MD_VER_EXT_LEN) == 0) { sra->array.major_version = -1; sra->array.minor_version = -2; - strcpy(sra->text_version, buf+9); + strcpy(sra->text_version, buf + MD_VER_EXT_LEN); sra->text_version[sizeof(sra->text_version) - 1] = '\0'; } else { sscanf(buf, "%d.%d", @@ -809,7 +810,7 @@ int sysfs_set_array(struct mdinfo *info) info->array.minor_version == -2) { char buf[SYSFS_MAX_BUF_SIZE]; - strcat(strcpy(ver, "external:"), info->text_version); + strcat(strcpy(ver, MD_VER_EXT), info->text_version); /* meta version might already be set if we are setting * new geometry for a reshape. In that case we don't @@ -819,8 +820,9 @@ int sysfs_set_array(struct mdinfo *info) */ if (sysfs_get_str(info, NULL, "metadata_version", buf, sizeof(buf)) > 0) - if (strlen(buf) >= 9 && buf[9] == '-') - ver[9] = '-'; + if (strlen(buf) >= MD_VER_BLOCKED_IDX && + buf[MD_VER_BLOCKED_IDX] == '-') + ver[MD_VER_BLOCKED_IDX] = '-'; if (sysfs_set_str(info, NULL, "metadata_version", ver) < 0) { pr_err("This kernel does not support external metadata.\n"); diff --git a/util.c b/util.c index cdc55435..3bd4829a 100644 --- a/util.c +++ b/util.c @@ -23,6 +23,7 @@ */ #include "mdadm.h" +#include "md_common.h" #include "md_p.h" #include "xmalloc.h" @@ -1559,7 +1560,7 @@ int open_container(int fd) if (n <= 0 || (unsigned)n >= sizeof(buf)) continue; buf[n] = 0; - if (strncmp(buf, "external", 8) != 0 || + if (strncmp(buf, MD_EXT, strlen(MD_EXT)) != 0 || n < 10 || buf[9] == '/') continue; @@ -1635,21 +1636,6 @@ int metadata_subdev_matches(char *metadata, char *devnm) return 0; } -int is_subarray_active(char *subarray, char *container) -{ - struct mdstat_ent *mdstat = mdstat_read(0, 0); - struct mdstat_ent *ent; - - for (ent = mdstat; ent; ent = ent->next) - if (is_container_member(ent, container)) - if (strcmp(to_subarray(ent, container), subarray) == 0) - break; - - free_mdstat(mdstat); - - return ent != NULL; -} - /* open_subarray - opens a subarray in a container * @dev: container device name * @st: empty supertype