X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=super-ddf.c;h=b01c68d5a40b4472b74595c7693d705871e82f04;hb=fd547b508c90a647cf60df678047f07046cf5c68;hp=b0218016e25a2c75efb5548fbd048b37e09b1494;hpb=b640a252ee4d0c7be9ab31d9300aec00571b6238;p=thirdparty%2Fmdadm.git diff --git a/super-ddf.c b/super-ddf.c index b0218016..b01c68d5 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -1,7 +1,7 @@ /* * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2006-2007 Neil Brown + * Copyright (C) 2006-2009 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -643,6 +643,7 @@ static int load_ddf_local(int fd, struct ddf_super *super, struct stat stb; char *conf; int i; + int confsec; int vnum; int max_virt_disks = __be16_to_cpu(super->active->max_vd_entries); unsigned long long dsize; @@ -693,11 +694,11 @@ static int load_ddf_local(int fd, struct ddf_super *super, 0); vnum = 0; - for (i = 0; - i < __be32_to_cpu(super->active->config_section_length); - i += super->conf_rec_len) { + for (confsec = 0; + confsec < __be32_to_cpu(super->active->config_section_length); + confsec += super->conf_rec_len) { struct vd_config *vd = - (struct vd_config *)((char*)conf + i*512); + (struct vd_config *)((char*)conf + confsec*512); struct vcl *vcl; if (vd->magic == DDF_SPARE_ASSIGN_MAGIC) { @@ -761,6 +762,9 @@ static int load_ddf_local(int fd, struct ddf_super *super, static int load_super_ddf_all(struct supertype *st, int fd, void **sbp, char *devname, int keep_fd); #endif + +static void free_super_ddf(struct supertype *st); + static int load_super_ddf(struct supertype *st, int fd, char *devname) { @@ -779,26 +783,30 @@ static int load_super_ddf(struct supertype *st, int fd, 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) { + if (devname) fprintf(stderr, Name ": %s is too small for ddf: " "size is %llu sectors.\n", devname, dsize>>9); - return 1; - } + return 1; } if (dsize & 511) { - if (devname) { + if (devname) fprintf(stderr, Name ": %s is an odd size for ddf: " "size is %llu bytes.\n", devname, dsize); - return 1; - } + return 1; } + free_super_ddf(st); + if (posix_memalign((void**)&super, 512, sizeof(*super))!= 0) { fprintf(stderr, Name ": malloc of %zu failed.\n", sizeof(*super)); @@ -836,6 +844,18 @@ 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; @@ -1000,7 +1020,7 @@ static void print_guid(char *guid, int tstamp) printf("%02X", guid[i]&255); } - printf(" ("); + printf("\n ("); while (l && guid[l-1] == ' ') l--; for (i=0 ; isrl) ?: "-unknown-"); } printf(" Device Size[%d] : %llu\n", n, - __be64_to_cpu(vc->blocks)/2); + (unsigned long long)__be64_to_cpu(vc->blocks)/2); printf(" Array Size[%d] : %llu\n", n, - __be64_to_cpu(vc->array_blocks)/2); + (unsigned long long)__be64_to_cpu(vc->array_blocks)/2); } } @@ -1100,7 +1120,7 @@ static void examine_pds(struct ddf_super *sb) int i; struct dl *dl; printf(" Physical Disks : %d\n", cnt); - printf(" Number RefNo Size Device Type/State\n"); + printf(" Number RefNo Size Device Type/State\n"); for (i=0 ; iphys->entries[i]; @@ -1111,18 +1131,19 @@ static void examine_pds(struct ddf_super *sb) //printf("\n"); printf(" %3d %08x ", i, __be32_to_cpu(pd->refnum)); - printf("%lluK ", __be64_to_cpu(pd->config_size)>>1); + printf("%8lluK ", + (unsigned long long)__be64_to_cpu(pd->config_size)>>1); for (dl = sb->dlist; dl ; dl = dl->next) { if (dl->disk.refnum == pd->refnum) { char *dv = map_dev(dl->major, dl->minor, 0); if (dv) { - printf("%-10s", dv); + printf("%-15s", dv); break; } } } if (!dl) - printf("%10s",""); + printf("%15s",""); printf(" %s%s%s%s%s", (type&2) ? "active":"", (type&4) ? "Global-Spare":"", @@ -1162,7 +1183,19 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info); static void uuid_from_super_ddf(struct supertype *st, int uuid[4]); -static void brief_examine_super_ddf(struct supertype *st) +static void brief_examine_super_ddf(struct supertype *st, int verbose) +{ + /* We just write a generic DDF ARRAY entry + */ + struct mdinfo info; + char nbuf[64]; + getinfo_super_ddf(st, &info); + fname_from_uuid(st, &info, nbuf, ':'); + + printf("ARRAY metadata=ddf UUID=%s\n", nbuf + 5); +} + +static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) { /* We just write a generic DDF ARRAY entry */ @@ -1172,7 +1205,6 @@ static void brief_examine_super_ddf(struct supertype *st) char nbuf[64]; getinfo_super_ddf(st, &info); fname_from_uuid(st, &info, nbuf, ':'); - printf("ARRAY metadata=ddf UUID=%s\n", nbuf + 5); for (i=0; i<__be16_to_cpu(ddf->virt->max_vdes); i++) { struct virtual_entry *ve = &ddf->virt->entries[i]; @@ -1189,6 +1221,18 @@ static void brief_examine_super_ddf(struct supertype *st) } } +static void export_examine_super_ddf(struct supertype *st) +{ + struct mdinfo info; + char nbuf[64]; + getinfo_super_ddf(st, &info); + fname_from_uuid(st, &info, nbuf, ':'); + printf("MD_METADATA=ddf\n"); + printf("MD_LEVEL=container\n"); + printf("MD_UUID=%s\n", nbuf+5); +} + + static void detail_super_ddf(struct supertype *st, char *homehost) { /* FIXME later @@ -1220,7 +1264,11 @@ static int match_home_ddf(struct supertype *st, char *homehost) * the hostname */ struct ddf_super *ddf = st->sb; - int len = strlen(homehost); + int len; + + if (!homehost) + return 0; + len = strlen(homehost); return (memcmp(ddf->controller.guid, T10, 8) == 0 && len < sizeof(ddf->controller.vendor_data) && @@ -1309,6 +1357,7 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) (ddf->anchor.guid+16)); info->array.utime = 0; info->array.chunk_size = 0; + info->container_enough = 0; info->disk.major = 0; @@ -1323,11 +1372,13 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info) info->component_size = ddf->dlist->size - info->data_offset; } else { info->disk.number = -1; + info->disk.raid_disk = -1; // info->disk.raid_disk = find refnum in the table and use index; } - info->disk.state = (1 << MD_DISK_SYNC); + info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + info->recovery_start = MaxSector; info->reshape_active = 0; info->name[0] = 0; @@ -1361,6 +1412,7 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) __be32_to_cpu(*(__u32*)(vc->conf.guid+16)); 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) { info->data_offset = __be64_to_cpu(vc->lba_offset[cd]); @@ -1385,13 +1437,15 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info) info->container_member = ddf->currentconf->vcnum; + info->recovery_start = MaxSector; info->resync_start = 0; + info->reshape_active = 0; if (!(ddf->virt->entries[info->container_member].state & DDF_state_inconsistent) && (ddf->virt->entries[info->container_member].init_state & DDF_initstate_mask) == DDF_init_full) - info->resync_start = ~0ULL; + info->resync_start = MaxSector; uuid_from_super_ddf(st, info->uuid); @@ -1484,7 +1538,6 @@ static int update_super_ddf(struct supertype *st, struct mdinfo *info, static void make_header_guid(char *guid) { __u32 stamp; - int rfd; /* Create a DDF Header of Virtual Disk GUID */ /* 24 bytes of fiction required. @@ -1499,11 +1552,8 @@ static void make_header_guid(char *guid) memcpy(guid+12, &stamp, 4); stamp = __cpu_to_be32(time(0) - DECADE); memcpy(guid+16, &stamp, 4); - rfd = open("/dev/urandom", O_RDONLY); - if (rfd < 0 || read(rfd, &stamp, 4) != 4) - stamp = random(); + stamp = random32(); memcpy(guid+20, &stamp, 4); - if (rfd >= 0) close(rfd); } static int init_super_ddf_bvd(struct supertype *st, @@ -1551,13 +1601,8 @@ static int init_super_ddf(struct supertype *st, struct phys_disk *pd; struct virtual_disk *vd; - if (!info) { - st->sb = NULL; - return 0; - } if (st->sb) - return init_super_ddf_bvd(st, info, size, name, homehost, - uuid); + 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__); @@ -1566,6 +1611,12 @@ static int init_super_ddf(struct supertype *st, memset(ddf, 0, sizeof(*ddf)); ddf->dlist = NULL; /* no physical disks yet */ ddf->conflist = NULL; /* No virtual disks yet */ + st->sb = ddf; + + if (info == NULL) { + /* zeroing superblock */ + return 0; + } /* At least 32MB *must* be reserved for the ddf. So let's just * start 32MB from the end, and put the primary header there. @@ -1700,7 +1751,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); @@ -1982,7 +2033,7 @@ static int init_super_ddf_bvd(struct supertype *st, memset(vc->vendor, 0xff, 32); memset(vc->phys_refnum, 0xff, 4*ddf->mppe); - memset(vc->phys_refnum+(ddf->mppe * 4), 0x00, 8*ddf->mppe); + memset(vc->phys_refnum+ddf->mppe, 0x00, 8*ddf->mppe); vcl->next = ddf->conflist; ddf->conflist = vcl; @@ -2136,12 +2187,12 @@ 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) = random(); - *(__u32*)(dd->disk.guid + 20) = random(); + *(__u32*)(dd->disk.guid + 16) = random32(); + *(__u32*)(dd->disk.guid + 20) = random32(); do { /* Cannot be bothered finding a CRC of some irrelevant details*/ - dd->disk.refnum = random(); + 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) @@ -2324,15 +2375,19 @@ 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; + struct vcl *currentconf = ddf->currentconf; + + /* we are done with currentconf reset it to point st at the container */ + ddf->currentconf = NULL; if (st->update_tail) { /* queue the virtual_disk and vd_config as metadata updates */ struct virtual_disk *vd; struct vd_config *vc; - struct ddf_super *ddf = st->sb; int len; - if (!ddf->currentconf) { + if (!currentconf) { int len = (sizeof(struct phys_disk) + sizeof(struct phys_disk_entry)); @@ -2351,20 +2406,24 @@ static int write_init_super_ddf(struct supertype *st) len = sizeof(struct virtual_disk) + sizeof(struct virtual_entry); vd = malloc(len); *vd = *ddf->virt; - vd->entries[0] = ddf->virt->entries[ddf->currentconf->vcnum]; - vd->populated_vdes = __cpu_to_be16(ddf->currentconf->vcnum); + vd->entries[0] = ddf->virt->entries[currentconf->vcnum]; + vd->populated_vdes = __cpu_to_be16(currentconf->vcnum); append_metadata_update(st, vd, len); /* Then the vd_config */ len = ddf->conf_rec_len * 512; vc = malloc(len); - memcpy(vc, &ddf->currentconf->conf, len); + memcpy(vc, ¤tconf->conf, len); append_metadata_update(st, vc, len); /* FIXME I need to close the fds! */ return 0; - } else + } 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, 1); + } } #endif @@ -2512,8 +2571,12 @@ static int validate_geometry_ddf(struct supertype *st, for (i=0; ddf_level_num[i].num1 != MAXINT; i++) if (ddf_level_num[i].num2 == level) break; - if (ddf_level_num[i].num1 == MAXINT) + if (ddf_level_num[i].num1 == MAXINT) { + if (verbose) + fprintf(stderr, Name ": DDF does not support level %d arrays\n", + level); return 0; + } /* Should check layout? etc */ if (st->sb && freesize) { @@ -2561,7 +2624,7 @@ static int validate_geometry_ddf(struct supertype *st, if (verbose) fprintf(stderr, Name ": ddf: Cannot create this array " - "on device %s\n", + "on device %s - a container is required.\n", dev); return 0; } @@ -2633,6 +2696,8 @@ validate_geometry_ddf_container(struct supertype *st, close(fd); *freesize = avail_size_ddf(st, ldsize >> 9); + if (*freesize == 0) + return 0; return 1; } @@ -2651,8 +2716,11 @@ static int validate_geometry_ddf_bvd(struct supertype *st, struct extent *e; int i; /* ddf/bvd supports lots of things, but not containers */ - if (level == LEVEL_CONTAINER) + if (level == LEVEL_CONTAINER) { + if (verbose) + fprintf(stderr, Name ": DDF cannot create a container within an container\n"); return 0; + } /* We must have the container info already read in. */ if (!ddf) return 0; @@ -2869,7 +2937,7 @@ static struct mdinfo *container_content_ddf(struct supertype *st) this->resync_start = 0; } else { this->array.state = 1; - this->resync_start = ~0ULL; + this->resync_start = MaxSector; } memcpy(this->name, ddf->virt->entries[i].name, 16); this->name[16]=0; @@ -2903,7 +2971,8 @@ static struct mdinfo *container_content_ddf(struct supertype *st) if (d->disk.refnum == vc->conf.phys_refnum[i]) break; if (d == NULL) - break; + /* Haven't found that one yet, maybe there are others */ + continue; dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); @@ -2915,6 +2984,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]); @@ -2926,12 +2996,22 @@ static struct mdinfo *container_content_ddf(struct supertype *st) return rest; } -static int store_zero_ddf(struct supertype *st, int fd) +static int store_super_ddf(struct supertype *st, int fd) { + struct ddf_super *ddf = st->sb; unsigned long long dsize; void *buf; int rc; + if (!ddf) + return 1; + + /* ->dlist and ->conflist will be set for updates, currently not + * supported + */ + if (ddf->dlist || ddf->conflist) + return 1; + if (!get_dev_size(fd, NULL, &dsize)) return 1; @@ -3003,7 +3083,7 @@ static int ddf_set_array_state(struct active_array *a, int consistent) if (consistent == 2) { /* Should check if a recovery should be started FIXME */ consistent = 1; - if (!is_resync_complete(a)) + if (!is_resync_complete(&a->info)) consistent = 0; } if (consistent) @@ -3015,9 +3095,9 @@ static int ddf_set_array_state(struct active_array *a, int consistent) old = ddf->virt->entries[inst].init_state; ddf->virt->entries[inst].init_state &= ~DDF_initstate_mask; - if (is_resync_complete(a)) + if (is_resync_complete(&a->info)) ddf->virt->entries[inst].init_state |= DDF_init_full; - else if (a->resync_start == 0) + else if (a->info.resync_start == 0) ddf->virt->entries[inst].init_state |= DDF_init_not; else ddf->virt->entries[inst].init_state |= DDF_init_quick; @@ -3025,7 +3105,7 @@ static int ddf_set_array_state(struct active_array *a, int consistent) ddf->updates_pending = 1; dprintf("ddf mark %d %s %llu\n", inst, consistent?"clean":"dirty", - a->resync_start); + a->info.resync_start); return consistent; } @@ -3484,6 +3564,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; @@ -3563,6 +3644,8 @@ struct superswitch super_ddf = { #ifndef MDASSEMBLE .examine_super = examine_super_ddf, .brief_examine_super = brief_examine_super_ddf, + .brief_examine_subarrays = brief_examine_subarrays_ddf, + .export_examine_super = export_examine_super_ddf, .detail_super = detail_super_ddf, .brief_detail_super = brief_detail_super_ddf, .validate_geometry = validate_geometry_ddf, @@ -3580,7 +3663,7 @@ struct superswitch super_ddf = { .load_super = load_super_ddf, .init_super = init_super_ddf, - .store_super = store_zero_ddf, + .store_super = store_super_ddf, .free_super = free_super_ddf, .match_metadata_desc = match_metadata_desc_ddf, .container_content = container_content_ddf,