From f35f25259279573c6274e2783536c0b0a399bdd4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 18 Sep 2008 16:01:55 +1000 Subject: [PATCH] Move calls to SET_ARRAY_INFO to common helper. When we assemble an array, there are three different approaches depending on whether metadata is internal or external, and on kernel version. Move all this to a common helper instead of duplicating in 3 places. Signed-off-by: NeilBrown --- Assemble.c | 36 +++++--------------- Create.c | 92 ++++++++++++++++++++------------------------------- Incremental.c | 42 +++++++++-------------- mdadm.h | 5 +-- super-ddf.c | 6 ++++ super-intel.c | 4 +++ sysfs.c | 78 ++++++++++++++++++++++++++----------------- util.c | 38 ++++++++++++++++++--- 8 files changed, 155 insertions(+), 146 deletions(-) diff --git a/Assemble.c b/Assemble.c index 1f41369a..65a679b6 100644 --- a/Assemble.c +++ b/Assemble.c @@ -140,6 +140,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, char *avail; int nextspare = 0; + memset(&info, 0, sizeof(info)); + if (get_linux_version() < 2004000) old_linux = 1; @@ -736,6 +738,9 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, return 1; } st->ss->getinfo_super(st, &info); +#ifndef MDASSEMBLE + sysfs_init(&info, mdfd, 0); +#endif for (i=0; iss->external) { - char ver[100]; - strcat(strcpy(ver, "external:"), info.text_version); - sra = sysfs_read(mdfd, 0, 0); - if ((vers % 100) < 2 || - sra == NULL || - sysfs_set_str(sra, NULL, "metadata_version", - ver) < 0) { - fprintf(stderr, Name ": This kernel does not " - "support external metadata.\n"); - return 1; - } - rv = sysfs_set_array(sra, &info); - } else -#endif - if ((vers % 100) >= 1) { /* can use different versions */ - mdu_array_info_t inf; - memset(&inf, 0, sizeof(inf)); - inf.major_version = info.array.major_version; - inf.minor_version = info.array.minor_version; - rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); - } else - rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); - + rv = set_array_info(mdfd, st, &info); if (rv) { - fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", + fprintf(stderr, Name ": failed to set array info for %s: %s\n", mddev, strerror(errno)); if (must_close) close(mdfd); return 1; @@ -913,7 +893,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, j = chosen_drive; if (j >= 0 /* && devices[j].uptodate */) { - rv = add_disk(mdfd, st, sra, &devices[j].i); + rv = add_disk(mdfd, st, &info, &devices[j].i); if (rv) { fprintf(stderr, Name ": failed to add " diff --git a/Create.c b/Create.c index 20886d11..652bc1c7 100644 --- a/Create.c +++ b/Create.c @@ -75,7 +75,6 @@ int Create(struct supertype *st, char *mddev, int mdfd, int container_fd = -1; int need_mdmon = 0; unsigned long long bitmapsize; - struct mdinfo *sra; struct mdinfo info, *infos; int did_default = 0; unsigned long safe_mode_delay = 0; @@ -521,6 +520,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, return 1; total_slots = info.array.nr_disks; + sysfs_init(&info, mdfd, 0); st->ss->getinfo_super(st, &info); if (did_default && verbose >= 0) { @@ -568,61 +568,41 @@ int Create(struct supertype *st, char *mddev, int mdfd, } - sra = sysfs_read(mdfd, 0, 0); + sysfs_init(&info, mdfd, 0); - if (st->ss->external) { - char ver[100]; - strcat(strcpy(ver, "external:"), - info.text_version); - if (st->ss->external && st->subarray[0]) { - /* member */ - - /* When creating a member, we need to be careful - * to negotiate with mdmon properly. - * If it is already running, we cannot write to - * the devices and must ask it to do that part. - * If it isn't running, we write to the devices, - * and then start it. - * We hold an exclusive open on the container - * device to make sure mdmon doesn't exit after - * we checked that it is running. - * - * For now, fail if it is already running. - */ - container_fd = open_dev_excl(st->container_dev); - if (container_fd < 0) { - fprintf(stderr, Name ": Cannot get exclusive " - "open on container - weird.\n"); - return 1; - } - if (mdmon_running(st->container_dev)) { - if (verbose) - fprintf(stderr, Name ": reusing mdmon " - "for %s.\n", - devnum2devname(st->container_dev)); - st->update_tail = &st->updates; - } else - need_mdmon = 1; - } - if ((vers % 100) < 2 || - sra == NULL || - sysfs_set_str(sra, NULL, "metadata_version", - ver) < 0) { - fprintf(stderr, Name ": This kernel does not " - "support external metadata.\n"); + if (st->ss->external && st->subarray[0]) { + /* member */ + + /* When creating a member, we need to be careful + * to negotiate with mdmon properly. + * If it is already running, we cannot write to + * the devices and must ask it to do that part. + * If it isn't running, we write to the devices, + * and then start it. + * We hold an exclusive open on the container + * device to make sure mdmon doesn't exit after + * we checked that it is running. + * + * For now, fail if it is already running. + */ + container_fd = open_dev_excl(st->container_dev); + if (container_fd < 0) { + fprintf(stderr, Name ": Cannot get exclusive " + "open on container - weird.\n"); return 1; } - rv = sysfs_set_array(sra, &info); - } else if ((vers % 100) >= 1) { /* can use different versions */ - mdu_array_info_t inf; - memset(&inf, 0, sizeof(inf)); - inf.major_version = info.array.major_version; - inf.minor_version = info.array.minor_version; - rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); - } else - rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); + if (mdmon_running(st->container_dev)) { + if (verbose) + fprintf(stderr, Name ": reusing mdmon " + "for %s.\n", + devnum2devname(st->container_dev)); + st->update_tail = &st->updates; + } else + need_mdmon = 1; + } + rv = set_array_info(mdfd, st, &info); if (rv) { - fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", + fprintf(stderr, Name ": failed to set array info for %s: %s\n", mddev, strerror(errno)); return 1; } @@ -714,7 +694,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, inf->errors = 0; rv = 0; - rv = add_disk(mdfd, st, sra, inf); + rv = add_disk(mdfd, st, &info, inf); if (rv) { fprintf(stderr, @@ -746,16 +726,16 @@ int Create(struct supertype *st, char *mddev, int mdfd, case LEVEL_LINEAR: case LEVEL_MULTIPATH: case 0: - sysfs_set_str(sra, NULL, "array_state", + sysfs_set_str(&info, NULL, "array_state", "active"); need_mdmon = 0; break; default: - sysfs_set_str(sra, NULL, "array_state", + sysfs_set_str(&info, NULL, "array_state", "readonly"); break; } - sysfs_set_safemode(sra, safe_mode_delay); + sysfs_set_safemode(&info, safe_mode_delay); } else { mdu_param_t param; if (ioctl(mdfd, RUN_ARRAY, ¶m)) { diff --git a/Incremental.c b/Incremental.c index 209ef982..aa9eb88d 100644 --- a/Incremental.c +++ b/Incremental.c @@ -74,7 +74,7 @@ int Incremental(char *devname, int verbose, int runstop, * start the array (auto-readonly). */ struct stat stb; - struct mdinfo info, info2; + struct mdinfo info; struct mddev_ident_s *array_list, *match; char chosen_name[1024]; int rv; @@ -150,6 +150,7 @@ int Incremental(char *devname, int verbose, int runstop, autof); } + memset(&info, 0, sizeof(info)); st->ss->getinfo_super(st, &info); /* 3/ Check if there is a match in mdadm.conf */ @@ -292,40 +293,32 @@ int Incremental(char *devname, int verbose, int runstop, chosen_name, strerror(errno)); return 2; } + sysfs_init(&info, mdfd, 0); + /* 5/ Find out if array already exists */ if (! mddev_busy(devnum)) { /* 5a/ if it does not */ /* - choose a name, from mdadm.conf or 'name' field in array. */ /* - create the array */ /* - add the device */ - mdu_array_info_t ainf; struct mdinfo *sra; - memset(&ainf, 0, sizeof(ainf)); - ainf.major_version = info.array.major_version; - ainf.minor_version = info.array.minor_version; - if (ioctl(mdfd, SET_ARRAY_INFO, &ainf) != 0) { - fprintf(stderr, Name - ": SET_ARRAY_INFO failed for %s: %s\b", + if (set_array_info(mdfd, st, &info) != 0) { + fprintf(stderr, Name ": failed to set array info for %s: %s\n", chosen_name, strerror(errno)); close(mdfd); return 2; } - sra = sysfs_read(mdfd, devnum, GET_VERSION); - sysfs_set_str(sra, NULL, "metadata_version", info.text_version); - st->ss->getinfo_super(st, &info); info.disk.major = major(stb.st_rdev); info.disk.minor = minor(stb.st_rdev); - if (add_disk(mdfd, st, sra, &info) != 0) { + if (add_disk(mdfd, st, &info, &info) != 0) { fprintf(stderr, Name ": failed to add %s to %s: %s.\n", devname, chosen_name, strerror(errno)); ioctl(mdfd, STOP_ARRAY, 0); close(mdfd); - sysfs_free(sra); return 2; } - sysfs_free(sra); sra = sysfs_read(mdfd, devnum, GET_DEVS); if (!sra || !sra->devs || sra->devs->disk.raid_disk >= 0) { /* It really should be 'none' - must be old buggy @@ -340,6 +333,7 @@ int Incremental(char *devname, int verbose, int runstop, sysfs_free(sra); return 2; } + sysfs_free(sra); } else { /* 5b/ if it does */ /* - check one drive in array to make sure metadata is a reasonably */ @@ -350,6 +344,7 @@ int Incremental(char *devname, int verbose, int runstop, int err; struct mdinfo *sra; struct supertype *st2; + struct mdinfo info2; sra = sysfs_read(mdfd, devnum, (GET_DEVS | GET_STATE)); sprintf(dn, "%d:%d", sra->devs->disk.major, @@ -367,6 +362,7 @@ int Incremental(char *devname, int verbose, int runstop, return 2; } close(dfd2); + memset(&info2, 0, sizeof(info2)); st2->ss->getinfo_super(st2, &info2); st2->ss->free_super(st2); if (info.array.level != info2.array.level || @@ -751,7 +747,6 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, } for (ra = list ; ra ; ra = ra->next) { - struct mdinfo *sra; struct mdinfo *dev; int devnum = -1; int mdfd; @@ -759,7 +754,6 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, int usepart = 1; char *n; int working = 0; - char ver[100]; if ((autof&7) == 3 || (autof&7) == 5) usepart = 0; @@ -813,14 +807,10 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, return 2; } - sra = sysfs_read(mdfd, 0, 0); - - sprintf(ver, "external:%s", ra->text_version); - sysfs_set_str(sra, NULL, "metadata_version", ver); - - sysfs_set_array(sra, ra); + sysfs_init(ra, mdfd, 0); + sysfs_set_array(ra, md_get_version(mdfd)); for (dev = ra->devs; dev; dev = dev->next) - if (sysfs_add_disk(sra, dev) == 0) + if (sysfs_add_disk(ra, dev) == 0) working++; if (runstop > 0 || working >= ra->array.working_disks) { @@ -828,11 +818,11 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, case LEVEL_LINEAR: case LEVEL_MULTIPATH: case 0: - sysfs_set_str(sra, NULL, "array_state", + sysfs_set_str(ra, NULL, "array_state", "active"); break; default: - sysfs_set_str(sra, NULL, "array_state", + sysfs_set_str(ra, NULL, "array_state", "readonly"); /* start mdmon if needed. */ if (!mdmon_running(st->container_dev)) @@ -840,7 +830,7 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, ping_monitor(devnum2devname(st->container_dev)); break; } - sysfs_set_safemode(sra, ra->safe_mode_delay); + sysfs_set_safemode(ra, ra->safe_mode_delay); if (verbose >= 0) printf("Started %s with %d devices\n", chosen_name, working); diff --git a/mdadm.h b/mdadm.h index b123da2d..a1bd77f2 100644 --- a/mdadm.h +++ b/mdadm.h @@ -340,6 +340,7 @@ extern void map_add(struct map_ent **melp, * else use devnum. >=0 -> major9. <0..... */ extern int sysfs_open(int devnum, char *devname, char *attr); +extern void sysfs_init(struct mdinfo *mdi, int fd, int devnum); extern void sysfs_free(struct mdinfo *sra); extern struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options); extern int sysfs_attr_match(const char *attr, const char *str); @@ -351,8 +352,7 @@ extern int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev, extern int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev, char *name, unsigned long long *val); extern int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms); -extern int sysfs_set_array(struct mdinfo *sra, - struct mdinfo *info); +extern int sysfs_set_array(struct mdinfo *info, int vers); extern int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd); extern int sysfs_disk_to_scsi_id(int fd, __u32 *id); extern int sysfs_unique_holder(int devnum, long rdev); @@ -769,6 +769,7 @@ extern void append_metadata_update(struct supertype *st, void *buf, int len); extern int add_disk(int mdfd, struct supertype *st, struct mdinfo *sra, struct mdinfo *info); +extern int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info); extern char *human_size(long long bytes); char *human_size_brief(long long bytes); diff --git a/super-ddf.c b/super-ddf.c index f7bdd2a0..70889dc3 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -1248,6 +1248,8 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) info->reshape_active = 0; + info->array.major_version = -1; + info->array.minor_version = -2; strcpy(info->text_version, "ddf"); info->safe_mode_delay = 0; @@ -1303,6 +1305,8 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) uuid_from_super_ddf(st, info->uuid); info->container_member = atoi(st->subarray); + info->array.major_version = -1; + info->array.minor_version = -2; sprintf(info->text_version, "/%s/%s", devnum2devname(st->container_dev), st->subarray); @@ -2591,6 +2595,8 @@ static struct mdinfo *container_content_ddf(struct supertype *st) this->array.layout = rlq_to_layout(vc->conf.rlq, vc->conf.prl, this->array.raid_disks); this->array.md_minor = -1; + this->array.major_version = -1; + this->array.minor_version = -2; this->array.ctime = DECADE + __be32_to_cpu(*(__u32*)(vc->conf.guid+16)); this->array.utime = DECADE + diff --git a/super-intel.c b/super-intel.c index 07539ca0..f5c6b09b 100644 --- a/super-intel.c +++ b/super-intel.c @@ -667,6 +667,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info) strncpy(info->name, (char *) dev->volume, MAX_RAID_SERIAL_LEN); info->name[MAX_RAID_SERIAL_LEN] = 0; + info->array.major_version = -1; + info->array.minor_version = -2; sprintf(info->text_version, "/%s/%d", devnum2devname(st->container_dev), info->container_member); @@ -700,6 +702,8 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info) info->disk.minor = 0; info->disk.raid_disk = -1; info->reshape_active = 0; + info->array.major_version = -1; + info->array.minor_version = -2; strcpy(info->text_version, "imsm"); info->safe_mode_delay = 0; info->disk.number = -1; diff --git a/sysfs.c b/sysfs.c index fdad790f..727e2508 100644 --- a/sysfs.c +++ b/sysfs.c @@ -74,6 +74,29 @@ int sysfs_open(int devnum, char *devname, char *attr) return fd; } +void sysfs_init(struct mdinfo *mdi, int fd, int devnum) +{ + if (fd >= 0) { + struct stat stb; + mdu_version_t vers; + if (fstat(fd, &stb)) + return; + if (ioctl(fd, RAID_VERSION, &vers) != 0) + return; + if (major(stb.st_rdev)==9) + sprintf(mdi->sys_name, "md%d", (int)minor(stb.st_rdev)); + else + sprintf(mdi->sys_name, "md_d%d", + (int)minor(stb.st_rdev)>>MdpMinorShift); + } else { + if (devnum >= 0) + sprintf(mdi->sys_name, "md%d", devnum); + else + sprintf(mdi->sys_name, "md_d%d", + -1-devnum); + } +} + struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) { /* Longest possible name in sysfs, mounted at /sys, is @@ -93,26 +116,9 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options) sra = malloc(sizeof(*sra)); if (sra == NULL) return sra; - sra->next = NULL; + memset(sra, 0, sizeof(*sra)); + sysfs_init(sra, fd, devnum); - if (fd >= 0) { - struct stat stb; - mdu_version_t vers; - if (fstat(fd, &stb)) return NULL; - if (ioctl(fd, RAID_VERSION, &vers) != 0) - return NULL; - if (major(stb.st_rdev)==9) - sprintf(sra->sys_name, "md%d", (int)minor(stb.st_rdev)); - else - sprintf(sra->sys_name, "md_d%d", - (int)minor(stb.st_rdev)>>MdpMinorShift); - } else { - if (devnum >= 0) - sprintf(sra->sys_name, "md%d", devnum); - else - sprintf(sra->sys_name, "md_d%d", - -1-devnum); - } sprintf(fname, "/sys/block/%s/md/", sra->sys_name); base = fname + strlen(fname); @@ -433,22 +439,34 @@ int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms) return sysfs_set_str(sra, NULL, "safe_mode_delay", delay); } -int sysfs_set_array(struct mdinfo *sra, - struct mdinfo *info) +int sysfs_set_array(struct mdinfo *info, int vers) { int rv = 0; - sra->array = info->array; - + char ver[100]; + + ver[0] = 0; + if (info->array.major_version == -1 && + info->array.minor_version == -2) { + strcat(strcpy(ver, "external:"), info->text_version); + + if ((vers % 100) < 2 || + sysfs_set_str(info, NULL, "metadata_version", + ver) < 0) { + fprintf(stderr, Name ": This kernel does not " + "support external metadata.\n"); + return 1; + } + } if (info->array.level < 0) return 0; /* FIXME */ - rv |= sysfs_set_str(sra, NULL, "level", + rv |= sysfs_set_str(info, NULL, "level", map_num(pers, info->array.level)); - rv |= sysfs_set_num(sra, NULL, "raid_disks", info->array.raid_disks); - rv |= sysfs_set_num(sra, NULL, "chunk_size", info->array.chunk_size); - rv |= sysfs_set_num(sra, NULL, "layout", info->array.layout); - rv |= sysfs_set_num(sra, NULL, "component_size", info->component_size/2); - rv |= sysfs_set_num(sra, NULL, "resync_start", info->resync_start); - sra->array = info->array; + rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks); + rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size); + rv |= sysfs_set_num(info, NULL, "layout", info->array.layout); + rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2); + if (info->array.level > 0) + rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start); return rv; } diff --git a/util.c b/util.c index 7469fca4..b63251f4 100644 --- a/util.c +++ b/util.c @@ -1009,10 +1009,15 @@ int add_disk(int mdfd, struct supertype *st, rv = sysfs_add_disk(sra, info); if (! rv) { struct mdinfo *sd2; - sd2 = malloc(sizeof(*sd2)); - *sd2 = *info; - sd2->next = sra->devs; - sra->devs = sd2; + for (sd2 = sra->devs; sd2; sd2=sd2->next) + if (sd2 == info) + break; + if (sd2 == NULL) { + sd2 = malloc(sizeof(*sd2)); + *sd2 = *info; + sd2->next = sra->devs; + sra->devs = sd2; + } } } else #endif @@ -1020,6 +1025,31 @@ int add_disk(int mdfd, struct supertype *st, return rv; } +int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info) +{ + /* Initialise kernel's knowledge of array. + * This varies between externally managed arrays + * and older kernels + */ + int vers = md_get_version(mdfd); + int rv; + +#ifndef MDASSEMBLE + if (st->ss->external) + rv = sysfs_set_array(info, vers); + else +#endif + if ((vers % 100) >= 1) { /* can use different versions */ + mdu_array_info_t inf; + memset(&inf, 0, sizeof(inf)); + inf.major_version = info->array.major_version; + inf.minor_version = info->array.minor_version; + rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); + } else + rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); + return rv; +} + char *devnum2devname(int num) { char name[100]; -- 2.39.2