X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=super-ddf.c;h=abd67936e095ea7ec6412743edf2c6db1faab043;hb=2de0b8a2b4d4c0bdc7fbe4caf591a7c160d86da5;hp=8c3f4bebffe195cc7baea9c71ced1188f896c85c;hpb=b7528a20cca58c973771d94d7d2b8ef74bcf582d;p=thirdparty%2Fmdadm.git diff --git a/super-ddf.c b/super-ddf.c index 8c3f4beb..abd67936 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -396,7 +396,7 @@ struct ddf_super { struct phys_disk *phys; struct virtual_disk *virt; int pdsize, vdsize; - int max_part, mppe, conf_rec_len; + unsigned int max_part, mppe, conf_rec_len; int currentdev; int updates_pending; struct vcl { @@ -406,7 +406,7 @@ struct ddf_super { struct vcl *next; __u64 *lba_offset; /* location in 'conf' of * the lba table */ - int vcnum; /* index into ->virt */ + unsigned int vcnum; /* index into ->virt */ __u64 *block_sizes; /* NULL if all the same */ }; }; @@ -440,7 +440,7 @@ struct ddf_super { #endif -static int calc_crc(void *buf, int len) +static unsigned int calc_crc(void *buf, int len) { /* crcs are always at the same place as in the ddf_header */ struct ddf_header *ddf = buf; @@ -522,12 +522,12 @@ static void *load_section(int fd, struct ddf_super *super, void *buf, else offset += __be64_to_cpu(super->active->secondary_lba); - if (lseek64(fd, offset<<9, 0) != (offset<<9)) { + if ((unsigned long long)lseek64(fd, offset<<9, 0) != (offset<<9)) { if (dofree) free(buf); return NULL; } - if (read(fd, buf, len<<9) != (len<<9)) { + if ((unsigned long long)read(fd, buf, len<<9) != (len<<9)) { if (dofree) free(buf); return NULL; @@ -642,10 +642,10 @@ static int load_ddf_local(int fd, struct ddf_super *super, struct dl *dl; struct stat stb; char *conf; - int i; - int confsec; + unsigned int i; + unsigned int confsec; int vnum; - int max_virt_disks = __be16_to_cpu(super->active->max_vd_entries); + unsigned int max_virt_disks = __be16_to_cpu(super->active->max_vd_entries); unsigned long long dsize; /* First the local disk info */ @@ -673,11 +673,11 @@ static int load_ddf_local(int fd, struct ddf_super *super, if (get_dev_size(fd, devname, &dsize)) dl->size = dsize >> 9; dl->spare = NULL; - for (i=0 ; i < super->max_part ; i++) + for (i = 0 ; i < super->max_part ; i++) dl->vlist[i] = NULL; super->dlist = dl; dl->pdnum = -1; - for (i=0; i < __be16_to_cpu(super->active->max_pd_entries); i++) + for (i = 0; i < __be16_to_cpu(super->active->max_pd_entries); i++) if (memcmp(super->phys->entries[i].guid, dl->disk.guid, DDF_GUID_LEN) == 0) dl->pdnum = i; @@ -760,7 +760,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,17 +772,13 @@ 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; + if (test_partition(fd)) + /* DDF is not allowed on partitions */ + return 1; + /* 32M is a lower bound */ if (dsize <= 32*1024*1024) { if (devname) @@ -840,18 +836,6 @@ static int load_super_ddf(struct supertype *st, int fd, return rv; } - if (st->subarray[0]) { - struct vcl *v; - - for (v = super->conflist; v; v = v->next) - if (v->vcnum == atoi(st->subarray)) - super->currentconf = v; - if (!super->currentconf) { - free(super); - return 1; - } - } - /* Should possibly check the sections .... */ st->sb = super; @@ -860,7 +844,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; } @@ -888,6 +871,15 @@ static void free_super_ddf(struct supertype *st) free(d->spare); free(d); } + while (ddf->add_list) { + struct dl *d = ddf->add_list; + ddf->add_list = d->next; + if (d->fd >= 0) + close(d->fd); + if (d->spare) + free(d->spare); + free(d); + } free(ddf); st->sb = NULL; } @@ -903,6 +895,7 @@ static struct supertype *match_metadata_desc_ddf(char *arg) st = malloc(sizeof(*st)); memset(st, 0, sizeof(*st)); + st->container_dev = NoMdDev; st->ss = &super_ddf; st->max_devs = 512; st->minor_version = 0; @@ -1042,7 +1035,7 @@ static void examine_vd(int n, struct ddf_super *sb, char *guid) struct vcl *vcl; for (vcl = sb->conflist ; vcl ; vcl = vcl->next) { - int i; + unsigned int i; struct vd_config *vc = &vcl->conf; if (calc_crc(vc, crl*512) != vc->crc) @@ -1053,7 +1046,7 @@ static void examine_vd(int n, struct ddf_super *sb, char *guid) /* Ok, we know about this VD, let's give more details */ printf(" Raid Devices[%d] : %d (", n, __be16_to_cpu(vc->prim_elmnt_count)); - for (i=0; i<__be16_to_cpu(vc->prim_elmnt_count); i++) { + for (i = 0; i < __be16_to_cpu(vc->prim_elmnt_count); i++) { int j; int cnt = __be16_to_cpu(sb->phys->used_pdes); for (j=0; jsb; struct mdinfo info; - int i; + 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++) { + for (i = 0; i < __be16_to_cpu(ddf->virt->max_vdes); i++) { struct virtual_entry *ve = &ddf->virt->entries[i]; struct vcl vcl; char nbuf1[64]; @@ -1221,7 +1217,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"); @@ -1247,7 +1243,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); } @@ -1260,7 +1256,11 @@ static int match_home_ddf(struct supertype *st, char *homehost) * the hostname */ struct ddf_super *ddf = st->sb; - int len = strlen(homehost); + unsigned int len; + + if (!homehost) + return 0; + len = strlen(homehost); return (memcmp(ddf->controller.guid, T10, 8) == 0 && len < sizeof(ddf->controller.vendor_data) && @@ -1269,7 +1269,7 @@ static int match_home_ddf(struct supertype *st, char *homehost) } #ifndef MDASSEMBLE -static struct vd_config *find_vdcr(struct ddf_super *ddf, int inst) +static struct vd_config *find_vdcr(struct ddf_super *ddf, unsigned int inst) { struct vcl *v; @@ -1285,8 +1285,8 @@ static int find_phys(struct ddf_super *ddf, __u32 phys_refnum) /* Find the entry in phys_disk which has the given refnum * and return it's index */ - int i; - for (i=0; i < __be16_to_cpu(ddf->phys->max_pdes); i++) + unsigned int i; + for (i = 0; i < __be16_to_cpu(ddf->phys->max_pdes); i++) if (ddf->phys->entries[i].refnum == phys_refnum) return i; return -1; @@ -1330,25 +1330,30 @@ 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; info->disk.major = 0; @@ -1369,7 +1374,9 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + info->recovery_start = MaxSector; info->reshape_active = 0; + info->recovery_blocked = 0; info->name[0] = 0; info->array.major_version = -1; @@ -1379,18 +1386,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); @@ -1398,13 +1419,13 @@ 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; - if (cd >= 0 && cd < ddf->mppe) { + if (cd >= 0 && (unsigned)cd < ddf->mppe) { info->data_offset = __be64_to_cpu(vc->lba_offset[cd]); if (vc->block_sizes) info->component_size = vc->block_sizes[cd]; @@ -1413,21 +1434,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 @@ -1437,12 +1463,11 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) uuid_from_super_ddf(st, info->uuid); - info->container_member = atoi(st->subarray); 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); @@ -1450,6 +1475,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; + } + } } @@ -1495,28 +1532,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); @@ -1739,7 +1775,7 @@ static int init_super_ddf(struct supertype *st, memset(pd, 0xff, pdsize); memset(pd, 0, sizeof(*pd)); - pd->magic = DDF_PHYS_DATA_MAGIC; + pd->magic = DDF_PHYS_RECORDS_MAGIC; pd->used_pdes = __cpu_to_be16(0); pd->max_pdes = __cpu_to_be16(max_phys_disks); memset(pd->pad, 0xff, 52); @@ -1889,7 +1925,7 @@ FIXME ignore DDF_Legacy devices? */ struct extent *rv; int n = 0; - int i, j; + unsigned int i, j; rv = malloc(sizeof(struct extent) * (ddf->max_part + 2)); if (!rv) @@ -1899,7 +1935,7 @@ FIXME ignore DDF_Legacy devices? struct vcl *v = dl->vlist[i]; if (v == NULL) continue; - for (j=0; j < v->conf.prim_elmnt_count; j++) + for (j = 0; j < v->conf.prim_elmnt_count; j++) if (v->conf.phys_refnum[j] == dl->disk.refnum) { /* This device plays role 'j' in 'v'. */ rv[n].start = __be64_to_cpu(v->lba_offset[j]); @@ -1927,7 +1963,7 @@ static int init_super_ddf_bvd(struct supertype *st, * We need to create a new vd_config and a new virtual_entry */ struct ddf_super *ddf = st->sb; - int venum; + unsigned int venum; struct virtual_entry *ve; struct vcl *vcl; struct vd_config *vc; @@ -1940,6 +1976,19 @@ static int init_super_ddf_bvd(struct supertype *st, return 0; } + if (name) + for (venum = 0; venum < __be16_to_cpu(ddf->virt->max_vdes); venum++) + if (!all_ff(ddf->virt->entries[venum].guid)) { + 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); + return 0; + } + } + for (venum = 0; venum < __be16_to_cpu(ddf->virt->max_vdes); venum++) if (all_ff(ddf->virt->entries[venum].guid)) break; @@ -1979,7 +2028,6 @@ static int init_super_ddf_bvd(struct supertype *st, } 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; @@ -2048,8 +2096,8 @@ static void add_to_super_ddf_bvd(struct supertype *st, struct ddf_super *ddf = st->sb; struct vd_config *vc; __u64 *lba_offset; - int working; - int i; + unsigned int working; + unsigned int i; unsigned long long blocks, pos, esize; struct extent *ex; @@ -2094,7 +2142,7 @@ static void add_to_super_ddf_bvd(struct supertype *st, vc->phys_refnum[dk->raid_disk] = dl->disk.refnum; lba_offset[dk->raid_disk] = __cpu_to_be64(pos); - for (i=0; i < ddf->max_part ; i++) + for (i = 0; i < ddf->max_part ; i++) if (dl->vlist[i] == NULL) break; if (i == ddf->max_part) @@ -2111,7 +2159,7 @@ static void add_to_super_ddf_bvd(struct supertype *st, */ working = 0; - for (i=0; i < __be16_to_cpu(vc->prim_elmnt_count); i++) + for (i = 0; i < __be16_to_cpu(vc->prim_elmnt_count); i++) if (vc->phys_refnum[i] != 0xffffffff) working++; @@ -2145,8 +2193,9 @@ static int add_to_super_ddf(struct supertype *st, struct tm *tm; unsigned long long size; struct phys_disk_entry *pde; - int n, i; + unsigned int n, i; struct stat stb; + __u32 *tptr; if (ddf->currentconf) { add_to_super_ddf_bvd(st, dk, fd, devname); @@ -2175,17 +2224,18 @@ 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*/ dd->disk.refnum = random32(); - for (i = __be16_to_cpu(ddf->active->max_pd_entries) - 1; - i >= 0; i--) - if (ddf->phys->entries[i].refnum == dd->disk.refnum) + for (i = __be16_to_cpu(ddf->active->max_pd_entries); + i > 0; i--) + if (ddf->phys->entries[i-1].refnum == dd->disk.refnum) break; - } while (i >= 0); + } while (i > 0); dd->disk.forced_ref = 1; dd->disk.forced_guid = 1; @@ -2237,6 +2287,40 @@ 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 = malloc(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 @@ -2245,7 +2329,7 @@ static int add_to_super_ddf(struct supertype *st, 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; @@ -2328,7 +2412,7 @@ static int __write_init_super_ddf(struct supertype *st, int do_close) char *null_aligned = (char*)((((unsigned long)null_conf)+511)&~511UL); if (null_conf[0] != 0xff) memset(null_conf, 0xff, sizeof(null_conf)); - int togo = conf_size; + unsigned int togo = conf_size; while (togo > sizeof(null_conf)-512) { if (write(fd, null_aligned, sizeof(null_conf)-512) < 0) break; @@ -2352,12 +2436,6 @@ static int __write_init_super_ddf(struct supertype *st, int do_close) successes++; } - if (do_close) - for (d = ddf->dlist; d; d=d->next) { - close(d->fd); - d->fd = -1; - } - return attempts != successes; } @@ -2406,8 +2484,12 @@ static int write_init_super_ddf(struct supertype *st) /* FIXME I need to close the fds! */ return 0; - } else - return __write_init_super_ddf(st, 1); + } else { + 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); + } } #endif @@ -2480,7 +2562,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) @@ -2520,13 +2602,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) { @@ -2541,10 +2623,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); } @@ -2571,7 +2657,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; } @@ -2635,7 +2721,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); @@ -2688,7 +2774,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) { @@ -2753,8 +2839,8 @@ static int validate_geometry_ddf_bvd(struct supertype *st, if ((S_IFMT & stb.st_mode) != S_IFBLK) return 0; for (dl = ddf->dlist ; dl ; dl = dl->next) { - if (dl->major == major(stb.st_rdev) && - dl->minor == minor(stb.st_rdev)) + if (dl->major == (int)major(stb.st_rdev) && + dl->minor == (int)minor(stb.st_rdev)) break; } if (!dl) { @@ -2782,7 +2868,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; @@ -2791,14 +2877,8 @@ static int load_super_ddf_all(struct supertype *st, int fd, int seq; char nm[20]; int dfd; - int devnum = fd2devnum(fd); - enum sysfs_read_flags flags; - - flags = GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE; - if (mdmon_running(devnum)) - flags |= SKIP_GONE_DEVS; - sra = sysfs_read(fd, 0, flags); + sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE); if (!sra) return 1; if (sra->array.major_version != -1 || @@ -2844,38 +2924,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]) { - struct vcl *v; - for (v = super->conflist; v; v = v->next) - if (v->vcnum == atoi(st->subarray)) - super->currentconf = v; - if (!super->currentconf) - 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 @@ -2891,9 +2968,17 @@ static struct mdinfo *container_content_ddf(struct supertype *st) for (vc = ddf->conflist ; vc ; vc=vc->next) { - int i; - int j; + unsigned int i; + unsigned int j; struct mdinfo *this; + char *ep; + __u32 *cptr; + + if (subarray && + (strtoul(subarray, &ep, 10) != vc->vcnum || + *ep != '\0')) + continue; + this = malloc(sizeof(*this)); memset(this, 0, sizeof(*this)); this->next = rest; @@ -2907,8 +2992,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; @@ -2942,13 +3027,28 @@ static struct mdinfo *container_content_ddf(struct supertype *st) devnum2devname(st->container_dev), this->container_member); - for (i=0 ; i < ddf->mppe ; i++) { + for (i = 0 ; i < ddf->mppe ; i++) { struct mdinfo *dev; struct dl *d; + int stt; + int pd; if (vc->conf.phys_refnum[i] == 0xFFFFFFFF) continue; + for (pd = __be16_to_cpu(ddf->phys->used_pdes); + pd--;) + if (ddf->phys->entries[pd].refnum + == vc->conf.phys_refnum[i]) + break; + if (pd < 0) + continue; + + stt = __be16_to_cpu(ddf->phys->entries[pd].state); + if ((stt & (DDF_Online|DDF_Failed|DDF_Rebuilding)) + != DDF_Online) + continue; + this->array.working_disks++; for (d = ddf->dlist; d ; d=d->next) @@ -2968,6 +3068,7 @@ static struct mdinfo *container_content_ddf(struct supertype *st) dev->disk.minor = d->minor; dev->disk.raid_disk = i; dev->disk.state = (1<recovery_start = MaxSector; dev->events = __be32_to_cpu(ddf->primary.seq); dev->data_offset = __be64_to_cpu(vc->lba_offset[i]); @@ -3092,6 +3193,9 @@ static int ddf_set_array_state(struct active_array *a, int consistent) return consistent; } +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) /* * The state of each disk is stored in the global phys_disk structure * in phys_disk.entries[n].state. @@ -3109,24 +3213,47 @@ static int ddf_set_array_state(struct active_array *a, int consistent) static void ddf_set_disk(struct active_array *a, int n, int state) { struct ddf_super *ddf = a->container->sb; - int inst = a->info.container_member; + unsigned int inst = a->info.container_member; struct vd_config *vc = find_vdcr(ddf, inst); int pd = find_phys(ddf, vc->phys_refnum[n]); int i, st, working; + struct mdinfo *mdi; + struct dl *dl; if (vc == NULL) { dprintf("ddf: cannot find instance %d!!\n", inst); return; } - if (pd < 0) { - /* disk doesn't currently exist. If it is now in_sync, - * insert it. */ + /* Find the matching slot in 'info'. */ + for (mdi = a->info.devs; mdi; mdi = mdi->next) + if (mdi->disk.raid_disk == n) + break; + if (!mdi) + return; + + /* and find the 'dl' entry corresponding to that. */ + for (dl = ddf->dlist; dl; dl = dl->next) + if (mdi->state_fd >= 0 && + mdi->disk.major == dl->major && + mdi->disk.minor == dl->minor) + break; + if (!dl) + return; + + if (pd < 0 || pd != dl->pdnum) { + /* disk doesn't currently exist or has changed. + * If it is now in_sync, insert it. */ if ((state & DS_INSYNC) && ! (state & DS_FAULTY)) { - /* Find dev 'n' in a->info->devs, determine the - * ddf refnum, and set vc->phys_refnum and update - * phys->entries[] - */ - /* FIXME */ + struct vcl *vcl; + pd = dl->pdnum; + vc->phys_refnum[n] = dl->disk.refnum; + vcl = container_of(vc, struct vcl, conf); + vcl->lba_offset[n] = mdi->data_offset; + ddf->phys->entries[pd].type &= + ~__cpu_to_be16(DDF_Global_Spare); + ddf->phys->entries[pd].type |= + __cpu_to_be16(DDF_Active_in_VD); + ddf->updates_pending = 1; } } else { int old = ddf->phys->entries[pd].state; @@ -3169,6 +3296,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: @@ -3209,7 +3338,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"); } @@ -3221,8 +3350,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. @@ -3250,8 +3379,9 @@ static void ddf_process_update(struct supertype *st, struct vd_config *vc; struct vcl *vcl; struct dl *dl; - int mppe; - int ent; + unsigned int mppe; + unsigned int ent; + unsigned int pdnum, pd2; dprintf("Process update %x\n", *magic); @@ -3266,6 +3396,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]; @@ -3310,7 +3459,7 @@ static void ddf_process_update(struct supertype *st, dprintf("len %d %d\n", update->len, ddf->conf_rec_len); mppe = __be16_to_cpu(ddf->anchor.max_primary_element_entries); - if (update->len != ddf->conf_rec_len * 512) + if ((unsigned)update->len != ddf->conf_rec_len * 512) return; vc = (struct vd_config*)update->buf; for (vcl = ddf->conflist; vcl ; vcl = vcl->next) @@ -3333,19 +3482,48 @@ static void ddf_process_update(struct supertype *st, memcpy(&vcl->conf, vc, update->len); vcl->lba_offset = (__u64*) &vcl->conf.phys_refnum[mppe]; + for (ent = 0; + ent < __be16_to_cpu(ddf->virt->populated_vdes); + ent++) + if (memcmp(vc->guid, ddf->virt->entries[ent].guid, + DDF_GUID_LEN) == 0) { + vcl->vcnum = ent; + break; + } ddf->conflist = vcl; } + /* Set DDF_Transition on all Failed devices - to help + * us detect those that are no longer in use + */ + for (pdnum = 0; pdnum < __be16_to_cpu(ddf->phys->used_pdes); pdnum++) + if (ddf->phys->entries[pdnum].state + & __be16_to_cpu(DDF_Failed)) + ddf->phys->entries[pdnum].state + |= __be16_to_cpu(DDF_Transition); /* Now make sure vlist is correct for each dl. */ for (dl = ddf->dlist; dl; dl = dl->next) { - int dn; - int vn = 0; + unsigned int dn; + unsigned int vn = 0; + int in_degraded = 0; for (vcl = ddf->conflist; vcl ; vcl = vcl->next) for (dn=0; dn < ddf->mppe ; dn++) if (vcl->conf.phys_refnum[dn] == dl->disk.refnum) { + int vstate; dprintf("dev %d has %p at %d\n", dl->pdnum, vcl, vn); + /* Clear the Transition flag */ + if (ddf->phys->entries[dl->pdnum].state + & __be16_to_cpu(DDF_Failed)) + ddf->phys->entries[dl->pdnum].state &= + ~__be16_to_cpu(DDF_Transition); + dl->vlist[vn++] = vcl; + vstate = ddf->virt->entries[vcl->vcnum].state + & DDF_state_mask; + if (vstate == DDF_state_degraded || + vstate == DDF_state_part_optimal) + in_degraded = 1; break; } while (vn < ddf->max_part) @@ -3353,8 +3531,14 @@ static void ddf_process_update(struct supertype *st, if (dl->vlist[0]) { ddf->phys->entries[dl->pdnum].type &= ~__cpu_to_be16(DDF_Global_Spare); - ddf->phys->entries[dl->pdnum].type |= - __cpu_to_be16(DDF_Active_in_VD); + if (!(ddf->phys->entries[dl->pdnum].type & + __cpu_to_be16(DDF_Active_in_VD))) { + ddf->phys->entries[dl->pdnum].type |= + __cpu_to_be16(DDF_Active_in_VD); + if (in_degraded) + ddf->phys->entries[dl->pdnum].state |= + __cpu_to_be16(DDF_Rebuilding); + } } if (dl->spare) { ddf->phys->entries[dl->pdnum].type &= @@ -3370,6 +3554,33 @@ static void ddf_process_update(struct supertype *st, DDF_Active_in_VD); } } + + /* Now remove any 'Failed' devices that are not part + * of any VD. They will have the Transition flag set. + * Once done, we need to update all dl->pdnum numbers. + */ + pd2 = 0; + for (pdnum = 0; pdnum < __be16_to_cpu(ddf->phys->used_pdes); pdnum++) + if ((ddf->phys->entries[pdnum].state + & __be16_to_cpu(DDF_Failed)) + && (ddf->phys->entries[pdnum].state + & __be16_to_cpu(DDF_Transition))) + /* skip this one */; + else if (pdnum == pd2) + pd2++; + else { + ddf->phys->entries[pd2] = ddf->phys->entries[pdnum]; + for (dl = ddf->dlist; dl; dl = dl->next) + if (dl->pdnum == (int)pdnum) + dl->pdnum = pd2; + pd2++; + } + ddf->phys->used_pdes = __cpu_to_be16(pd2); + while (pd2 < pdnum) { + memset(ddf->phys->entries[pd2].guid, 0xff, DDF_GUID_LEN); + pd2++; + } + ddf->updates_pending = 1; break; case DDF_SPARE_ASSIGN_MAGIC: @@ -3473,10 +3684,11 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, int is_global = 0; int is_dedicated = 0; struct extent *ex; - int j; + unsigned int j; /* If in this array, skip */ for (d2 = a->info.devs ; d2 ; d2 = d2->next) - if (d2->disk.major == dl->major && + if (d2->state_fd >= 0 && + d2->disk.major == dl->major && d2->disk.minor == dl->minor) { dprintf("%x:%x already in array\n", dl->major, dl->minor); break; @@ -3525,13 +3737,14 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, esize = ex[j].start - pos; if (esize >= a->info.component_size) break; - pos = ex[i].start + ex[i].size; - i++; - } while (ex[i-1].size); + pos = ex[j].start + ex[j].size; + j++; + } while (ex[j-1].size); free(ex); if (esize < a->info.component_size) { - dprintf("%x:%x has no room: %llu %llu\n", dl->major, dl->minor, + dprintf("%x:%x has no room: %llu %llu\n", + dl->major, dl->minor, esize, a->info.component_size); /* No room */ continue; @@ -3547,6 +3760,7 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, di->disk.major = dl->major; di->disk.minor = dl->minor; di->disk.state = 0; + di->recovery_start = 0; di->data_offset = pos; di->component_size = a->info.component_size; di->container_member = dl->pdnum; @@ -3588,7 +3802,9 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, } mu->buf = malloc(ddf->conf_rec_len * 512); - mu->len = ddf->conf_rec_len; + 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); @@ -3622,6 +3838,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, @@ -3633,6 +3858,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, @@ -3649,7 +3876,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,