summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2008-04-28 16:29:37 +1000
committerNeil Brown <neilb@suse.de>2008-04-28 16:29:37 +1000
commit7a3be72fc621b4a7589e923cf0652c51493f831a (patch)
treec2e88676f5be4205eab54fe9b71c43ec442b0ffd
parent2cdb64897d4fe33a11af13c6356dcd338c561e77 (diff)
downloadmdadm-7a3be72fc621b4a7589e923cf0652c51493f831a.tar.gz
mdadm-7a3be72fc621b4a7589e923cf0652c51493f831a.tar.xz
mdadm-7a3be72fc621b4a7589e923cf0652c51493f831a.zip
Fix problems with array.size overflowing on large arrays.
array.size is 32bits and counts K. So for arrays with more than 4Terrabytes, it can overflow. The correct number can be read from sysfs, but there are still a few places that use array.size and risk truncation. What is worse. they compare a number of kilobytes with a number of sectors !! So use get_component_size() to read the sysfs information, and be more consistent about units.
-rw-r--r--ChangeLog2
-rw-r--r--Detail.c2
-rw-r--r--Manage.c13
3 files changed, 14 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index fdf720d..fd42b4e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,8 @@
Changes Prior to this release
- Avoid segfault when parsing /proc/mdstat with auto-read-only
arrays.
+ - Fix problem with failing to add devices to v.large (>4TB) arrays,
+ cause by problems with device-size overflow.
Changes Prior to 2.6.4 release
- Make "--create --auto=mdp" work for non-standard device names.
diff --git a/Detail.c b/Detail.c
index de1f409..6199d26 100644
--- a/Detail.c
+++ b/Detail.c
@@ -191,7 +191,7 @@ int Detail(char *dev, int brief, int export, int test, char *homehost)
if (dsize > 0)
printf(" Used Dev Size : %llu%s\n",
dsize,
- human_size((long long)array.size<<10));
+ human_size((long long)dsize<<10));
else
printf(" Used Dev Size : unknown\n");
} else
diff --git a/Manage.c b/Manage.c
index f17105a..1fb8468 100644
--- a/Manage.c
+++ b/Manage.c
@@ -188,6 +188,7 @@ int Manage_subdevs(char *devname, int fd,
*/
mdu_array_info_t array;
mdu_disk_info_t disc;
+ unsigned long long array_size;
mddev_dev_t dv, next = NULL;
struct stat stb;
int j, jnext = 0;
@@ -202,6 +203,14 @@ int Manage_subdevs(char *devname, int fd,
return 1;
}
+ /* array.size is only 32 bit and may be truncated.
+ * So read from sysfs if possible, and record number of sectors
+ */
+
+ array_size = get_component_size(fd);
+ if (array_size <= 0)
+ array_size = array.size * 2;
+
tst = super_by_fd(fd);
if (!tst) {
fprintf(stderr, Name ": unsupport array - version %d.%d\n",
@@ -337,7 +346,7 @@ int Manage_subdevs(char *devname, int fd,
/* Make sure device is large enough */
if (tst->ss->avail_size(tst, ldsize/512) <
- array.size) {
+ array_size) {
fprintf(stderr, Name ": %s not large enough to join array\n",
dv->devname);
return 1;
@@ -412,7 +421,7 @@ int Manage_subdevs(char *devname, int fd,
/* non-persistent. Must ensure that new drive
* is at least array.size big.
*/
- if (ldsize/512 < array.size) {
+ if (ldsize/512 < array_size) {
fprintf(stderr, Name ": %s not large enough to join array\n",
dv->devname);
return 1;