tags 385951 + patch thanks On Mon, Sep 04, 2006 at 10:41:16AM +0200, martin f krafft wrote: > Neil, this one looks like a bug, not sure how to fix it though. > Maybe prevent scanning /dev/hdX if you are also scanning /dev/hdXY ?
The attached patch does just that -- if it finds hda1 right after hda (and the major numbers match), it simply kills hda, as it can't contain both a partition table _and_ an MD superblock. The parsing might be a bit cursory, but I've verified the assumptions done against the kernel, so I'm quite sure it shouldn't break. I haven't got a setup that breaks like the submitter, but it does indeed remove hda from the scanning in my test. Klaus Ethgen wrote: >> This is a very critical bug and should be fixed in etch (I think, this >> is release critical!!!) FWIW, I'm not the maintainer, but I do not really think this warrants the critical severity; the setup is quite rare and easily worked around (just specify the devices manually in mdadm.conf). /* Steinar */ -- Homepage: http://www.sesse.net/
diff -ur mdadm-2.5.3.git200608202239/config.c mdadm-2.5.3.git200608202239.patched/config.c --- mdadm-2.5.3.git200608202239/config.c 2006-08-21 01:27:43.000000000 +0200 +++ mdadm-2.5.3.git200608202239.patched/config.c 2006-09-13 02:33:18.000000000 +0200 @@ -222,7 +222,8 @@ mddev_dev_t load_partitions(void) { FILE *f = fopen("/proc/partitions", "r"); - char buf[1024]; + char buf[1024], last_device_name[1024]; + int last_major = -1; mddev_dev_t rv = NULL; if (f == NULL) { fprintf(stderr, Name ": cannot open /proc/partitions\n"); @@ -230,7 +231,7 @@ } while (fgets(buf, 1024, f)) { int major, minor; - char *name, *mp; + char *name, *kernel_name, *mp, *ptr; mddev_dev_t d; buf[1023] = '\0'; @@ -244,6 +245,46 @@ name = map_dev(major, minor, 1); if (!name) continue; + + /* + * We want the name exactly as it comes from + * /proc/partitions; this makes sure we do not get + * confused by weird LVM names and the like. + */ + kernel_name = buf + 22; /* will be safe until we reach 10TB */ + while (isdigit(*kernel_name) || isspace(*kernel_name)) { /* just to be sure */ + ++kernel_name; + } + + /* Chop the trailing newline. */ + ptr = strchr(kernel_name, '\n'); + if (ptr) + *ptr = '\0'; + + /* + * Check if this could be a partition of the previous device + * (the disk _always_ comes just before the first partition, cf. + * /usr/src/linux/fs/partitions/check.c) + */ + if (major == last_major && strlen(kernel_name) > strlen(last_device_name) && + strncmp(kernel_name, last_device_name, strlen(last_device_name)) == 0 && + isdigit(kernel_name[strlen(kernel_name) - 1])) { + /* + * The previous device has a partition table, so delete + * it so it isn't scanned for a superblock. This makes + * sure we don't get confused when a partition with an + * md superblock lives very close to the end of a + * disk. + */ + d = rv->next; + free(rv->devname); + free(rv); + rv = d; + } + + last_major = major; + strcpy(last_device_name, kernel_name); + d = malloc(sizeof(*d)); d->devname = strdup(name); d->next = rv;