From 95425a89fc31ea0e98f536ef0b8616a0ec317af2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 18 Oct 2012 15:31:20 +1100 Subject: [PATCH] Assemble: split out select_devices function. Assemble() is way too big. This patch starts cleaning it up by pulling the 'select_devices()' function. This examines the device to make sure they all belong to one array, or select those that do (depending on exact use case). Signed-off-by: NeilBrown --- Assemble.c | 324 ++++++++++++++++++++++++++++------------------------- 1 file changed, 173 insertions(+), 151 deletions(-) diff --git a/Assemble.c b/Assemble.c index a1e2791..2f1d2de 100644 --- a/Assemble.c +++ b/Assemble.c @@ -129,145 +129,20 @@ static int ident_matches(struct mddev_ident *ident, return 1; } -int Assemble(struct supertype *st, char *mddev, - struct mddev_ident *ident, - struct mddev_dev *devlist, - struct context *c) +static int select_devices(struct mddev_dev *devlist, + struct mddev_ident *ident, + struct supertype **stp, + struct mdinfo **contentp, + struct context *c, + int inargv, int auto_assem) + { - /* - * The task of Assemble is to find a collection of - * devices that should (according to their superblocks) - * form an array, and to give this collection to the MD driver. - * In Linux-2.4 and later, this involves submitting a - * SET_ARRAY_INFO ioctl with no arg - to prepare - * the array - and then submit a number of - * ADD_NEW_DISK ioctls to add disks into - * the array. Finally RUN_ARRAY might - * be submitted to start the array. - * - * Much of the work of Assemble is in finding and/or - * checking the disks to make sure they look right. - * - * If mddev is not set, then scan must be set and we - * read through the config file for dev+uuid mapping - * We recurse, setting mddev, for each device that - * - isn't running - * - has a valid uuid (or any uuid if !uuidset) - * - * If mddev is set, we try to determine state of md. - * check version - must be at least 0.90.0 - * check kernel version. must be at least 2.4. - * If not, we can possibly fall back on START_ARRAY - * Try to GET_ARRAY_INFO. - * If possible, give up - * If not, try to STOP_ARRAY just to make sure - * - * If !uuidset and scan, look in conf-file for uuid - * If not found, give up - * If !devlist and scan and uuidset, get list of devs from conf-file - * - * For each device: - * Check superblock - discard if bad - * Check uuid (set if we don't have one) - discard if no match - * Check superblock similarity if we have a superblock - discard if different - * Record events, devicenum - * This should give us a list of devices for the array - * We should collect the most recent event number - * - * Count disks with recent enough event count - * While force && !enough disks - * Choose newest rejected disks, update event count - * mark clean and rewrite superblock - * If recent kernel: - * SET_ARRAY_INFO - * foreach device with recent events : ADD_NEW_DISK - * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY - * If old kernel: - * Check the device numbers in superblock are right - * update superblock if any changes - * START_ARRAY - * - */ - int mdfd; - int clean; - int auto_assem = (mddev == NULL && !ident->uuid_set && - ident->super_minor == UnSet && ident->name[0] == 0 - && (ident->container == NULL || ident->member == NULL)); - int old_linux = 0; - int vers = vers; /* Keep gcc quite - it really is initialised */ - struct { - char *devname; - int uptodate; /* set once we decide that this device is as - * recent as everything else in the array. - */ - int included; /* set if the device is already in the array - * due to a previous '-I' - */ - struct mdinfo i; - } *devices; - char *devmap; - int *best = NULL; /* indexed by raid_disk */ - int bestcnt = 0; - int devcnt = 0; - unsigned int okcnt, sparecnt, rebuilding_cnt; - unsigned int req_cnt; - int i; - int most_recent = 0; - int chosen_drive; - int change = 0; - int inargv = 0; - int report_missmatch; -#ifndef MDASSEMBLE - int bitmap_done; -#endif - int start_partial_ok = (c->runstop >= 0) && - (c->force || devlist==NULL || auto_assem); - unsigned int num_devs; struct mddev_dev *tmpdev; - struct mdinfo info; + int num_devs; + struct supertype *st = *stp; struct mdinfo *content = NULL; - struct mdinfo *pre_exist = NULL; - char *avail; - int nextspare = 0; - char *name = NULL; - char chosen_name[1024]; + int report_missmatch = ((inargv && c->verbose >= 0) || c->verbose > 0); struct domainlist *domains = NULL; - struct map_ent *map = NULL; - struct map_ent *mp; - - if (get_linux_version() < 2004000) - old_linux = 1; - - /* - * If any subdevs are listed, then any that don't - * match ident are discarded. Remainder must all match and - * become the array. - * If no subdevs, then we scan all devices in the config file, but - * there must be something in the identity - */ - - if (!devlist && - ident->uuid_set == 0 && - (ident->super_minor < 0 || ident->super_minor == UnSet) && - ident->name[0] == 0 && - (ident->container == NULL || ident->member == NULL) && - ident->devices == NULL) { - pr_err("No identity information available for %s - cannot assemble.\n", - mddev ? mddev : "further assembly"); - return 1; - } - - if (devlist == NULL) - devlist = conf_get_devs(); - else if (mddev) - inargv = 1; - - report_missmatch = ((inargv && c->verbose >= 0) || c->verbose > 0); - try_again: - /* We come back here when doing auto-assembly and attempting some - * set of devices failed. Those are now marked as ->used==2 and - * we ignore them and try again - */ tmpdev = devlist; num_devs = 0; while (tmpdev) { @@ -279,12 +154,6 @@ int Assemble(struct supertype *st, char *mddev, tmpdev = tmpdev->next; } - if (!st && ident->st) st = ident->st; - - if (c->verbose>0) - pr_err("looking for devices for %s\n", - mddev ? mddev : "further assembly"); - /* first walk the list of devices to find a consistent set * that match the criterea, if that is possible. * We flag the ones we like with 'used'. @@ -299,7 +168,8 @@ int Assemble(struct supertype *st, char *mddev, struct dev_policy *pol = NULL; int found_container = 0; - if (tmpdev->used > 1) continue; + if (tmpdev->used > 1) + continue; if (ident->devices && !match_oneof(ident->devices, devname)) { @@ -400,7 +270,7 @@ int Assemble(struct supertype *st, char *mddev, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); - return 1; + return -1; } if (found_container) { @@ -431,7 +301,7 @@ int Assemble(struct supertype *st, char *mddev, /* we have a uuid */ int uuid[4]; - content = &info; + content = *contentp; tst->ss->getinfo_super(tst, content, NULL); if (!parse_uuid(ident->container, uuid) || @@ -483,7 +353,7 @@ int Assemble(struct supertype *st, char *mddev, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); - return 1; + return -1; } if (c->verbose > 0) pr_err("found match on member %s in %s\n", @@ -494,7 +364,7 @@ int Assemble(struct supertype *st, char *mddev, goto loop; } else { - content = &info; + content = *contentp; tst->ss->getinfo_super(tst, content, NULL); if (!ident_matches(ident, content, tst, @@ -570,7 +440,7 @@ int Assemble(struct supertype *st, char *mddev, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); - return 1; + return -1; } tmpdev->used = 1; } @@ -596,7 +466,7 @@ int Assemble(struct supertype *st, char *mddev, if (tmpdev->used != 3) continue; tmpdev->used = 1; - content = &info; + content = *contentp; if (!st->sb) { /* we need sb from one of the spares */ @@ -636,13 +506,165 @@ int Assemble(struct supertype *st, char *mddev, } } domain_free(domains); + *stp = st; + if (st && st->sb && content == *contentp) + st->ss->getinfo_super(st, content, NULL); + *contentp = content; + + return num_devs; +} + +int Assemble(struct supertype *st, char *mddev, + struct mddev_ident *ident, + struct mddev_dev *devlist, + struct context *c) +{ + /* + * The task of Assemble is to find a collection of + * devices that should (according to their superblocks) + * form an array, and to give this collection to the MD driver. + * In Linux-2.4 and later, this involves submitting a + * SET_ARRAY_INFO ioctl with no arg - to prepare + * the array - and then submit a number of + * ADD_NEW_DISK ioctls to add disks into + * the array. Finally RUN_ARRAY might + * be submitted to start the array. + * + * Much of the work of Assemble is in finding and/or + * checking the disks to make sure they look right. + * + * If mddev is not set, then scan must be set and we + * read through the config file for dev+uuid mapping + * We recurse, setting mddev, for each device that + * - isn't running + * - has a valid uuid (or any uuid if !uuidset) + * + * If mddev is set, we try to determine state of md. + * check version - must be at least 0.90.0 + * check kernel version. must be at least 2.4. + * If not, we can possibly fall back on START_ARRAY + * Try to GET_ARRAY_INFO. + * If possible, give up + * If not, try to STOP_ARRAY just to make sure + * + * If !uuidset and scan, look in conf-file for uuid + * If not found, give up + * If !devlist and scan and uuidset, get list of devs from conf-file + * + * For each device: + * Check superblock - discard if bad + * Check uuid (set if we don't have one) - discard if no match + * Check superblock similarity if we have a superblock - discard if different + * Record events, devicenum + * This should give us a list of devices for the array + * We should collect the most recent event number + * + * Count disks with recent enough event count + * While force && !enough disks + * Choose newest rejected disks, update event count + * mark clean and rewrite superblock + * If recent kernel: + * SET_ARRAY_INFO + * foreach device with recent events : ADD_NEW_DISK + * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY + * If old kernel: + * Check the device numbers in superblock are right + * update superblock if any changes + * START_ARRAY + * + */ + int mdfd; + int clean; + int auto_assem = (mddev == NULL && !ident->uuid_set && + ident->super_minor == UnSet && ident->name[0] == 0 + && (ident->container == NULL || ident->member == NULL)); + int old_linux = 0; + int vers = vers; /* Keep gcc quite - it really is initialised */ + struct { + char *devname; + int uptodate; /* set once we decide that this device is as + * recent as everything else in the array. + */ + int included; /* set if the device is already in the array + * due to a previous '-I' + */ + struct mdinfo i; + } *devices; + char *devmap; + int *best = NULL; /* indexed by raid_disk */ + int bestcnt = 0; + int devcnt = 0; + unsigned int okcnt, sparecnt, rebuilding_cnt; + unsigned int req_cnt; + int i; + int most_recent = 0; + int chosen_drive; + int change = 0; + int inargv = 0; +#ifndef MDASSEMBLE + int bitmap_done; +#endif + int start_partial_ok = (c->runstop >= 0) && + (c->force || devlist==NULL || auto_assem); + int num_devs; + struct mddev_dev *tmpdev; + struct mdinfo info; + struct mdinfo *content = NULL; + struct mdinfo *pre_exist = NULL; + char *avail; + int nextspare = 0; + char *name = NULL; + char chosen_name[1024]; + struct map_ent *map = NULL; + struct map_ent *mp; + + if (get_linux_version() < 2004000) + old_linux = 1; + + /* + * If any subdevs are listed, then any that don't + * match ident are discarded. Remainder must all match and + * become the array. + * If no subdevs, then we scan all devices in the config file, but + * there must be something in the identity + */ + + if (!devlist && + ident->uuid_set == 0 && + (ident->super_minor < 0 || ident->super_minor == UnSet) && + ident->name[0] == 0 && + (ident->container == NULL || ident->member == NULL) && + ident->devices == NULL) { + pr_err("No identity information available for %s - cannot assemble.\n", + mddev ? mddev : "further assembly"); + return 1; + } + + if (devlist == NULL) + devlist = conf_get_devs(); + else if (mddev) + inargv = 1; + + try_again: + /* We come back here when doing auto-assembly and attempting some + * set of devices failed. Those are now marked as ->used==2 and + * we ignore them and try again + */ + if (!st && ident->st) + st = ident->st; + if (c->verbose>0) + pr_err("looking for devices for %s\n", + mddev ? mddev : "further assembly"); + + content = &info; + num_devs = select_devices(devlist, ident, &st, &content, c, + inargv, auto_assem); + if (num_devs < 0) + return 1; if (!st || !st->sb || !content) return 2; - if (content == &info) - st->ss->getinfo_super(st, content, NULL); - /* We have a full set of devices - we now need to find the * array device. * However there is a risk that we are racing with "mdadm -I"