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 <neilb@suse.de>
This commit is contained in:
NeilBrown 2008-09-18 16:01:55 +10:00
parent 7801ac2092
commit f35f252592
8 changed files with 153 additions and 144 deletions

View File

@ -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; 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) {
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;
@ -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 "

View File

@ -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 */
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");
/* 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, &param)) {

View File

@ -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);

View File

@ -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);

View File

@ -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 +

View 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;
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;

76
sysfs.c
View File

@ -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;
}

38
util.c
View File

@ -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];