char *avail;
int nextspare = 0;
+ memset(&info, 0, sizeof(info));
+
if (get_linux_version() < 2004000)
old_linux = 1;
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;
/* Almost ready to actually *do* something */
if (!old_linux) {
- struct mdinfo *sra = NULL;
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) {
- 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;
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 "
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;
return 1;
total_slots = info.array.nr_disks;
+ sysfs_init(&info, mdfd, 0);
st->ss->getinfo_super(st, &info);
if (did_default && verbose >= 0) {
}
- 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;
}
inf->errors = 0;
rv = 0;
- rv = add_disk(mdfd, st, sra, inf);
+ rv = add_disk(mdfd, st, &info, inf);
if (rv) {
fprintf(stderr,
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)) {
* 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;
autof);
}
+ memset(&info, 0, sizeof(info));
st->ss->getinfo_super(st, &info);
/* 3/ Check if there is a match in mdadm.conf */
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
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 */
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,
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 ||
}
for (ra = list ; ra ; ra = ra->next) {
- struct mdinfo *sra;
struct mdinfo *dev;
int devnum = -1;
int mdfd;
int usepart = 1;
char *n;
int working = 0;
- char ver[100];
if ((autof&7) == 3 || (autof&7) == 5)
usepart = 0;
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) {
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))
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);
* 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 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 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);
info->reshape_active = 0;
+ info->array.major_version = -1;
+ info->array.minor_version = -2;
strcpy(info->text_version, "ddf");
info->safe_mode_delay = 0;
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);
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 +
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);
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;
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
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);
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;
}
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
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];