X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=super-ddf.c;h=1ddf9d1a14a1eb387bef84b123b4cf2360d7cede;hp=6f162b9aab1744109bf65dd3fadaad48f84c6789;hb=503975b9d5f0696b5d2ee20ea903b859e3f60662;hpb=c7079c84412848c11d21b99bd3702701fa5ca5d6 diff --git a/super-ddf.c b/super-ddf.c index 6f162b9a..1ddf9d1a 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -543,34 +543,32 @@ static int load_ddf_headers(int fd, struct ddf_super *super, char *devname) if (lseek64(fd, dsize-512, 0) < 0) { if (devname) - fprintf(stderr, - Name": Cannot seek to anchor block on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot seek to anchor block on %s: %s\n", + devname, strerror(errno)); return 1; } if (read(fd, &super->anchor, 512) != 512) { if (devname) - fprintf(stderr, - Name ": Cannot read anchor block on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot read anchor block on %s: %s\n", + devname, strerror(errno)); return 1; } if (super->anchor.magic != DDF_HEADER_MAGIC) { if (devname) - fprintf(stderr, Name ": no DDF anchor found on %s\n", + pr_err("no DDF anchor found on %s\n", devname); return 2; } if (calc_crc(&super->anchor, 512) != super->anchor.crc) { if (devname) - fprintf(stderr, Name ": bad CRC on anchor on %s\n", + pr_err("bad CRC on anchor on %s\n", devname); return 2; } if (memcmp(super->anchor.revision, DDF_REVISION_0, 8) != 0 && memcmp(super->anchor.revision, DDF_REVISION_2, 8) != 0) { if (devname) - fprintf(stderr, Name ": can only support super revision" + pr_err("can only support super revision" " %.8s and earlier, not %.8s on %s\n", DDF_REVISION_2, super->anchor.revision,devname); return 2; @@ -579,9 +577,8 @@ static int load_ddf_headers(int fd, struct ddf_super *super, char *devname) dsize >> 9, 1, &super->primary, &super->anchor) == 0) { if (devname) - fprintf(stderr, - Name ": Failed to load primary DDF header " - "on %s\n", devname); + pr_err("Failed to load primary DDF header " + "on %s\n", devname); return 2; } super->active = &super->primary; @@ -652,7 +649,7 @@ static int load_ddf_local(int fd, struct ddf_super *super, if (posix_memalign((void**)&dl, 512, sizeof(*dl) + (super->max_part) * sizeof(dl->vlist[0])) != 0) { - fprintf(stderr, Name ": %s could not allocate disk info buffer\n", + pr_err("%s could not allocate disk info buffer\n", __func__); return 1; } @@ -661,7 +658,7 @@ static int load_ddf_local(int fd, struct ddf_super *super, super->active->data_section_offset, super->active->data_section_length, 0); - dl->devname = devname ? strdup(devname) : NULL; + dl->devname = devname ? xstrdup(devname) : NULL; fstat(fd, &stb); dl->major = major(stb.st_rdev); @@ -706,9 +703,8 @@ static int load_ddf_local(int fd, struct ddf_super *super, continue; if (posix_memalign((void**)&dl->spare, 512, super->conf_rec_len*512) != 0) { - fprintf(stderr, Name - ": %s could not allocate spare info buf\n", - __func__); + pr_err("%s could not allocate spare info buf\n", + __func__); return 1; } @@ -732,9 +728,8 @@ static int load_ddf_local(int fd, struct ddf_super *super, if (posix_memalign((void**)&vcl, 512, (super->conf_rec_len*512 + offsetof(struct vcl, conf))) != 0) { - fprintf(stderr, Name - ": %s could not allocate vcl buf\n", - __func__); + pr_err("%s could not allocate vcl buf\n", + __func__); return 1; } vcl->next = super->conflist; @@ -760,7 +755,7 @@ static int load_ddf_local(int fd, struct ddf_super *super, #ifndef MDASSEMBLE static int load_super_ddf_all(struct supertype *st, int fd, - void **sbp, char *devname, int keep_fd); + void **sbp, char *devname); #endif static void free_super_ddf(struct supertype *st); @@ -772,14 +767,6 @@ static int load_super_ddf(struct supertype *st, int fd, struct ddf_super *super; int rv; -#ifndef MDASSEMBLE - /* if 'fd' is a container, load metadata from all the devices */ - if (load_super_ddf_all(st, fd, &st->sb, devname, 1) == 0) - return 0; -#endif - if (st->subarray[0]) - return 1; /* FIXME Is this correct */ - if (get_dev_size(fd, devname, &dsize) == 0) return 1; @@ -790,25 +777,23 @@ static int load_super_ddf(struct supertype *st, int fd, /* 32M is a lower bound */ if (dsize <= 32*1024*1024) { if (devname) - fprintf(stderr, - Name ": %s is too small for ddf: " - "size is %llu sectors.\n", - devname, dsize>>9); + pr_err("%s is too small for ddf: " + "size is %llu sectors.\n", + devname, dsize>>9); return 1; } if (dsize & 511) { if (devname) - fprintf(stderr, - Name ": %s is an odd size for ddf: " - "size is %llu bytes.\n", - devname, dsize); + pr_err("%s is an odd size for ddf: " + "size is %llu bytes.\n", + devname, dsize); return 1; } free_super_ddf(st); if (posix_memalign((void**)&super, 512, sizeof(*super))!= 0) { - fprintf(stderr, Name ": malloc of %zu failed.\n", + pr_err("malloc of %zu failed.\n", sizeof(*super)); return 1; } @@ -826,9 +811,8 @@ static int load_super_ddf(struct supertype *st, int fd, if (rv) { if (devname) - fprintf(stderr, - Name ": Failed to load all information " - "sections on %s\n", devname); + pr_err("Failed to load all information " + "sections on %s\n", devname); free(super); return rv; } @@ -837,33 +821,12 @@ static int load_super_ddf(struct supertype *st, int fd, if (rv) { if (devname) - fprintf(stderr, - Name ": Failed to load all information " - "sections on %s\n", devname); + pr_err("Failed to load all information " + "sections on %s\n", devname); free(super); return rv; } - if (st->subarray[0]) { - unsigned long val; - struct vcl *v; - char *ep; - - val = strtoul(st->subarray, &ep, 10); - if (*ep != '\0') { - free(super); - return 1; - } - - for (v = super->conflist; v; v = v->next) - if (v->vcnum == val) - super->currentconf = v; - if (!super->currentconf) { - free(super); - return 1; - } - } - /* Should possibly check the sections .... */ st->sb = super; @@ -872,7 +835,6 @@ static int load_super_ddf(struct supertype *st, int fd, st->minor_version = 0; st->max_devs = 512; } - st->loaded_container = 0; return 0; } @@ -922,8 +884,8 @@ static struct supertype *match_metadata_desc_ddf(char *arg) ) return NULL; - st = malloc(sizeof(*st)); - memset(st, 0, sizeof(*st)); + st = xcalloc(1, sizeof(*st)); + st->container_dev = NoMdDev; st->ss = &super_ddf; st->max_devs = 512; st->minor_version = 0; @@ -1199,7 +1161,7 @@ static void examine_super_ddf(struct supertype *st, char *homehost) examine_pds(sb); } -static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info); +static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *map); static void uuid_from_super_ddf(struct supertype *st, int uuid[4]); @@ -1209,7 +1171,7 @@ static void brief_examine_super_ddf(struct supertype *st, int verbose) */ struct mdinfo info; char nbuf[64]; - getinfo_super_ddf(st, &info); + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(st, &info, nbuf, ':'); printf("ARRAY metadata=ddf UUID=%s\n", nbuf + 5); @@ -1223,7 +1185,7 @@ static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) struct mdinfo info; unsigned int i; char nbuf[64]; - getinfo_super_ddf(st, &info); + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(st, &info, nbuf, ':'); for (i = 0; i < __be16_to_cpu(ddf->virt->max_vdes); i++) { @@ -1245,7 +1207,7 @@ static void export_examine_super_ddf(struct supertype *st) { struct mdinfo info; char nbuf[64]; - getinfo_super_ddf(st, &info); + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(st, &info, nbuf, ':'); printf("MD_METADATA=ddf\n"); printf("MD_LEVEL=container\n"); @@ -1271,7 +1233,7 @@ static void brief_detail_super_ddf(struct supertype *st) // struct ddf_super *ddf = st->sb; struct mdinfo info; char nbuf[64]; - getinfo_super_ddf(st, &info); + getinfo_super_ddf(st, &info, NULL); fname_from_uuid(st, &info, nbuf,':'); printf(" UUID=%s", nbuf + 5); } @@ -1358,23 +1320,27 @@ static void uuid_from_super_ddf(struct supertype *st, int uuid[4]) memcpy(uuid, buf, 4*4); } -static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info); +static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, char *map); -static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) +static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *map) { struct ddf_super *ddf = st->sb; + int map_disks = info->array.raid_disks; + __u32 *cptr; if (ddf->currentconf) { - getinfo_super_ddf_bvd(st, info); + getinfo_super_ddf_bvd(st, info, map); return; } + memset(info, 0, sizeof(*info)); info->array.raid_disks = __be16_to_cpu(ddf->phys->used_pdes); info->array.level = LEVEL_CONTAINER; info->array.layout = 0; info->array.md_minor = -1; - info->array.ctime = DECADE + __be32_to_cpu(*(__u32*) - (ddf->anchor.guid+16)); + cptr = (__u32 *)(ddf->anchor.guid + 16); + info->array.ctime = DECADE + __be32_to_cpu(*cptr); + info->array.utime = 0; info->array.chunk_size = 0; info->container_enough = 1; @@ -1400,6 +1366,7 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) info->recovery_start = MaxSector; info->reshape_active = 0; + info->recovery_blocked = 0; info->name[0] = 0; info->array.major_version = -1; @@ -1409,18 +1376,32 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) uuid_from_super_ddf(st, info->uuid); + if (map) { + int i; + for (i = 0 ; i < map_disks; i++) { + if (i < info->array.raid_disks && + (__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Online) && + !(__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Failed)) + map[i] = 1; + else + map[i] = 0; + } + } } static int rlq_to_layout(int rlq, int prl, int raiddisks); -static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) +static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, char *map) { struct ddf_super *ddf = st->sb; struct vcl *vc = ddf->currentconf; int cd = ddf->currentdev; int j; struct dl *dl; + int map_disks = info->array.raid_disks; + __u32 *cptr; + memset(info, 0, sizeof(*info)); /* FIXME this returns BVD info - what if we want SVD ?? */ info->array.raid_disks = __be16_to_cpu(vc->conf.prim_elmnt_count); @@ -1428,8 +1409,8 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) info->array.layout = rlq_to_layout(vc->conf.rlq, vc->conf.prl, info->array.raid_disks); info->array.md_minor = -1; - info->array.ctime = DECADE + - __be32_to_cpu(*(__u32*)(vc->conf.guid+16)); + cptr = (__u32 *)(vc->conf.guid + 16); + info->array.ctime = DECADE + __be32_to_cpu(*cptr); info->array.utime = DECADE + __be32_to_cpu(vc->conf.timestamp); info->array.chunk_size = 512 << vc->conf.chunk_shift; info->custom_array_size = 0; @@ -1443,23 +1424,26 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) } for (dl = ddf->dlist; dl ; dl = dl->next) - if (dl->raiddisk == info->disk.raid_disk) + if (dl->raiddisk == ddf->currentdev) break; + info->disk.major = 0; info->disk.minor = 0; + info->disk.state = 0; if (dl) { info->disk.major = dl->major; info->disk.minor = dl->minor; + info->disk.raid_disk = dl->raiddisk; + info->disk.number = dl->pdnum; + info->disk.state = (1<disk.number = __be32_to_cpu(ddf->disk.refnum); -// info->disk.raid_disk = find refnum in the table and use index; -// info->disk.state = ???; info->container_member = ddf->currentconf->vcnum; info->recovery_start = MaxSector; info->resync_start = 0; info->reshape_active = 0; + info->recovery_blocked = 0; if (!(ddf->virt->entries[info->container_member].state & DDF_state_inconsistent) && (ddf->virt->entries[info->container_member].init_state @@ -1471,9 +1455,9 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) info->array.major_version = -1; info->array.minor_version = -2; - sprintf(info->text_version, "/%s/%s", + sprintf(info->text_version, "/%s/%d", devnum2devname(st->container_dev), - st->subarray); + info->container_member); info->safe_mode_delay = 200; memcpy(info->name, ddf->virt->entries[info->container_member].name, 16); @@ -1481,6 +1465,18 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) for(j=0; j<16; j++) if (info->name[j] == ' ') info->name[j] = 0; + + if (map) + for (j = 0; j < map_disks; j++) { + map[j] = 0; + if (j < info->array.raid_disks) { + int i = find_phys(ddf, vc->conf.phys_refnum[j]); + if (i >= 0 && + (__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Online) && + !(__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Failed)) + map[i] = 1; + } + } } @@ -1526,28 +1522,27 @@ static int update_super_ddf(struct supertype *st, struct mdinfo *info, if (strcmp(update, "grow") == 0) { /* FIXME */ - } - if (strcmp(update, "resync") == 0) { + } else if (strcmp(update, "resync") == 0) { // info->resync_checkpoint = 0; - } - /* We ignore UUID updates as they make even less sense - * with DDF - */ - if (strcmp(update, "homehost") == 0) { + } else if (strcmp(update, "homehost") == 0) { /* homehost is stored in controller->vendor_data, * or it is when we are the vendor */ // if (info->vendor_is_local) // strcpy(ddf->controller.vendor_data, homehost); - } - if (strcmp(update, "name") == 0) { + rv = -1; + } else if (strcmp(update, "name") == 0) { /* name is stored in virtual_entry->name */ // memset(ve->name, ' ', 16); // strncpy(ve->name, info->name, 16); - } - if (strcmp(update, "_reshape_progress") == 0) { + rv = -1; + } else if (strcmp(update, "_reshape_progress") == 0) { /* We don't support reshape yet */ - } + } else if (strcmp(update, "assemble") == 0 ) { + /* Do nothing, just succeed */ + rv = 0; + } else + rv = -1; // update_all_csum(ddf); @@ -1624,7 +1619,7 @@ static int init_super_ddf(struct supertype *st, return init_super_ddf_bvd(st, info, size, name, homehost, uuid); if (posix_memalign((void**)&ddf, 512, sizeof(*ddf)) != 0) { - fprintf(stderr, Name ": %s could not allocate superblock\n", __func__); + pr_err("%s could not allocate superblock\n", __func__); return 0; } memset(ddf, 0, sizeof(*ddf)); @@ -1762,7 +1757,7 @@ static int init_super_ddf(struct supertype *st, strcpy((char*)ddf->controller.vendor_data, homehost); if (posix_memalign((void**)&pd, 512, pdsize) != 0) { - fprintf(stderr, Name ": %s could not allocate pd\n", __func__); + pr_err("%s could not allocate pd\n", __func__); return 0; } ddf->phys = pd; @@ -1776,7 +1771,7 @@ static int init_super_ddf(struct supertype *st, memset(pd->pad, 0xff, 52); if (posix_memalign((void**)&vd, 512, vdsize) != 0) { - fprintf(stderr, Name ": %s could not allocate vd\n", __func__); + pr_err("%s could not allocate vd\n", __func__); return 0; } ddf->virt = vd; @@ -1922,9 +1917,7 @@ FIXME ignore DDF_Legacy devices? int n = 0; unsigned int i, j; - rv = malloc(sizeof(struct extent) * (ddf->max_part + 2)); - if (!rv) - return NULL; + rv = xmalloc(sizeof(struct extent) * (ddf->max_part + 2)); for (i = 0; i < ddf->max_part; i++) { struct vcl *v = dl->vlist[i]; @@ -1965,9 +1958,9 @@ static int init_super_ddf_bvd(struct supertype *st, if (__be16_to_cpu(ddf->virt->populated_vdes) >= __be16_to_cpu(ddf->virt->max_vdes)) { - fprintf(stderr, Name": This ddf already has the " - "maximum of %d virtual devices\n", - __be16_to_cpu(ddf->virt->max_vdes)); + pr_err("This ddf already has the " + "maximum of %d virtual devices\n", + __be16_to_cpu(ddf->virt->max_vdes)); return 0; } @@ -1977,9 +1970,9 @@ static int init_super_ddf_bvd(struct supertype *st, char *n = ddf->virt->entries[venum].name; if (strncmp(name, n, 16) == 0) { - fprintf(stderr, Name ": This ddf already" - " has an array called %s\n", - name); + pr_err("This ddf already" + " has an array called %s\n", + name); return 0; } } @@ -1988,7 +1981,7 @@ static int init_super_ddf_bvd(struct supertype *st, if (all_ff(ddf->virt->entries[venum].guid)) break; if (venum == __be16_to_cpu(ddf->virt->max_vdes)) { - fprintf(stderr, Name ": Cannot find spare slot for " + pr_err("Cannot find spare slot for " "virtual disk - DDF is corrupt\n"); return 0; } @@ -2018,12 +2011,11 @@ static int init_super_ddf_bvd(struct supertype *st, /* Now create a new vd_config */ if (posix_memalign((void**)&vcl, 512, (offsetof(struct vcl, conf) + ddf->conf_rec_len * 512)) != 0) { - fprintf(stderr, Name ": %s could not allocate vd_config\n", __func__); + pr_err("%s could not allocate vd_config\n", __func__); return 0; } vcl->lba_offset = (__u64*) &vcl->conf.phys_refnum[ddf->mppe]; vcl->vcnum = venum; - sprintf(st->subarray, "%d", venum); vcl->block_sizes = NULL; /* FIXME not for CONCAT */ vc = &vcl->conf; @@ -2191,6 +2183,7 @@ static int add_to_super_ddf(struct supertype *st, struct phys_disk_entry *pde; unsigned int n, i; struct stat stb; + __u32 *tptr; if (ddf->currentconf) { add_to_super_ddf_bvd(st, dk, fd, devname); @@ -2203,9 +2196,8 @@ static int add_to_super_ddf(struct supertype *st, fstat(fd, &stb); if (posix_memalign((void**)&dd, 512, sizeof(*dd) + sizeof(dd->vlist[0]) * ddf->max_part) != 0) { - fprintf(stderr, Name - ": %s could allocate buffer for new disk, aborting\n", - __func__); + pr_err("%s could allocate buffer for new disk, aborting\n", + __func__); return 1; } dd->major = major(stb.st_rdev); @@ -2219,8 +2211,9 @@ static int add_to_super_ddf(struct supertype *st, tm = localtime(&now); sprintf(dd->disk.guid, "%8s%04d%02d%02d", T10, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); - *(__u32*)(dd->disk.guid + 16) = random32(); - *(__u32*)(dd->disk.guid + 20) = random32(); + tptr = (__u32 *)(dd->disk.guid + 16); + *tptr++ = random32(); + *tptr = random32(); do { /* Cannot be bothered finding a CRC of some irrelevant details*/ @@ -2248,7 +2241,7 @@ static int add_to_super_ddf(struct supertype *st, sizeof(struct phys_disk_entry)); struct phys_disk *pd; - pd = malloc(len); + pd = xmalloc(len); pd->magic = DDF_PHYS_RECORDS_MAGIC; pd->used_pdes = __cpu_to_be16(n); pde = &pd->entries[0]; @@ -2281,15 +2274,48 @@ static int add_to_super_ddf(struct supertype *st, return 0; } +static int remove_from_super_ddf(struct supertype *st, mdu_disk_info_t *dk) +{ + struct ddf_super *ddf = st->sb; + struct dl *dl; + + /* mdmon has noticed that this disk (dk->major/dk->minor) has + * disappeared from the container. + * We need to arrange that it disappears from the metadata and + * internal data structures too. + * Most of the work is done by ddf_process_update which edits + * the metadata and closes the file handle and attaches the memory + * where free_updates will free it. + */ + for (dl = ddf->dlist; dl ; dl = dl->next) + if (dl->major == dk->major && + dl->minor == dk->minor) + break; + if (!dl) + return -1; + + if (st->update_tail) { + int len = (sizeof(struct phys_disk) + + sizeof(struct phys_disk_entry)); + struct phys_disk *pd; + + pd = xmalloc(len); + pd->magic = DDF_PHYS_RECORDS_MAGIC; + pd->used_pdes = __cpu_to_be16(dl->pdnum); + pd->entries[0].state = __cpu_to_be16(DDF_Missing); + append_metadata_update(st, pd, len); + } + return 0; +} + /* * This is the write_init_super method for a ddf container. It is * called when creating a container or adding another device to a * container. */ +#define NULL_CONF_SZ 4096 -static unsigned char null_conf[4096+512]; - -static int __write_init_super_ddf(struct supertype *st, int do_close) +static int __write_init_super_ddf(struct supertype *st) { struct ddf_super *ddf = st->sb; @@ -2300,6 +2326,12 @@ static int __write_init_super_ddf(struct supertype *st, int do_close) int attempts = 0; int successes = 0; unsigned long long size, sector; + char *null_aligned; + + if (posix_memalign((void**)&null_aligned, 4096, NULL_CONF_SZ) != 0) { + return -ENOMEM; + } + memset(null_aligned, 0xff, NULL_CONF_SZ); /* try to write updated metadata, * if we catch a failure move on to the next disk @@ -2369,14 +2401,11 @@ static int __write_init_super_ddf(struct supertype *st, int do_close) if (write(fd, &c->conf, conf_size) < 0) break; } else { - char *null_aligned = (char*)((((unsigned long)null_conf)+511)&~511UL); - if (null_conf[0] != 0xff) - memset(null_conf, 0xff, sizeof(null_conf)); unsigned int togo = conf_size; - while (togo > sizeof(null_conf)-512) { - if (write(fd, null_aligned, sizeof(null_conf)-512) < 0) + while (togo > NULL_CONF_SZ) { + if (write(fd, null_aligned, NULL_CONF_SZ) < 0) break; - togo -= sizeof(null_conf)-512; + togo -= NULL_CONF_SZ; } if (write(fd, null_aligned, togo) < 0) break; @@ -2395,12 +2424,7 @@ static int __write_init_super_ddf(struct supertype *st, int do_close) continue; successes++; } - - if (do_close) - for (d = ddf->dlist; d; d=d->next) { - close(d->fd); - d->fd = -1; - } + free(null_aligned); return attempts != successes; } @@ -2436,7 +2460,7 @@ static int write_init_super_ddf(struct supertype *st) /* First the virtual disk. We have a slightly fake header */ len = sizeof(struct virtual_disk) + sizeof(struct virtual_entry); - vd = malloc(len); + vd = xmalloc(len); *vd = *ddf->virt; vd->entries[0] = ddf->virt->entries[currentconf->vcnum]; vd->populated_vdes = __cpu_to_be16(currentconf->vcnum); @@ -2444,7 +2468,7 @@ static int write_init_super_ddf(struct supertype *st) /* Then the vd_config */ len = ddf->conf_rec_len * 512; - vc = malloc(len); + vc = xmalloc(len); memcpy(vc, ¤tconf->conf, len); append_metadata_update(st, vc, len); @@ -2454,7 +2478,7 @@ static int write_init_super_ddf(struct supertype *st) struct dl *d; for (d = ddf->dlist; d; d=d->next) while (Kill(d->devname, NULL, 0, 1, 1) == 0); - return __write_init_super_ddf(st, 1); + return __write_init_super_ddf(st); } } @@ -2517,7 +2541,7 @@ static int reserve_space(struct supertype *st, int raiddisks, free(e); } if (cnt < raiddisks) { - fprintf(stderr, Name ": not enough devices with space to create array.\n"); + pr_err("not enough devices with space to create array.\n"); return 0; /* No enough free spaces large enough */ } if (size == 0) { @@ -2528,7 +2552,7 @@ static int reserve_space(struct supertype *st, int raiddisks, continue; /* This is bigger than 'size', see if there are enough */ cnt = 0; - for (dl2 = dl; dl2 ; dl2=dl2->next) + for (dl2 = ddf->dlist; dl2 ; dl2=dl2->next) if (dl2->esize >= dl->esize) cnt++; if (cnt >= raiddisks) @@ -2540,7 +2564,7 @@ static int reserve_space(struct supertype *st, int raiddisks, } *freesize = size; if (size < 32) { - fprintf(stderr, Name ": not enough spare devices to create array.\n"); + pr_err("not enough spare devices to create array.\n"); return 0; } } @@ -2568,13 +2592,13 @@ validate_geometry_ddf_container(struct supertype *st, static int validate_geometry_ddf_bvd(struct supertype *st, int level, int layout, int raiddisks, - int chunk, unsigned long long size, + int *chunk, unsigned long long size, char *dev, unsigned long long *freesize, int verbose); static int validate_geometry_ddf(struct supertype *st, int level, int layout, int raiddisks, - int chunk, unsigned long long size, + int *chunk, unsigned long long size, char *dev, unsigned long long *freesize, int verbose) { @@ -2589,10 +2613,14 @@ static int validate_geometry_ddf(struct supertype *st, * If given BVDs, we make an SVD, changing all the GUIDs in the process. */ + if (chunk && *chunk == UnSet) + *chunk = DEFAULT_CHUNK; + + if (level == LEVEL_CONTAINER) { /* Must be a fresh device to add to a container */ return validate_geometry_ddf_container(st, level, layout, - raiddisks, chunk, + raiddisks, chunk?*chunk:0, size, dev, freesize, verbose); } @@ -2605,7 +2633,7 @@ static int validate_geometry_ddf(struct supertype *st, break; if (ddf_level_num[i].num1 == MAXINT) { if (verbose) - fprintf(stderr, Name ": DDF does not support level %d arrays\n", + pr_err("DDF does not support level %d arrays\n", level); return 0; } @@ -2619,7 +2647,7 @@ static int validate_geometry_ddf(struct supertype *st, * chosen so that add_to_super/getinfo_super * can return them. */ - return reserve_space(st, raiddisks, size, chunk, freesize); + return reserve_space(st, raiddisks, size, chunk?*chunk:0, freesize); } return 1; } @@ -2654,15 +2682,14 @@ static int validate_geometry_ddf(struct supertype *st, } if (verbose) - fprintf(stderr, - Name ": ddf: Cannot create this array " - "on device %s - a container is required.\n", - dev); + pr_err("ddf: Cannot create this array " + "on device %s - a container is required.\n", + dev); return 0; } if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) { if (verbose) - fprintf(stderr, Name ": ddf: Cannot open %s: %s\n", + pr_err("ddf: Cannot open %s: %s\n", dev, strerror(errno)); return 0; } @@ -2671,7 +2698,7 @@ static int validate_geometry_ddf(struct supertype *st, if (cfd < 0) { close(fd); if (verbose) - fprintf(stderr, Name ": ddf: Cannot use %s: %s\n", + pr_err("ddf: Cannot use %s: %s\n", dev, strerror(EBUSY)); return 0; } @@ -2683,7 +2710,7 @@ static int validate_geometry_ddf(struct supertype *st, * and try to create a bvd */ struct ddf_super *ddf; - if (load_super_ddf_all(st, cfd, (void **)&ddf, NULL, 1) == 0) { + if (load_super_ddf_all(st, cfd, (void **)&ddf, NULL) == 0) { st->sb = ddf; st->container_dev = fd2devnum(cfd); close(cfd); @@ -2717,7 +2744,7 @@ validate_geometry_ddf_container(struct supertype *st, fd = open(dev, O_RDONLY|O_EXCL, 0); if (fd < 0) { if (verbose) - fprintf(stderr, Name ": ddf: Cannot open %s: %s\n", + pr_err("ddf: Cannot open %s: %s\n", dev, strerror(errno)); return 0; } @@ -2736,7 +2763,7 @@ validate_geometry_ddf_container(struct supertype *st, static int validate_geometry_ddf_bvd(struct supertype *st, int level, int layout, int raiddisks, - int chunk, unsigned long long size, + int *chunk, unsigned long long size, char *dev, unsigned long long *freesize, int verbose) { @@ -2750,7 +2777,7 @@ static int validate_geometry_ddf_bvd(struct supertype *st, /* ddf/bvd supports lots of things, but not containers */ if (level == LEVEL_CONTAINER) { if (verbose) - fprintf(stderr, Name ": DDF cannot create a container within an container\n"); + pr_err("DDF cannot create a container within an container\n"); return 0; } /* We must have the container info already read in. */ @@ -2787,10 +2814,9 @@ static int validate_geometry_ddf_bvd(struct supertype *st, } if (dcnt < raiddisks) { if (verbose) - fprintf(stderr, - Name ": ddf: Not enough devices with " - "space for this array (%d < %d)\n", - dcnt, raiddisks); + pr_err("ddf: Not enough devices with " + "space for this array (%d < %d)\n", + dcnt, raiddisks); return 0; } return 1; @@ -2807,7 +2833,7 @@ static int validate_geometry_ddf_bvd(struct supertype *st, } if (!dl) { if (verbose) - fprintf(stderr, Name ": ddf: %s is not in the " + pr_err("ddf: %s is not in the " "same DDF set\n", dev); return 0; @@ -2830,7 +2856,7 @@ static int validate_geometry_ddf_bvd(struct supertype *st, } static int load_super_ddf_all(struct supertype *st, int fd, - void **sbp, char *devname, int keep_fd) + void **sbp, char *devname) { struct mdinfo *sra; struct ddf_super *super; @@ -2886,49 +2912,35 @@ static int load_super_ddf_all(struct supertype *st, int fd, int rv; sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); - dfd = dev_open(nm, keep_fd? O_RDWR : O_RDONLY); + dfd = dev_open(nm, O_RDWR); if (dfd < 0) return 2; rv = load_ddf_headers(dfd, super, NULL); if (rv == 0) - rv = load_ddf_local(dfd, super, NULL, keep_fd); - if (!keep_fd) close(dfd); + rv = load_ddf_local(dfd, super, NULL, 1); if (rv) return 1; } - if (st->subarray[0]) { - unsigned long val; - struct vcl *v; - char *ep; - - val = strtoul(st->subarray, &ep, 10); - if (*ep != '\0') { - free(super); - return 1; - } - - for (v = super->conflist; v; v = v->next) - if (v->vcnum == val) - super->currentconf = v; - if (!super->currentconf) { - free(super); - return 1; - } - } *sbp = super; if (st->ss == NULL) { st->ss = &super_ddf; st->minor_version = 0; st->max_devs = 512; - st->container_dev = fd2devnum(fd); } - st->loaded_container = 1; + st->container_dev = fd2devnum(fd); return 0; } + +static int load_container_ddf(struct supertype *st, int fd, + char *devname) +{ + return load_super_ddf_all(st, fd, &st->sb, devname); +} + #endif /* MDASSEMBLE */ -static struct mdinfo *container_content_ddf(struct supertype *st) +static struct mdinfo *container_content_ddf(struct supertype *st, char *subarray) { /* Given a container loaded by load_super_ddf_all, * extract information about all the arrays into @@ -2947,8 +2959,15 @@ static struct mdinfo *container_content_ddf(struct supertype *st) unsigned int i; unsigned int j; struct mdinfo *this; - this = malloc(sizeof(*this)); - memset(this, 0, sizeof(*this)); + char *ep; + __u32 *cptr; + + if (subarray && + (strtoul(subarray, &ep, 10) != vc->vcnum || + *ep != '\0')) + continue; + + this = xcalloc(1, sizeof(*this)); this->next = rest; rest = this; @@ -2960,8 +2979,8 @@ static struct mdinfo *container_content_ddf(struct supertype *st) this->array.md_minor = -1; this->array.major_version = -1; this->array.minor_version = -2; - this->array.ctime = DECADE + - __be32_to_cpu(*(__u32*)(vc->conf.guid+16)); + cptr = (__u32 *)(vc->conf.guid + 16); + this->array.ctime = DECADE + __be32_to_cpu(*cptr); this->array.utime = DECADE + __be32_to_cpu(vc->conf.timestamp); this->array.chunk_size = 512 << vc->conf.chunk_shift; @@ -2999,25 +3018,34 @@ static struct mdinfo *container_content_ddf(struct supertype *st) struct mdinfo *dev; struct dl *d; int stt; + int pd; if (vc->conf.phys_refnum[i] == 0xFFFFFFFF) continue; - for (d = ddf->dlist; d ; d=d->next) - if (d->disk.refnum == vc->conf.phys_refnum[i]) + for (pd = __be16_to_cpu(ddf->phys->used_pdes); + pd--;) + if (ddf->phys->entries[pd].refnum + == vc->conf.phys_refnum[i]) break; - if (d == NULL) - /* Haven't found that one yet, maybe there are others */ + if (pd < 0) continue; - stt = __be16_to_cpu(ddf->phys->entries[d->pdnum].state); + + stt = __be16_to_cpu(ddf->phys->entries[pd].state); if ((stt & (DDF_Online|DDF_Failed|DDF_Rebuilding)) != DDF_Online) continue; this->array.working_disks++; - dev = malloc(sizeof(*dev)); - memset(dev, 0, sizeof(*dev)); + for (d = ddf->dlist; d ; d=d->next) + if (d->disk.refnum == vc->conf.phys_refnum[i]) + break; + if (d == NULL) + /* Haven't found that one yet, maybe there are others */ + continue; + + dev = xcalloc(1, sizeof(*dev)); dev->next = this->devs; this->devs = dev; @@ -3254,6 +3282,8 @@ static void ddf_set_disk(struct active_array *a, int n, int state) case DDF_RAID1: if (working == 0) state = DDF_state_failed; + else if (working == 2 && state == DDF_state_degraded) + state = DDF_state_part_optimal; break; case DDF_RAID4: case DDF_RAID5: @@ -3294,7 +3324,7 @@ static void ddf_sync_metadata(struct supertype *st) if (!ddf->updates_pending) return; ddf->updates_pending = 0; - __write_init_super_ddf(st, 0); + __write_init_super_ddf(st); dprintf("ddf: sync_metadata\n"); } @@ -3306,8 +3336,8 @@ static void ddf_process_update(struct supertype *st, * our actions. * Possible update are: * DDF_PHYS_RECORDS_MAGIC - * Add a new physical device. Changes to this record - * only happen implicitly. + * Add a new physical device or remove an old one. + * Changes to this record only happen implicitly. * used_pdes is the device number. * DDF_VIRT_RECORDS_MAGIC * Add a new VD. Possibly also change the 'access' bits. @@ -3352,6 +3382,25 @@ static void ddf_process_update(struct supertype *st, ent = __be16_to_cpu(pd->used_pdes); if (ent >= __be16_to_cpu(ddf->phys->max_pdes)) return; + if (pd->entries[0].state & __cpu_to_be16(DDF_Missing)) { + struct dl **dlp; + /* removing this disk. */ + ddf->phys->entries[ent].state |= __cpu_to_be16(DDF_Missing); + for (dlp = &ddf->dlist; *dlp; dlp = &(*dlp)->next) { + struct dl *dl = *dlp; + if (dl->pdnum == (signed)ent) { + close(dl->fd); + dl->fd = -1; + /* FIXME this doesn't free + * dl->devname */ + update->space = dl; + *dlp = dl->next; + break; + } + } + ddf->updates_pending = 1; + return; + } if (!all_ff(ddf->phys->entries[ent].guid)) return; ddf->phys->entries[ent] = pd->entries[0]; @@ -3688,10 +3737,7 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, } /* Cool, we have a device with some space at pos */ - di = malloc(sizeof(*di)); - if (!di) - continue; - memset(di, 0, sizeof(*di)); + di = xcalloc(1, sizeof(*di)); di->disk.number = i; di->disk.raid_disk = i; di->disk.major = dl->major; @@ -3723,24 +3769,15 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, * Create a metadata_update record to update the * phys_refnum and lba_offset values */ - mu = malloc(sizeof(*mu)); - if (mu && posix_memalign(&mu->space, 512, sizeof(struct vcl)) != 0) { + mu = xmalloc(sizeof(*mu)); + if (posix_memalign(&mu->space, 512, sizeof(struct vcl)) != 0) { free(mu); mu = NULL; } - if (!mu) { - while (rv) { - struct mdinfo *n = rv->next; - - free(rv); - rv = n; - } - return NULL; - } - - mu->buf = malloc(ddf->conf_rec_len * 512); + mu->buf = xmalloc(ddf->conf_rec_len * 512); mu->len = ddf->conf_rec_len * 512; mu->space = NULL; + mu->space_list = NULL; mu->next = *updates; vc = find_vdcr(ddf, a->info.container_member); memcpy(mu->buf, vc, ddf->conf_rec_len * 512); @@ -3774,6 +3811,15 @@ static int ddf_level_to_layout(int level) } } +static void default_geometry_ddf(struct supertype *st, int *level, int *layout, int *chunk) +{ + if (level && *level == UnSet) + *level = LEVEL_CONTAINER; + + if (level && layout && *layout == UnSet) + *layout = ddf_level_to_layout(*level); +} + struct superswitch super_ddf = { #ifndef MDASSEMBLE .examine_super = examine_super_ddf, @@ -3785,6 +3831,8 @@ struct superswitch super_ddf = { .validate_geometry = validate_geometry_ddf, .write_init_super = write_init_super_ddf, .add_to_super = add_to_super_ddf, + .remove_from_super = remove_from_super_ddf, + .load_container = load_container_ddf, #endif .match_home = match_home_ddf, .uuid_from_super= uuid_from_super_ddf, @@ -3801,7 +3849,7 @@ struct superswitch super_ddf = { .free_super = free_super_ddf, .match_metadata_desc = match_metadata_desc_ddf, .container_content = container_content_ddf, - .default_layout = ddf_level_to_layout, + .default_geometry = default_geometry_ddf, .external = 1,