From: Czarnowska, Anna Sent: Monday, July 05, 2010 11:43 AM To: Neil Brown Cc: linux-raid@xxxxxxxxxxxxxxx; Czarnowska, Anna; Hawrylewicz Czarnowski, Przemyslaw; Labun, Marcin; Neubauer, Wojciech; Williams, Dan J; Ciechanowski, Ed; dledford@xxxxxxxxxx Subject: [PATCH 30/33] Incremental for bare disks, checking routine + integration From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@xxxxxxxxx> The idea of this patch is to allow adding of bare device to the container if device is plugged into the same port as recently removed device. Function 'bare_disk_match_array' has been added to look for special 'cookie' file (named after /dev/disk/by-path name of missing device) containing the name of valid array. If it is found, container device name is returned. This container is used with Manage_subdevs() add, to add device. Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@xxxxxxxxx> --- Incremental.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++--------- config.c | 9 ++- mdadm.h | 3 +- 3 files changed, 160 insertions(+), 32 deletions(-) diff --git a/Incremental.c b/Incremental.c index adaefb9..3783e37 100644 --- a/Incremental.c +++ b/Incremental.c @@ -29,6 +29,8 @@ */ #include "mdadm.h" +#include <sys/types.h> +#include <dirent.h> static int count_active(struct supertype *st, int mdfd, char **availp, struct mdinfo *info); @@ -40,6 +42,87 @@ static int IncrementalNewPart(char *devname, int verbose, int export, static int IncrementalNewDisk(char *devname, int verbose, int export, struct domain_ent *domain); + + +/* finds cookie file with matching path. If found, returns device name + * either for this array (native) or its parent container (external) +*/ char *bare_disk_match_array(char *devname, int fd, struct supertype +**st) { + char *dev_path; + char cookie_path[PATH_MAX]; + FILE *cookie; + struct mdstat_ent *mds = NULL, *ent = NULL; + char *mdname = NULL; + + if (!devname) + return NULL; + + mds = mdstat_read(0, 0); + /* no active arrays */ + if (!mds) + return NULL; + + dev_path = get_devpath_from_devname(devname); + if (!dev_path) { + free_mdstat(mds); + return NULL; + } + + snprintf(cookie_path, PATH_MAX, FAILED_SLOTS "/%s", dev_path); + if ((cookie = fopen(cookie_path, "r")) == NULL) { + fprintf(stderr, Name " : Cannot open %s cookie. " + "Bare disk spare action disabled\n.", + cookie_path); + free(dev_path); + return NULL; + } + + /* + * find first active array using list instde 'cookie' file + */ + while(fgets(cookie_path, PATH_MAX, cookie)) { + int devnum; + if (sscanf(cookie_path, "md%d", &devnum) != 1) + continue; + ent = mdstat_by_devnum(&mds, devnum); + if (ent) /* found active array */ + break; + } + if (ent) { + char md_path[PATH_MAX]; + struct mdstat_ent *parent = NULL; + int mdfd; + strcpy(md_path, "/dev/"); + if (is_external(ent->metadata_version)) { + parent = mdstat_get_parent(ent); + if (!parent) { + fprintf(stderr, Name " : Cannot find parent " + "container for array %s\n.", + ent->dev); + goto cleanup; + } + strncat(md_path + 5, parent->dev, PATH_MAX - 5); + free_mdstat(parent); + } else { + strncat(md_path + 5, ent->dev, PATH_MAX - 5); + } + mdfd = open_mddev(md_path, 0); + if (mdfd < 0) + goto cleanup; + *st = guess_super(mdfd); + close(mdfd); + if (!*st) + goto cleanup; + mdname = strdup(md_path); + } +cleanup: + fclose(cookie); + free_mdstat(mds); + free(dev_path); + return mdname; +} + int Incremental(char *devname, int verbose, int runstop, struct supertype *st, char *homehost, int require_homehost, int autof) @@ -1044,10 +1127,19 @@ static int IncrementalNewPart(char *devname, int verbose, int export, struct mdstat_ent *mdstat, *md; struct stat stb; int dfd; + struct supertype *st = NULL; + char *mdname; + int mdfd; + int rv = 0; + struct mddev_dev_s devlist; mdstat = arrays_in_domain(devname, domain); for (md = mdstat; md; md = md->next) printf(Name ": %s\n", md->dev); + + /* any arrays for this domain? */ + if (!mdstat) + return 1; /* 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. @@ -1072,7 +1164,34 @@ static int IncrementalNewPart(char *devname, int verbose, int export, * or 0xff. */ - return 0; + /* for bare action, check if 'cookie' exists for this device, + * temporarily get metadata from matching array and invoke standard + * Incremental with bare=1 + */ + if (conf_get_domain_action(devname, domain->platform) == same_port_bare && + !strstr(devname, "part") && + (mdname = bare_disk_match_array(devname, dfd, &st)) && + !strcmp(st->ss->name, domain->platform)) { + free(st); + mdfd = open_mddev(mdname, 0); + if (!mdfd) { + fprintf(stderr, Name ": cannot open array device %s.\n", mdname); + close(dfd); + return 1; + } + close(dfd); + memset(&devlist, 0, sizeof(devlist)); + devlist.devname = devname; + devlist.disposition = 'a'; + rv = Manage_subdevs(mdname, mdfd, &devlist, 0); + free(mdname); + mdname = NULL; + close(mdfd); + return rv; + } + free(mdname); + close(dfd); + return 1; } /* @@ -1103,7 +1222,7 @@ static int IncrementalNewDisk(char *devname, int verbose, int export, if (domain->handler->check_table(dfd, verbose, export, domain) == 0) { close(dfd); - return 0; + return 1; } /* * OK, at this point we have a valid block device without a @@ -1138,33 +1257,38 @@ int IncrementalNew(char *devname, int verbose, int export) { struct domain_ent *domain; char *devpath; - int rv; + int rv = 1; + int i; - domain = conf_get_domain(devname, NULL); - 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); + for (i = 0; superlist[i]; i++) { + domain = conf_get_domain(devname, (char *)superlist[i]->name); + if (!domain) + continue; + 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. + */ + continue; + 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); + if (!rv) + break; + } return rv; } diff --git a/config.c b/config.c index 5829182..ae06859 100644 --- a/config.c +++ b/config.c @@ -827,6 +827,9 @@ void domainline(char *line) de->action = grow; else if (strncasecmp("par", w+offset, 3) == 0) de->action = partition; + else if (strncasecmp("bar", w+offset, 3) == 0 || + strncasecmp("sam", w+offset, 3) == 0) + de->action = same_port_bare; if (offset == 13) de->action |= force; } else if (strncasecmp("metadata=", w, 9) == 0) { @@ -1046,7 +1049,7 @@ struct domain_ent *get_domain_from_devpath(char *devpath, char *platform) st = get_supertype_by_name(de->platform); if (!st) continue; - + if (match_platform(st, platform)) { st->ss->free_super(st); free(st); @@ -1947,9 +1950,9 @@ struct mdstat_ent *arrays_in_domain(char *devname, struct domain_ent *domain) return array_list; } -int conf_get_domain_action(char *devname) +int conf_get_domain_action(char *devname, char *platform) { - struct domain_ent *domain = conf_get_domain(devname, NULL); + struct domain_ent *domain = conf_get_domain(devname, platform); if (!domain) return incremental; return domain->action; diff --git a/mdadm.h b/mdadm.h index 6eeebd5..a1ec751 100644 --- a/mdadm.h +++ b/mdadm.h @@ -303,6 +303,7 @@ enum domain_actions { appropriate things with the partitions */ spare, grow, + same_port_bare, action_mask=511, force=512, /* so we can bitwise & this with actions to signify we should forcibly take over drives even if they have @@ -955,7 +956,7 @@ extern mddev_dev_t conf_get_devs(void); extern struct domain_ent *conf_get_domain(char *devname, char *platform); extern struct subset *conf_get_subset(char *devname, struct supertype *st, struct domain_ent *domain); -extern int conf_get_domain_action(char *devname); +extern int conf_get_domain_action(char *devname, char *platform); extern struct mdstat_ent *arrays_in_domain(char *devname, struct domain_ent *domain); extern struct subset *conf_get_any_subset(void); -- 1.6.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html