]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Move calls to SET_ARRAY_INFO to common helper.
authorNeilBrown <neilb@suse.de>
Thu, 18 Sep 2008 06:01:55 +0000 (16:01 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 18 Sep 2008 06:01:55 +0000 (16:01 +1000)
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 <neilb@suse.de>
Assemble.c
Create.c
Incremental.c
mdadm.h
super-ddf.c
super-intel.c
sysfs.c
util.c

index 1f41369a8512acb5bf1d18748337d184f1ba343b..65a679b650e1e7af29487c279f53161f51adbd7d 100644 (file)
@@ -140,6 +140,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        char *avail;
        int nextspare = 0;
 
        char *avail;
        int nextspare = 0;
 
+       memset(&info, 0, sizeof(info));
+
        if (get_linux_version() < 2004000)
                old_linux = 1;
 
        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);
                return 1;
        }
        st->ss->getinfo_super(st, &info);
+#ifndef MDASSEMBLE
+       sysfs_init(&info, mdfd, 0);
+#endif
        for (i=0; i<bestcnt; i++) {
                int j = best[i];
                unsigned int desired_state;
        for (i=0; i<bestcnt; i++) {
                int j = best[i];
                unsigned int desired_state;
@@ -844,36 +849,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
 
        /* Almost ready to actually *do* something */
        if (!old_linux) {
 
        /* Almost ready to actually *do* something */
        if (!old_linux) {
-               struct mdinfo *sra = NULL;
                int rv;
 
                int rv;
 
-#ifndef MDASSEMBLE
-               if (st->ss->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) {
                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;
                                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 */) {
                                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 "
 
                                if (rv) {
                                        fprintf(stderr, Name ": failed to add "
index 20886d119c868609e15dd52d1f8dc65c4dfb278a..652bc1c761cbdd7e9a30839f33f29000e7d95a32 100644 (file)
--- 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;
        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;
        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;
                return 1;
 
        total_slots = info.array.nr_disks;
+       sysfs_init(&info, mdfd, 0);
        st->ss->getinfo_super(st, &info);
 
        if (did_default && verbose >= 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;
                }
                        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) {
        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;
        }
                        mddev, strerror(errno));
                return 1;
        }
@@ -714,7 +694,7 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                                inf->errors = 0;
                                rv = 0;
 
                                inf->errors = 0;
                                rv = 0;
 
-                               rv = add_disk(mdfd, st, sra, inf);
+                               rv = add_disk(mdfd, st, &info, inf);
 
                                if (rv) {
                                        fprintf(stderr,
 
                                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:
                        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:
                                              "active");
                                need_mdmon = 0;
                                break;
                        default:
-                               sysfs_set_str(sra, NULL, "array_state",
+                               sysfs_set_str(&info, NULL, "array_state",
                                              "readonly");
                                break;
                        }
                                              "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, &param)) {
                } else {
                        mdu_param_t param;
                        if (ioctl(mdfd, RUN_ARRAY, &param)) {
index 209ef98207e3a430d3ab3d9f21156809d95b0c11..aa9eb88dbf8fb652fad2787dc6af0757f2acb901 100644 (file)
@@ -74,7 +74,7 @@ int Incremental(char *devname, int verbose, int runstop,
         *   start the array (auto-readonly).
         */
        struct stat stb;
         *   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;
        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);
        }
 
                                             autof);
        }
 
+       memset(&info, 0, sizeof(info));
        st->ss->getinfo_super(st, &info);
        /* 3/ Check if there is a match in mdadm.conf */
 
        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;
        }
                        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 */
        /* 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;
 
                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;
                }
                                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);
                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);
                        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;
                }
                        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
                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);
                        return 2;
                }
+               sysfs_free(sra);
        } else {
        /* 5b/ if it does */
        /* - check one drive in array to make sure metadata is a reasonably */
        } 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;
                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,
                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);
                        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 ||
                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) {
        }
 
        for (ra = list ; ra ; ra = ra->next) {
-               struct mdinfo *sra;
                struct mdinfo *dev;
                int devnum = -1;
                int mdfd;
                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;
                int usepart = 1;
                char *n;
                int working = 0;
-               char ver[100];
 
                if ((autof&7) == 3 || (autof&7) == 5)
                        usepart = 0;
 
                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;
                }
 
                        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)
                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) {
                                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:
                        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:
                                              "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))
                                              "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;
                        }
                                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);
                        if (verbose >= 0)
                                printf("Started %s with %d devices\n",
                                       chosen_name, working);
diff --git a/mdadm.h b/mdadm.h
index b123da2dd24503ef3c2bf6830da826edc342388a..a1bd77f2d6c6c6e76913555e302ab4d3704de929 100644 (file)
--- 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);
  * 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);
 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_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);
 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 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);
 
 extern char *human_size(long long bytes);
 char *human_size_brief(long long bytes);
index f7bdd2a04f8dddd1f7171fa48c088b162c0cb47a..70889dc388ee2be5973b2b5c8bb78b6ba7e76c01 100644 (file)
@@ -1248,6 +1248,8 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info)
 
        info->reshape_active = 0;
 
 
        info->reshape_active = 0;
 
+       info->array.major_version = -1;
+       info->array.minor_version = -2;
        strcpy(info->text_version, "ddf");
        info->safe_mode_delay = 0;
 
        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);
        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);
        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.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 +
                this->array.ctime         = DECADE +
                        __be32_to_cpu(*(__u32*)(vc->conf.guid+16));
                this->array.utime         = DECADE +
index 07539ca07ed19c522704f315995f94136c63c3c5..f5c6b09b93a5b464fa93319316130e3eaa2baf21 100644 (file)
@@ -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;
 
        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);
        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->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;
        strcpy(info->text_version, "imsm");
        info->safe_mode_delay = 0;
        info->disk.number = -1;
diff --git a/sysfs.c b/sysfs.c
index fdad790f06e2d1294e5ace28ca62462949a6767e..727e25085471f59563bfa2210370c78b70a3461d 100644 (file)
--- a/sysfs.c
+++ b/sysfs.c
@@ -74,6 +74,29 @@ int sysfs_open(int devnum, char *devname, char *attr)
        return fd;
 }
 
        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
 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 = 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);
 
        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);
 }
 
        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;
 {
        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 */
        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));
                            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;
 }
 
        return rv;
 }
 
diff --git a/util.c b/util.c
index 7469fca4111e0f0a577c4c36766d5b2333a54acc..b63251f4df166a29625981ecb5c021fca90b6459 100644 (file)
--- 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;
                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
                }
        } else
 #endif
@@ -1020,6 +1025,31 @@ int add_disk(int mdfd, struct supertype *st,
        return rv;
 }
 
        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];
 char *devnum2devname(int num)
 {
        char name[100];