From f907ef185bc01d277086aeab2c10c4f2c818815e Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Fri, 16 Apr 2010 15:24:03 -0400 Subject: Refactor IncrementalNew into two distinct routines, one for whenever we might need to repartition a device, and one for when we will be using the block device directly. Signed-off-by: Doug Ledford --- Incremental.c | 158 +++++++++++++++++++++++++++++++++++++++------------------- mdadm.c | 4 +- mdadm.h | 2 +- 3 files changed, 110 insertions(+), 54 deletions(-) diff --git a/Incremental.c b/Incremental.c index 5fdf509..ad6be86 100644 --- a/Incremental.c +++ b/Incremental.c @@ -35,6 +35,10 @@ static int count_active(struct supertype *st, int mdfd, char **availp, static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra, int number, __u64 events, int verbose, char *array_name); +static int IncrementalNewPart(char *devname, int verbose, int export, + struct domain_ent *domain); +static int IncrementalNewDisk(char *devname, int verbose, int export, + struct domain_ent *domain); int Incremental(char *devname, int verbose, int runstop, struct supertype *st, char *homehost, int require_homehost, @@ -884,77 +888,129 @@ int IncrementalRemove(char *devname, int verbose) } /* - * IncrementalNewDisk - Check to see if the passed in device belongs to any - * DOMAIN entries from the config file, and if so, perform the required - * action. - * - * @devname - The device we are supposed to examine. This is a currently - * non-raid device, decide if we should claim it and if so, perform the - * required actions. - * - * Special note: Due to limitations of the whole hotplug model, any time we - * have a partitioned device, the bare drive will get called into this - * function because only the partitions will register as already being raid - * members, the bare drive itself won't. We need to be smart enough here - * so that even if we have a DOMAIN line that says partition, that we don't - * actually do the partitioning if the right partition table is already there. + * IncrementalNewPart - We have a partition or a whole disk device, and we + * have a domain that says not to partition the device, so we will either + * use the whole disk or the partition directly. */ -int IncrementalNewDisk(char *devname, int verbose, int export) +static int IncrementalNewPart(char *devname, int verbose, int export, + struct domain_ent *domain) { - struct stat stb; struct mdstat_ent *mdstat, *md; struct domain_ent *domain; int dfd; - domain = conf_get_domain(devname); - if (!domain) - return 0; - if (action(domain) <= incremental) - /* Nothing to do. We only get called in the case that there - * is no current superblock on the device in question, and - * since our matching domain says we should either ignore or - * use devices incrementally, they have to already have a - * superblock. Since we don't, we're done. - */ - return 0; - if (action(domain) != partition && - (mdstat = arrays_in_domain(devname, domain)) == NULL) { - /* As a technical design decision, we *must* have at least one - * array in our domain that we can add this device to or else - * we simply can't do anything with this device. - */ - printf("No arrays found in domain!\n"); - return 1; - } + mdstat = arrays_in_domain(devname, domain); + for (md = mdstat; md; md = md->next) + printf(Name ": %s\n", md->dev); /* We've finished with the easy tests that allow us to kick drives * out without touching actual physical media, now we need to start * the slower checks. */ - dfd = dev_open(devname, O_RDONLY|O_EXCL); - if (dfd < 0) { - fprintf(stderr, Name ": cannot open %s: %s.\n", - devname, strerror(errno)); + dfd = dev_open_check(devname, O_RDONLY|O_EXCL); + if (dfd < 0) return 1; - } - if (fstat(dfd, &stb) < 0) { - fprintf(stderr, Name ": fstat failed for %s: %s.\n", - devname, strerror(errno)); - close(dfd); - return 1; - } - if ((stb.st_mode & S_IFMT) != S_IFBLK) { - fprintf(stderr, Name ": %s is not a block device.\n", devname); + if (guess_super(dfd) != NULL) { + /* This won't happen with our udev rules, but someone might + * try this by hand, make them use normal incremental mode + * instead if the device has a superblock already */ + fprintf(stderr, Name ": superblock present on %s.\n", devname); close(dfd); return 1; } + /* + * OK, at this point we have a valid block device without a + * superblock. If we aren't in force mode, then don't use the + * device unless it's "clean", meaning no filesystems, no lvm, + * no anything. The requirement here is that both the first and + * last 4k of the device must be one of three patterns: 0x00, 0x5a, + * or 0xff. + */ + + return 0; +} + +/* + * IncrementalNewDisk - We have a whole disk device, and we have a domain + * that says to partition the disk. However, we will get called whether + * the partition is the correct partition or not, so we need to skip devs + * that already have the right partition and partition bare devs or + * repartition devs with stuff already on them only if the force option + * is present on our domain. + */ +static int IncrementalNewDisk(char *devname, int verbose, int export, + struct domain_ent *domain) +{ + struct mdstat_ent *mdstat, *md; + struct domain_ent *domain; + int dfd; + dfd = dev_open_check(devname, O_RDONLY|O_EXCL); + if (dfd < 0) + return 1; if (guess_super(dfd) != NULL) { + /* This won't happen with our udev rules, but someone might + * try this by hand, make them use normal incremental mode + * instead if the device has a superblock already */ fprintf(stderr, Name ": superblock present on %s.\n", devname); close(dfd); return 1; } + /* + * OK, at this point we have a valid block device without a + * superblock. If we aren't in force mode, then don't use the + * device unless it's "clean", meaning no filesystems, no lvm, + * no anything. The requirement here is that both the first and + * last 4k of the device must be one of three patterns: 0x00, 0x5a, + * or 0xff. + */ - for (md = mdstat; md; md = md->next) - printf(Name ": %s\n", md->dev); return 0; } + +/* + * IncrementalNew - We've got a device that doesn't appear to have any + * current existing raid superblock on it, check to see if we should be + * claiming it based on DOMAIN entries in the config file. + * + * @devname - The device to investigate + * + * Special note: if we have partitioned devices, the whole disk device is + * going to get called into this code, we need to detect that the device + * is already in use and leave it be, where as if we get a truly new + * device we may need to partition it and set it up for the partitions to + * be added to various arrays later on in the hot plug process. + */ +int IncrementalNew(char *devname, int verbose, int export) +{ + struct domain_ent *domain; + char *devpath; + int rv; + + domain = conf_get_domain(devname); + if (!domain) + return 0; + if (action(domain) <= incremental) + /* Nothing to do. We only get called in the case that there + * is no current superblock on the device in question, and + * since our matching domain says we should either ignore or + * use devices incrementally, they have to already have a + * superblock. Since we don't, we're done. + */ + return 0; + devpath = get_devpath_from_devname(devname); + if (strstr(devpath, "part") || action(domain) != partition) + /* We are on a partition, not a whole disk, or we are on a + * whole disk but we want to use the whole disk instead + * of partitioning it */ + rv = IncrementalNewPart(devname, verbose, export, domain); + else + /* Only use this if we are dealing with a disk that would + * need partitioned. This will get called even when our + * disk actually already belongs to all the right arrays + * and there is nothing to be done, so only do work here + * if we really need to */ + rv = IncrementalNewDisk(devname, verbose, export, domain); + free(devpath); + return rv; +} + diff --git a/mdadm.c b/mdadm.c index 35d1f7d..c6410aa 100644 --- a/mdadm.c +++ b/mdadm.c @@ -1563,8 +1563,8 @@ int main(int argc, char *argv[]) if (devmode == 'f') rv = IncrementalRemove(devlist->devname, verbose-quiet); else if (new_disk > 0) - rv = IncrementalNewDisk(devlist->devname, verbose-quiet, - export); + rv = IncrementalNew(devlist->devname, verbose-quiet, + export); else rv = Incremental(devlist->devname, verbose-quiet, runstop, ss, homehost, diff --git a/mdadm.h b/mdadm.h index 7c037ea..a11cfa8 100644 --- a/mdadm.h +++ b/mdadm.h @@ -874,7 +874,7 @@ extern int Incremental_container(struct supertype *st, char *devname, extern void RebuildMap(void); extern int IncrementalScan(int verbose); extern int IncrementalRemove(char *devname, int verbose); -extern int IncrementalNewDisk(char *devname, int verbose, int export); +extern int IncrementalNew(char *devname, int verbose, int export); extern int CreateBitmap(char *filename, int force, char uuid[16], unsigned long chunksize, unsigned long daemon_sleep, unsigned long write_behind, -- cgit