summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2007-12-14 20:14:38 +1100
committerNeil Brown <neilb@suse.de>2007-12-14 20:14:38 +1100
commit1686dc25ecf60a9b7691d73fc2b5a7e08184c940 (patch)
tree828cbf76ac4e341c9c50fb9e2a90efcdefd5e76b
parent3da92f272d017b1817b13f37f41c1ed4d6117291 (diff)
downloadmdadm-1686dc25ecf60a9b7691d73fc2b5a7e08184c940.tar.gz
mdadm-1686dc25ecf60a9b7691d73fc2b5a7e08184c940.tar.xz
mdadm-1686dc25ecf60a9b7691d73fc2b5a7e08184c940.zip
Find super from fd on an array.
We used to use the major/minor numbers, but that isn't sufficient any more, so pass the fd, and possibly check 'text' version.
-rw-r--r--Detail.c2
-rw-r--r--Grow.c8
-rw-r--r--Manage.c6
-rw-r--r--mdadm.h2
-rw-r--r--util.c56
5 files changed, 53 insertions, 21 deletions
diff --git a/Detail.c b/Detail.c
index 2bde9fa..5a408ec 100644
--- a/Detail.c
+++ b/Detail.c
@@ -88,7 +88,7 @@ int Detail(char *dev, int brief, int export, int test, char *homehost)
close(fd);
return rv;
}
- st = super_by_version(array.major_version, array.minor_version);
+ st = super_by_fd(fd);
if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode))
stb.st_rdev = 0;
diff --git a/Grow.c b/Grow.c
index e07e2c0..3c22741 100644
--- a/Grow.c
+++ b/Grow.c
@@ -58,7 +58,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
return 1;
}
- st = super_by_version(info.array.major_version, info.array.minor_version);
+ st = super_by_fd(fd);
if (!st) {
fprintf(stderr, Name ": cannot handle arrays with superblock version %d\n", info.array.major_version);
return 1;
@@ -277,7 +277,7 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
bitmapsize = bitmapsize * array.raid_disks / ncopies;
}
- st = super_by_version(array.major_version, array.minor_version);
+ st = super_by_fd(fd);
if (!st) {
fprintf(stderr, Name ": Cannot understand version %d.%d\n",
array.major_version, array.minor_version);
@@ -519,8 +519,8 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
case 4:
case 5:
case 6:
- st = super_by_version(array.major_version,
- array.minor_version);
+ st = super_by_fd(fd);
+
/* size can be changed independently.
* layout/chunksize/raid_disks/level can be changed
* though the kernel may not support it all.
diff --git a/Manage.c b/Manage.c
index 09d397b..f17105a 100644
--- a/Manage.c
+++ b/Manage.c
@@ -202,8 +202,7 @@ int Manage_subdevs(char *devname, int fd,
return 1;
}
- tst = super_by_version(array.major_version,
- array.minor_version);
+ tst = super_by_fd(fd);
if (!tst) {
fprintf(stderr, Name ": unsupport array - version %d.%d\n",
array.major_version, array.minor_version);
@@ -308,8 +307,7 @@ int Manage_subdevs(char *devname, int fd,
}
remove_partitions(tfd);
- st = super_by_version(array.major_version,
- array.minor_version);
+ st = dup_super(tst);
if (array.not_persistent==0)
st->ss->load_super(st, tfd, NULL);
diff --git a/mdadm.h b/mdadm.h
index 0156e37..a001e9f 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -381,7 +381,7 @@ struct supertype {
void *sb;
};
-extern struct supertype *super_by_version(int vers, int minor);
+extern struct supertype *super_by_fd(int fd);
extern struct supertype *guess_super(int fd);
extern struct supertype *dup_super(struct supertype *st);
extern int get_dev_size(int fd, char *dname, unsigned long long *sizep);
diff --git a/util.c b/util.c
index 811627e..732bc1c 100644
--- a/util.c
+++ b/util.c
@@ -723,29 +723,63 @@ int dev_open(char *dev, int flags)
struct superswitch *superlist[] = { &super0, &super1, NULL };
-struct supertype *super_by_version(int vers, int minor)
+struct supertype *super_by_fd(int fd)
{
- struct supertype *st = malloc(sizeof(*st));
- if (!st) return st;
- if (vers == 0) {
- st->ss = &super0;
- st->max_devs = MD_SB_DISKS;
+ mdu_array_info_t array;
+ int vers;
+ int minor;
+ struct supertype *st = NULL;
+ struct sysarray *sra;
+ char *verstr = NULL;
+ char version[20];
+ int i;
+
+ sra = sysfs_read(fd, 0, GET_VERSION);
+
+ if (sra) {
+ vers = sra->major_version;
+ minor = sra->minor_version;
+ } else {
+ if (ioctl(fd, GET_ARRAY_INFO, &array))
+ array.major_version = array.minor_version = 0;
+ vers = array.major_version;
+ minor = array.minor_version;
}
- if (vers == 1) {
- st->ss = &super1;
- st->max_devs = 384;
+ if (vers != -1) {
+ sprintf(version, "%d.%d", vers, minor);
+ verstr = version;
}
- st->minor_version = minor;
+ for (i = 0; st == NULL && superlist[i] ; i++)
+ st = superlist[i]->match_metadata_desc(verstr);
+
+ if (sra)
+ sysfs_free(sra);
st->sb = NULL;
return st;
}
struct supertype *dup_super(struct supertype *st)
{
+ struct supertype *stnew = NULL;
+ char *verstr = NULL;
+ char version[20];
+ int i;
+
if (!st)
return st;
- return super_by_version(st->ss->major, st->minor_version);
+
+ if (st->minor_version == -1)
+ sprintf(version, "%d", st->ss->major);
+ else
+ sprintf(version, "%d.%d", st->ss->major, st->minor_version);
+ verstr = version;
+
+ for (i = 0; stnew == NULL && superlist[i] ; i++)
+ stnew = superlist[i]->match_metadata_desc(verstr);
+
+ stnew->sb = NULL;
+ return stnew;
}
struct supertype *guess_super(int fd)