#include "mdmon.h"
#include "sha1.h"
#include <values.h>
+#include <stddef.h>
/* a non-official T10 name for creation GUIDs */
static char T10[] = "Linux-MD";
* for concat I hope) */
be64 array_blocks; /* blocks in array */
__u8 pad1[8];
- be32 spare_refs[8];
+ be32 spare_refs[8]; /* This is used to detect missing spares.
+ * As we don't have an interface for that
+ * the values are ignored.
+ */
__u8 cache_pol[8];
__u8 bg_rate;
__u8 pad2[3];
} *dlist, *add_list;
};
-#ifndef MDASSEMBLE
static int load_super_ddf_all(struct supertype *st, int fd,
void **sbp, char *devname);
static int get_svd_state(const struct ddf_super *, const struct vcl *);
unsigned long long data_offset,
char *dev, unsigned long long *freesize,
int verbose);
-#endif
static void free_super_ddf(struct supertype *st);
static int all_ff(const char *guid);
char *name, char *homehost,
int *uuid, unsigned long long data_offset);
-#ifndef offsetof
-#define offsetof(t,f) ((size_t)&(((t*)0)->f))
-#endif
-
#if DEBUG
static void pr_state(struct ddf_super *ddf, const char *msg)
{
unsigned int i;
- dprintf("%s/%s: ", __func__, msg);
+ dprintf("%s: ", msg);
for (i = 0; i < be16_to_cpu(ddf->active->max_vd_entries); i++) {
if (all_ff(ddf->virt->entries[i].guid))
continue;
- dprintf("%u(s=%02x i=%02x) ", i,
+ dprintf_cont("%u(s=%02x i=%02x) ", i,
ddf->virt->entries[i].state,
ddf->virt->entries[i].init_state);
}
- dprintf("\n");
+ dprintf_cont("\n");
}
#else
static void pr_state(const struct ddf_super *ddf, const char *msg) {}
rlq = DDF_RAID1_SIMPLE;
prim_elmnt_count = cpu_to_be16(2);
sec_elmnt_count = array->raid_disks / 2;
+ srl = DDF_2SPANNED;
+ prl = DDF_RAID1;
} else if (array->raid_disks % 3 == 0
&& array->layout == 0x103) {
rlq = DDF_RAID1_MULTI;
prim_elmnt_count = cpu_to_be16(3);
sec_elmnt_count = array->raid_disks / 3;
+ srl = DDF_2SPANNED;
+ prl = DDF_RAID1;
+ } else if (array->layout == 0x201) {
+ prl = DDF_RAID1E;
+ rlq = DDF_RAID1E_OFFSET;
+ } else if (array->layout == 0x102) {
+ prl = DDF_RAID1E;
+ rlq = DDF_RAID1E_ADJACENT;
} else
return err_bad_md_layout(array);
- srl = DDF_2SPANNED;
- prl = DDF_RAID1;
break;
default:
return err_bad_md_layout(array);
return err_bad_ddf_layout(conf);
level = 1;
break;
+ case DDF_RAID1E:
+ if (conf->rlq == DDF_RAID1E_ADJACENT)
+ layout = 0x102;
+ else if (conf->rlq == DDF_RAID1E_OFFSET)
+ layout = 0x201;
+ else
+ return err_bad_ddf_layout(conf);
+ level = 10;
+ break;
case DDF_RAID4:
if (conf->rlq != DDF_RAID4_N)
return err_bad_ddf_layout(conf);
return 0;
if (!be32_eq(hdr->magic, DDF_HEADER_MAGIC)) {
- pr_err("%s: bad header magic\n", __func__);
+ pr_err("bad header magic\n");
return 0;
}
if (!be32_eq(calc_crc(hdr, 512), hdr->crc)) {
- pr_err("%s: bad CRC\n", __func__);
+ pr_err("bad CRC\n");
return 0;
}
if (memcmp(anchor->guid, hdr->guid, DDF_GUID_LEN) != 0 ||
hdr->type != type ||
memcmp(anchor->pad2, hdr->pad2, 512 -
offsetof(struct ddf_header, pad2)) != 0) {
- pr_err("%s: header mismatch\n", __func__);
+ pr_err("header mismatch\n");
return 0;
}
if (memcmp(super->anchor.revision, DDF_REVISION_0, 8) != 0 &&
memcmp(super->anchor.revision, DDF_REVISION_2, 8) != 0) {
if (devname)
- pr_err("can only support super revision"
- " %.8s and earlier, not %.8s on %s\n",
+ pr_err("can only support super revision %.8s and earlier, not %.8s on %s\n",
DDF_REVISION_2, super->anchor.revision,devname);
return 2;
}
dsize >> 9, 1,
&super->primary, &super->anchor) == 0) {
if (devname)
- pr_err("Failed to load primary DDF header "
- "on %s\n", devname);
+ pr_err("Failed to load primary DDF header on %s\n", devname);
} else
super->active = &super->primary;
if (posix_memalign((void**)&dl, 512,
sizeof(*dl) +
(super->max_part) * sizeof(dl->vlist[0])) != 0) {
- pr_err("%s could not allocate disk info buffer\n",
- __func__);
+ pr_err("could not allocate disk info buffer\n");
return 1;
}
continue;
if (posix_memalign((void**)&dl->spare, 512,
super->conf_rec_len*512) != 0) {
- pr_err("%s could not allocate spare info buf\n",
- __func__);
+ pr_err("could not allocate spare info buf\n");
return 1;
}
if (posix_memalign((void**)&vcl, 512,
(super->conf_rec_len*512 +
offsetof(struct vcl, conf))) != 0) {
- pr_err("%s could not allocate vcl buf\n",
- __func__);
+ pr_err("could not allocate vcl buf\n");
return 1;
}
vcl->next = super->conflist;
vcl->block_sizes = NULL; /* FIXME not for CONCAT */
vcl->conf.sec_elmnt_count = vd->sec_elmnt_count;
if (alloc_other_bvds(super, vcl) != 0) {
- pr_err("%s could not allocate other bvds\n",
- __func__);
+ pr_err("could not allocate other bvds\n");
free(vcl);
return 1;
};
/* 32M is a lower bound */
if (dsize <= 32*1024*1024) {
if (devname)
- pr_err("%s is too small for ddf: "
- "size is %llu sectors.\n",
+ pr_err("%s is too small for ddf: size is %llu sectors.\n",
devname, dsize>>9);
return 1;
}
if (dsize & 511) {
if (devname)
- pr_err("%s is an odd size for ddf: "
- "size is %llu bytes.\n",
+ pr_err("%s is an odd size for ddf: size is %llu bytes.\n",
devname, dsize);
return 1;
}
if (rv) {
if (devname)
- pr_err("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 (rv) {
if (devname)
- pr_err("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;
}
return st;
}
-#ifndef MDASSEMBLE
-
static mapping_t ddf_state[] = {
{ "Optimal", 0},
{ "Degraded", 1},
{ "Spanned", DDF_2SPANNED},
{ NULL, 0}
};
-#endif
static int all_ff(const char *guid)
{
return (const char *) buf;
}
-#ifndef MDASSEMBLE
static void print_guid(char *guid, int tstamp)
{
/* A GUIDs are part (or all) ASCII and part binary.
printf("%d", j);
else
printf("--");
+ printf("@%lluK", (unsigned long long) be64_to_cpu(LBA_OFFSET(sb, vc)[i])/2);
}
printf(")\n");
if (vc->chunk_shift != 255)
static void detail_super_ddf(struct supertype *st, char *homehost)
{
- /* FIXME later
- * Could print DDF GUID
- * Need to find which array
- * If whole, briefly list all arrays
- * If one, give name
- */
+ struct ddf_super *sb = st->sb;
+ int cnt = be16_to_cpu(sb->virt->populated_vdes);
+
+ printf(" Container GUID : "); print_guid(sb->anchor.guid, 1);
+ printf("\n");
+ printf(" Seq : %08x\n", be32_to_cpu(sb->active->seq));
+ printf(" Virtual Disks : %d\n", cnt);
+ printf("\n");
}
static const char *vendors_with_variable_volume_UUID[] = {
fname_from_uuid(st, &info, nbuf,':');
printf(" UUID=%s", nbuf + 5);
}
-#endif
static int match_home_ddf(struct supertype *st, char *homehost)
{
ddf->controller.vendor_data[len] == 0);
}
-#ifndef MDASSEMBLE
static int find_index_in_bvd(const struct ddf_super *ddf,
const struct vd_config *conf, unsigned int n,
unsigned int *n_bvd)
j++;
}
}
- dprintf("%s: couldn't find BVD member %u (total %u)\n",
- __func__, n, be16_to_cpu(conf->prim_elmnt_count));
+ dprintf("couldn't find BVD member %u (total %u)\n",
+ n, be16_to_cpu(conf->prim_elmnt_count));
return 0;
}
goto bad;
}
if (v->other_bvds == NULL) {
- pr_err("%s: BUG: other_bvds is NULL, nsec=%u\n",
- __func__, conf->sec_elmnt_count);
+ pr_err("BUG: other_bvds is NULL, nsec=%u\n",
+ conf->sec_elmnt_count);
goto bad;
}
nsec = n / be16_to_cpu(conf->prim_elmnt_count);
if (!find_index_in_bvd(ddf, conf,
n - nsec*conf->sec_elmnt_count, n_bvd))
goto bad;
- dprintf("%s: found disk %u as member %u in bvd %d of array %u\n"
- , __func__, n, *n_bvd, ibvd, inst);
+ dprintf("found disk %u as member %u in bvd %d of array %u\n",
+ n, *n_bvd, ibvd, inst);
*vcl = v;
return conf;
}
bad:
- pr_err("%s: Could't find disk %d in array %u\n", __func__, n, inst);
+ pr_err("Could't find disk %d in array %u\n", n, inst);
return NULL;
}
-#endif
static int find_phys(const struct ddf_super *ddf, be32 phys_refnum)
{
if (info->disk.raid_disk >= 0)
pde = ddf->phys->entries + info->disk.raid_disk;
if (pde &&
- !(be16_to_cpu(pde->state) & DDF_Failed))
+ !(be16_to_cpu(pde->state) & DDF_Failed) &&
+ !(be16_to_cpu(pde->state) & DDF_Missing))
info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
else
info->disk.state = 1 << MD_DISK_FAULTY;
} else {
+ /* There should always be a dlist, but just in case...*/
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) | (1 << MD_DISK_ACTIVE);
}
info->events = be32_to_cpu(ddf->active->seq);
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)
+ int i, e = 0;
+ int max = be16_to_cpu(ddf->phys->max_pdes);
+ for (i = e = 0 ; i < map_disks ; i++, e++) {
+ while (e < max &&
+ be32_to_cpu(ddf->phys->entries[e].refnum) == 0xffffffff)
+ e++;
+ if (i < info->array.raid_disks && e < max &&
+ !(be16_to_cpu(ddf->phys->entries[e].state)
& DDF_Failed))
map[i] = 1;
else
int cd = ddf->currentdev;
int n_prim;
int j;
- struct dl *dl;
+ struct dl *dl = NULL;
int map_disks = info->array.raid_disks;
__u32 *cptr;
struct vd_config *conf;
return DDF_NOTFOUND;
}
-#ifndef MDASSEMBLE
static unsigned int find_vde_by_guid(const struct ddf_super *ddf,
const char *guid)
{
return i;
return DDF_NOTFOUND;
}
-#endif
static int init_super_ddf(struct supertype *st,
mdu_array_info_t *info,
- unsigned long long size, char *name, char *homehost,
+ struct shape *s, char *name, char *homehost,
int *uuid, unsigned long long data_offset)
{
/* This is primarily called by Create when creating a new array.
struct phys_disk *pd;
struct virtual_disk *vd;
- if (data_offset != INVALID_SECTORS) {
- pr_err("data-offset not supported by DDF\n");
- return 0;
- }
-
if (st->sb)
- return init_super_ddf_bvd(st, info, size, name, homehost, uuid,
+ return init_super_ddf_bvd(st, info, s->size, name, homehost, uuid,
data_offset);
if (posix_memalign((void**)&ddf, 512, sizeof(*ddf)) != 0) {
- pr_err("%s could not allocate superblock\n", __func__);
+ pr_err("could not allocate superblock\n");
return 0;
}
memset(ddf, 0, sizeof(*ddf));
strcpy((char*)ddf->controller.vendor_data, homehost);
if (posix_memalign((void**)&pd, 512, pdsize) != 0) {
- pr_err("%s could not allocate pd\n", __func__);
+ pr_err("could not allocate pd\n");
return 0;
}
ddf->phys = pd;
memset(pd->entries[i].guid, 0xff, DDF_GUID_LEN);
if (posix_memalign((void**)&vd, 512, vdsize) != 0) {
- pr_err("%s could not allocate vd\n", __func__);
+ pr_err("could not allocate vd\n");
return 0;
}
ddf->virt = vd;
return ffs(chunksize/512)-1;
}
-#ifndef MDASSEMBLE
struct extent {
unsigned long long start, size;
};
static struct extent *get_extents(struct ddf_super *ddf, struct dl *dl)
{
- /* Find a list of used extents on the give physical device
+ /* Find a list of used extents on the given physical device
* (dnum) of the given ddf.
* Return a malloced array of 'struct extent'
*/
rv[n].size = 0;
return rv;
}
-#endif
+
+static unsigned long long find_space(
+ struct ddf_super *ddf, struct dl *dl,
+ unsigned long long data_offset,
+ unsigned long long *size)
+{
+ /* Find if the requested amount of space is available.
+ * If it is, return start.
+ * If not, set *size to largest space.
+ * If data_offset != INVALID_SECTORS, then the space must start
+ * at this location.
+ */
+ struct extent *e = get_extents(ddf, dl);
+ int i = 0;
+ unsigned long long pos = 0;
+ unsigned long long max_size = 0;
+
+ if (!e) {
+ *size = 0;
+ return INVALID_SECTORS;
+ }
+ do {
+ unsigned long long esize = e[i].start - pos;
+ if (data_offset != INVALID_SECTORS &&
+ pos <= data_offset &&
+ e[i].start > data_offset) {
+ pos = data_offset;
+ esize = e[i].start - pos;
+ }
+ if (data_offset != INVALID_SECTORS &&
+ pos != data_offset) {
+ i++;
+ continue;
+ }
+ if (esize >= *size) {
+ /* Found! */
+ free(e);
+ return pos;
+ }
+ if (esize > max_size)
+ max_size = esize;
+ pos = e[i].start + e[i].size;
+ i++;
+ } while (e[i-1].size);
+ *size = max_size;
+ free(e);
+ return INVALID_SECTORS;
+}
static int init_super_ddf_bvd(struct supertype *st,
mdu_array_info_t *info,
/* Now create a new vd_config */
if (posix_memalign((void**)&vcl, 512,
(offsetof(struct vcl, conf) + ddf->conf_rec_len * 512)) != 0) {
- pr_err("%s could not allocate vd_config\n", __func__);
+ pr_err("could not allocate vd_config\n");
return 0;
}
vcl->vcnum = venum;
vc->chunk_shift = chunk_to_shift(info->chunk_size);
if (layout_md2ddf(info, vc) == -1 ||
be16_to_cpu(vc->prim_elmnt_count) > ddf->mppe) {
- pr_err("%s: unsupported RAID level/layout %d/%d with %d disks\n",
- __func__, info->level, info->layout, info->raid_disks);
+ pr_err("unsupported RAID level/layout %d/%d with %d disks\n",
+ info->level, info->layout, info->raid_disks);
free(vcl);
return 0;
}
vc->sec_elmnt_seq = 0;
if (alloc_other_bvds(ddf, vcl) != 0) {
- pr_err("%s could not allocate other bvds\n",
- __func__);
+ pr_err("could not allocate other bvds\n");
free(vcl);
return 0;
}
- vc->blocks = cpu_to_be64(info->size * 2);
+ vc->blocks = cpu_to_be64(size * 2);
vc->array_blocks = cpu_to_be64(
calc_array_size(info->level, info->raid_disks, info->layout,
- info->chunk_size, info->size*2));
+ info->chunk_size, size * 2));
memset(vc->pad1, 0xff, 8);
vc->spare_refs[0] = cpu_to_be32(0xffffffff);
vc->spare_refs[1] = cpu_to_be32(0xffffffff);
return 1;
}
-#ifndef MDASSEMBLE
static void add_to_super_ddf_bvd(struct supertype *st,
- mdu_disk_info_t *dk, int fd, char *devname)
+ mdu_disk_info_t *dk, int fd, char *devname,
+ unsigned long long data_offset)
{
/* fd and devname identify a device within the ddf container (st).
* dk identifies a location in the new BVD.
struct ddf_super *ddf = st->sb;
struct vd_config *vc;
unsigned int i;
- unsigned long long blocks, pos, esize;
- struct extent *ex;
+ unsigned long long blocks, pos;
unsigned int raid_disk = dk->raid_disk;
if (fd == -1) {
raid_disk %= n;
}
- ex = get_extents(ddf, dl);
- if (!ex)
- return;
-
- i = 0; pos = 0;
blocks = be64_to_cpu(vc->blocks);
if (ddf->currentconf->block_sizes)
blocks = ddf->currentconf->block_sizes[dk->raid_disk];
- /* First-fit */
- do {
- esize = ex[i].start - pos;
- if (esize >= blocks)
- break;
- pos = ex[i].start + ex[i].size;
- i++;
- } while (ex[i-1].size);
-
- free(ex);
- if (esize < blocks)
+ pos = find_space(ddf, dl, data_offset, &blocks);
+ if (pos == INVALID_SECTORS)
return;
ddf->currentdev = dk->raid_disk;
cpu_to_be16(DDF_Global_Spare));
be16_set(ddf->phys->entries[dl->pdnum].type,
cpu_to_be16(DDF_Active_in_VD));
- dprintf("%s: added disk %d/%08x to VD %d/%s as disk %d\n",
- __func__, dl->pdnum, be32_to_cpu(dl->disk.refnum),
+ dprintf("added disk %d/%08x to VD %d/%s as disk %d\n",
+ dl->pdnum, be32_to_cpu(dl->disk.refnum),
ddf->currentconf->vcnum, guid_str(vc->guid),
dk->raid_disk);
ddf_set_updates_pending(ddf, vc);
if (t < cfs) {
__u64 wsp = cfs - t;
if (wsp > 1024*1024*2ULL && wsp > dl->size / 16) {
- pr_err("%s: %x:%x: workspace size 0x%llx too big, ignoring\n",
- __func__, dl->major, dl->minor, wsp);
+ pr_err("%x:%x: workspace size 0x%llx too big, ignoring\n",
+ dl->major, dl->minor, (unsigned long long)wsp);
} else
cfs = t;
}
pde->config_size = cpu_to_be64(cfs);
- dprintf("%s: %x:%x config_size %llx, DDF structure is %llx blocks\n",
- __func__, dl->major, dl->minor, cfs, dl->size-cfs);
+ dprintf("%x:%x config_size %llx, DDF structure is %llx blocks\n",
+ dl->major, dl->minor,
+ (unsigned long long)cfs, (unsigned long long)(dl->size-cfs));
}
/* Add a device to a container, either while creating it or while
__u32 *tptr;
if (ddf->currentconf) {
- add_to_super_ddf_bvd(st, dk, fd, devname);
+ add_to_super_ddf_bvd(st, dk, fd, devname, data_offset);
return 0;
}
fstat(fd, &stb);
n = find_unused_pde(ddf);
if (n == DDF_NOTFOUND) {
- pr_err("%s: No free slot in array, cannot add disk\n",
- __func__);
+ pr_err("No free slot in array, cannot add disk\n");
return 1;
}
pde = &ddf->phys->entries[n];
get_dev_size(fd, NULL, &size);
if (size <= 32*1024*1024) {
- pr_err("%s: device size must be at least 32MB\n",
- __func__);
+ pr_err("device size must be at least 32MB\n");
return 1;
}
size >>= 9;
if (posix_memalign((void**)&dd, 512,
sizeof(*dd) + sizeof(dd->vlist[0]) * ddf->max_part) != 0) {
- pr_err("%s could allocate buffer for new disk, aborting\n",
- __func__);
+ pr_err("could allocate buffer for new disk, aborting\n");
return 1;
}
dd->major = major(stb.st_rdev);
}
return 0;
}
-#endif
/*
* This is the write_init_super method for a ddf container. It is
memcpy(&ddf->primary, &ddf->anchor, 512);
memcpy(&ddf->secondary, &ddf->anchor, 512);
+ ddf->anchor.type = DDF_HEADER_ANCHOR;
ddf->anchor.openflag = 0xFF; /* 'open' means nothing */
ddf->anchor.seq = cpu_to_be32(0xFFFFFFFF); /* no sequencing in anchor */
ddf->anchor.crc = calc_crc(&ddf->anchor, 512);
return 1;
}
-#ifndef MDASSEMBLE
static int __write_init_super_ddf(struct supertype *st)
{
struct ddf_super *ddf = st->sb;
len);
append_metadata_update(st, vc, tlen);
- /* FIXME I need to close the fds! */
return 0;
} else {
struct dl *d;
if (!currentconf)
for (d = ddf->dlist; d; d=d->next)
while (Kill(d->devname, NULL, 0, -1, 1) == 0);
+ /* Note: we don't close the fd's now, but a subsequent
+ * ->free_super() will
+ */
return __write_init_super_ddf(st);
}
}
-#endif
-
static __u64 avail_size_ddf(struct supertype *st, __u64 devsize,
unsigned long long data_offset)
{
return devsize - 32*1024*2;
}
-#ifndef MDASSEMBLE
-
static int reserve_space(struct supertype *st, int raiddisks,
unsigned long long size, int chunk,
+ unsigned long long data_offset,
unsigned long long *freesize)
{
/* Find 'raiddisks' spare extents at least 'size' big (but
}
/* Now find largest extent on each device */
for (dl = ddf->dlist ; dl ; dl=dl->next) {
- struct extent *e = get_extents(ddf, dl);
- unsigned long long pos = 0;
- int i = 0;
- int found = 0;
- unsigned long long minsize = size;
-
- if (size == 0)
- minsize = chunk;
+ unsigned long long minsize = ULLONG_MAX;
- if (!e)
- continue;
- do {
- unsigned long long esize;
- esize = e[i].start - pos;
- if (esize >= minsize) {
- found = 1;
- minsize = esize;
- }
- pos = e[i].start + e[i].size;
- i++;
- } while (e[i-1].size);
- if (found) {
+ find_space(ddf, dl, data_offset, &minsize);
+ if (minsize >= size && minsize >= (unsigned)chunk) {
cnt++;
dl->esize = minsize;
}
- free(e);
}
if (cnt < raiddisks) {
pr_err("not enough devices with space to create array.\n");
int *chunk, unsigned long long size,
unsigned long long data_offset,
char *dev, unsigned long long *freesize,
- int verbose)
+ int consistency_policy, int verbose)
{
int fd;
struct mdinfo *sra;
* 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,
+ data_offset, freesize);
}
return 1;
}
*/
fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd >= 0) {
- sra = sysfs_read(fd, NULL, GET_VERSION);
close(fd);
- if (sra && sra->array.major_version == -1 &&
- strcmp(sra->text_version, "ddf") == 0) {
- /* load super */
- /* find space for 'n' devices. */
- /* remember the devices */
- /* Somehow return the fact that we have enough */
- }
-
+ /* Just a bare device, no good to us */
if (verbose)
- pr_err("ddf: Cannot create this array "
- "on device %s - a container is required.\n",
+ pr_err("ddf: Cannot create this array on device %s - a container is required.\n",
dev);
return 0;
}
char *dev, unsigned long long *freesize,
int verbose)
{
- struct stat stb;
+ dev_t rdev;
struct ddf_super *ddf = st->sb;
struct dl *dl;
- unsigned long long pos = 0;
unsigned long long maxsize;
- struct extent *e;
- int i;
/* ddf/bvd supports lots of things, but not containers */
if (level == LEVEL_CONTAINER) {
if (verbose)
if (minsize == 0)
minsize = 8;
for (dl = ddf->dlist; dl ; dl = dl->next) {
- int found = 0;
- pos = 0;
-
- i = 0;
- e = get_extents(ddf, dl);
- if (!e) continue;
- do {
- unsigned long long esize;
- esize = e[i].start - pos;
- if (esize >= minsize)
- found = 1;
- pos = e[i].start + e[i].size;
- i++;
- } while (e[i-1].size);
- if (found)
+ if (find_space(ddf, dl, data_offset, &minsize)
+ != INVALID_SECTORS)
dcnt++;
- free(e);
}
if (dcnt < raiddisks) {
if (verbose)
- pr_err("ddf: Not enough devices with "
- "space for this array (%d < %d)\n",
+ pr_err("ddf: Not enough devices with space for this array (%d < %d)\n",
dcnt, raiddisks);
return 0;
}
return 1;
}
/* This device must be a member of the set */
- if (stat(dev, &stb) < 0)
- return 0;
- if ((S_IFMT & stb.st_mode) != S_IFBLK)
+ if (!stat_is_blkdev(dev, NULL))
return 0;
for (dl = ddf->dlist ; dl ; dl = dl->next) {
- if (dl->major == (int)major(stb.st_rdev) &&
- dl->minor == (int)minor(stb.st_rdev))
+ if (dl->major == (int)major(rdev) &&
+ dl->minor == (int)minor(rdev))
break;
}
if (!dl) {
if (verbose)
- pr_err("ddf: %s is not in the "
- "same DDF set\n",
+ pr_err("ddf: %s is not in the same DDF set\n",
dev);
return 0;
}
- e = get_extents(ddf, dl);
- maxsize = 0;
- i = 0;
- if (e)
- do {
- unsigned long long esize;
- esize = e[i].start - pos;
- if (esize >= maxsize)
- maxsize = esize;
- pos = e[i].start + e[i].size;
- i++;
- } while (e[i-1].size);
+ maxsize = ULLONG_MAX;
+ find_space(ddf, dl, data_offset, &maxsize);
*freesize = maxsize;
- // FIXME here I am
return 1;
}
return load_super_ddf_all(st, fd, &st->sb, devname);
}
-#endif /* MDASSEMBLE */
-
static int check_secondary(const struct vcl *vc)
{
const struct vd_config *conf = &vc->conf;
}
for (i = 0; i < conf->sec_elmnt_count; i++) {
if (!__was_sec_seen(i)) {
- pr_err("BVD %d is missing\n", i);
+ /* pr_err("BVD %d is missing\n", i); */
return -1;
}
}
int ofd, ret;
if (fstat(fd, &sta) == -1 || !S_ISBLK(sta.st_mode)) {
- pr_err("%s: file descriptor for invalid device\n",
- __func__);
+ pr_err("file descriptor for invalid device\n");
return 1;
}
for (dl = ddf->dlist; dl; dl = dl->next)
dl->minor == (int)minor(sta.st_rdev))
break;
if (!dl) {
- pr_err("%s: couldn't find disk %d/%d\n", __func__,
+ pr_err("couldn't find disk %d/%d\n",
(int)major(sta.st_rdev),
(int)minor(sta.st_rdev));
return 1;
*/
if (!be32_eq(first->active->seq, second->active->seq)) {
- dprintf("%s: sequence number mismatch %u<->%u\n", __func__,
+ dprintf("sequence number mismatch %u<->%u\n",
be32_to_cpu(first->active->seq),
be32_to_cpu(second->active->seq));
return 0;
if (vl1->other_bvds != NULL &&
vl1->conf.sec_elmnt_seq !=
vl2->conf.sec_elmnt_seq) {
- dprintf("%s: adding BVD %u\n", __func__,
+ dprintf("adding BVD %u\n",
vl2->conf.sec_elmnt_seq);
add_other_bvd(vl1, &vl2->conf,
first->conf_rec_len*512);
if (posix_memalign((void **)&vl1, 512,
(first->conf_rec_len*512 +
offsetof(struct vcl, conf))) != 0) {
- pr_err("%s could not allocate vcl buf\n",
- __func__);
+ pr_err("could not allocate vcl buf\n");
return 3;
}
vl1->block_sizes = NULL;
memcpy(&vl1->conf, &vl2->conf, first->conf_rec_len*512);
if (alloc_other_bvds(first, vl1) != 0) {
- pr_err("%s could not allocate other bvds\n",
- __func__);
+ pr_err("could not allocate other bvds\n");
free(vl1);
return 3;
}
vl1->conf.guid, DDF_GUID_LEN))
break;
vl1->vcnum = vd;
- dprintf("%s: added config for VD %u\n", __func__, vl1->vcnum);
+ dprintf("added config for VD %u\n", vl1->vcnum);
first->conflist = vl1;
}
if (posix_memalign((void **)&dl1, 512,
sizeof(*dl1) + (first->max_part) * sizeof(dl1->vlist[0]))
!= 0) {
- pr_err("%s could not allocate disk info buffer\n",
- __func__);
+ pr_err("could not allocate disk info buffer\n");
return 3;
}
memcpy(dl1, dl2, sizeof(*dl1));
if (dl2->spare) {
if (posix_memalign((void **)&dl1->spare, 512,
first->conf_rec_len*512) != 0) {
- pr_err("%s could not allocate spare info buf\n",
- __func__);
+ pr_err("could not allocate spare info buf\n");
return 3;
}
memcpy(dl1->spare, dl2->spare, first->conf_rec_len*512);
}
}
first->dlist = dl1;
- dprintf("%s: added disk %d: %08x\n", __func__, dl1->pdnum,
+ dprintf("added disk %d: %08x\n", dl1->pdnum,
be32_to_cpu(dl1->disk.refnum));
}
return 0;
}
-#ifndef MDASSEMBLE
/*
* A new array 'a' has been started which claims to be instance 'inst'
* within container 'c'.
static const char faulty[] = "faulty";
if (all_ff(ddf->virt->entries[n].guid)) {
- pr_err("%s: subarray %d doesn't exist\n", __func__, n);
+ pr_err("subarray %d doesn't exist\n", n);
return -ENODEV;
}
- dprintf("%s: new subarray %d, GUID: %s\n", __func__, n,
+ dprintf("new subarray %d, GUID: %s\n", n,
guid_str(ddf->virt->entries[n].guid));
for (dev = a->info.devs; dev; dev = dev->next) {
for (dl = ddf->dlist; dl; dl = dl->next)
dl->minor == dev->disk.minor)
break;
if (!dl || dl->pdnum < 0) {
- pr_err("%s: device %d/%d of subarray %d not found in meta data\n",
- __func__, dev->disk.major, dev->disk.minor, n);
+ pr_err("device %d/%d of subarray %d not found in meta data\n",
+ dev->disk.major, dev->disk.minor, n);
return -1;
}
if ((be16_to_cpu(ddf->phys->entries[dl->pdnum].state) &
(DDF_Online|DDF_Missing|DDF_Failed)) != DDF_Online) {
- pr_err("%s: new subarray %d contains broken device %d/%d (%02x)\n",
- __func__, n, dl->major, dl->minor,
- be16_to_cpu(
- ddf->phys->entries[dl->pdnum].state));
+ pr_err("new subarray %d contains broken device %d/%d (%02x)\n",
+ n, dl->major, dl->minor,
+ be16_to_cpu(ddf->phys->entries[dl->pdnum].state));
if (write(dev->state_fd, faulty, sizeof(faulty)-1) !=
sizeof(faulty) - 1)
pr_err("Write to state_fd failed\n");
int old = ddf->virt->entries[inst].state;
if (consistent == 2) {
handle_missing(ddf, a, inst);
- /* Should check if a recovery should be started FIXME */
consistent = 1;
if (!is_resync_complete(&a->info))
consistent = 0;
unsigned int i, n_bvd, working = 0;
unsigned int n_prim = be16_to_cpu(vc->prim_elmnt_count);
int pd, st, state;
+ char *avail = xcalloc(1, n_prim);
+ mdu_array_info_t array;
+
+ layout_ddf2md(vc, &array);
+
for (i = 0; i < n_prim; i++) {
if (!find_index_in_bvd(ddf, vc, i, &n_bvd))
continue;
continue;
st = be16_to_cpu(ddf->phys->entries[pd].state);
if ((st & (DDF_Online|DDF_Failed|DDF_Rebuilding))
- == DDF_Online)
+ == DDF_Online) {
working++;
+ avail[i] = 1;
+ }
}
state = DDF_state_degraded;
else if (working >= 2)
state = DDF_state_part_optimal;
break;
+ case DDF_RAID1E:
+ if (!enough(10, n_prim, array.layout, 1, avail))
+ state = DDF_state_failed;
+ break;
case DDF_RAID4:
case DDF_RAID5:
if (working < n_prim - 1)
struct dl *dl;
int update = 0;
- dprintf("%s: %d to %x\n", __func__, n, state);
+ dprintf("%d to %x\n", n, state);
if (vc == NULL) {
dprintf("ddf: cannot find instance %d!!\n", inst);
return;
if (mdi->disk.raid_disk == n)
break;
if (!mdi) {
- pr_err("%s: cannot find raid disk %d\n",
- __func__, n);
+ pr_err("cannot find raid disk %d\n", n);
return;
}
mdi->disk.minor == dl->minor)
break;
if (!dl) {
- pr_err("%s: cannot find raid disk %d (%d/%d)\n",
- __func__, n,
- mdi->disk.major, mdi->disk.minor);
+ pr_err("cannot find raid disk %d (%d/%d)\n",
+ n, mdi->disk.major, mdi->disk.minor);
return;
}
if (pd < 0 || pd != dl->pdnum) {
/* disk doesn't currently exist or has changed.
* If it is now in_sync, insert it. */
- dprintf("%s: phys disk not found for %d: %d/%d ref %08x\n",
- __func__, dl->pdnum, dl->major, dl->minor,
+ dprintf("phys disk not found for %d: %d/%d ref %08x\n",
+ dl->pdnum, dl->major, dl->minor,
be32_to_cpu(dl->disk.refnum));
- dprintf("%s: array %u disk %u ref %08x pd %d\n",
- __func__, inst, n_bvd,
+ dprintf("array %u disk %u ref %08x pd %d\n",
+ inst, n_bvd,
be32_to_cpu(vc->phys_refnum[n_bvd]), pd);
- if ((state & DS_INSYNC) && ! (state & DS_FAULTY)) {
- pd = dl->pdnum; /* FIXME: is this really correct ? */
+ if ((state & DS_INSYNC) && ! (state & DS_FAULTY) &&
+ dl->pdnum >= 0) {
+ pd = dl->pdnum;
vc->phys_refnum[n_bvd] = dl->disk.refnum;
LBA_OFFSET(ddf, vc)[n_bvd] =
cpu_to_be64(mdi->data_offset);
unsigned int vdnum, i;
vdnum = find_vde_by_guid(ddf, guid);
if (vdnum == DDF_NOTFOUND) {
- pr_err("%s: could not find VD %s\n", __func__,
- guid_str(guid));
+ pr_err("could not find VD %s\n", guid_str(guid));
return -1;
}
if (del_from_conflist(&ddf->conflist, guid) == 0) {
- pr_err("%s: could not find conf %s\n", __func__,
- guid_str(guid));
+ pr_err("could not find conf %s\n", guid_str(guid));
return -1;
}
for (dl = ddf->dlist; dl; dl = dl->next)
DDF_GUID_LEN))
dl->vlist[i] = NULL;
memset(ddf->virt->entries[vdnum].guid, 0xff, DDF_GUID_LEN);
- dprintf("%s: deleted %s\n", __func__, guid_str(guid));
+ dprintf("deleted %s\n", guid_str(guid));
return 0;
}
ddf->currentconf = NULL;
if (!victim) {
- pr_err("%s: nothing to kill\n", __func__);
+ pr_err("nothing to kill\n");
return -1;
}
conf = &victim->conf;
vdnum = find_vde_by_guid(ddf, conf->guid);
if (vdnum == DDF_NOTFOUND) {
- pr_err("%s: could not find VD %s\n", __func__,
- guid_str(conf->guid));
+ pr_err("could not find VD %s\n", guid_str(conf->guid));
return -1;
}
if (st->update_tail) {
+ sizeof(struct virtual_entry);
vd = xmalloc(len);
if (vd == NULL) {
- pr_err("%s: failed to allocate %d bytes\n", __func__,
- len);
+ pr_err("failed to allocate %d bytes\n", len);
return -1;
}
memset(vd, 0 , len);
return;
}
}
- pr_err("%s: no match for BVD %d of %s in update\n", __func__,
+ pr_err("no match for BVD %d of %s in update\n",
conf->sec_elmnt_seq, guid_str(conf->guid));
}
+static void ddf_process_phys_update(struct supertype *st,
+ struct metadata_update *update)
+{
+ struct ddf_super *ddf = st->sb;
+ struct phys_disk *pd;
+ unsigned int ent;
+
+ pd = (struct phys_disk*)update->buf;
+ ent = be16_to_cpu(pd->used_pdes);
+ if (ent >= be16_to_cpu(ddf->phys->max_pdes))
+ return;
+ if (be16_and(pd->entries[0].state, cpu_to_be16(DDF_Missing))) {
+ struct dl **dlp;
+ /* removing this disk. */
+ be16_set(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;
+ *dlp = dl->next;
+ update->space = dl->devname;
+ *(void**)dl = update->space_list;
+ update->space_list = (void**)dl;
+ break;
+ }
+ }
+ ddf_set_updates_pending(ddf, NULL);
+ return;
+ }
+ if (!all_ff(ddf->phys->entries[ent].guid))
+ return;
+ ddf->phys->entries[ent] = pd->entries[0];
+ ddf->phys->used_pdes = cpu_to_be16
+ (1 + be16_to_cpu(ddf->phys->used_pdes));
+ ddf_set_updates_pending(ddf, NULL);
+ if (ddf->add_list) {
+ struct active_array *a;
+ struct dl *al = ddf->add_list;
+ ddf->add_list = al->next;
+
+ al->next = ddf->dlist;
+ ddf->dlist = al;
+
+ /* As a device has been added, we should check
+ * for any degraded devices that might make
+ * use of this spare */
+ for (a = st->arrays ; a; a=a->next)
+ a->check_degraded = 1;
+ }
+}
+
+static void ddf_process_virt_update(struct supertype *st,
+ struct metadata_update *update)
+{
+ struct ddf_super *ddf = st->sb;
+ struct virtual_disk *vd;
+ unsigned int ent;
+
+ vd = (struct virtual_disk*)update->buf;
+
+ if (vd->entries[0].state == DDF_state_deleted) {
+ if (_kill_subarray_ddf(ddf, vd->entries[0].guid))
+ return;
+ } else {
+ ent = find_vde_by_guid(ddf, vd->entries[0].guid);
+ if (ent != DDF_NOTFOUND) {
+ dprintf("VD %s exists already in slot %d\n",
+ guid_str(vd->entries[0].guid),
+ ent);
+ return;
+ }
+ ent = find_unused_vde(ddf);
+ if (ent == DDF_NOTFOUND)
+ return;
+ ddf->virt->entries[ent] = vd->entries[0];
+ ddf->virt->populated_vdes =
+ cpu_to_be16(
+ 1 + be16_to_cpu(
+ ddf->virt->populated_vdes));
+ dprintf("added VD %s in slot %d(s=%02x i=%02x)\n",
+ guid_str(vd->entries[0].guid), ent,
+ ddf->virt->entries[ent].state,
+ ddf->virt->entries[ent].init_state);
+ }
+ ddf_set_updates_pending(ddf, NULL);
+}
+
+static void ddf_remove_failed(struct ddf_super *ddf)
+{
+ /* 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.
+ */
+ unsigned int pdnum;
+ unsigned int pd2 = 0;
+ struct dl *dl;
+
+ for (pdnum = 0; pdnum < be16_to_cpu(ddf->phys->max_pdes);
+ pdnum++) {
+ if (be32_to_cpu(ddf->phys->entries[pdnum].refnum) ==
+ 0xFFFFFFFF)
+ continue;
+ if (be16_and(ddf->phys->entries[pdnum].state,
+ cpu_to_be16(DDF_Failed))
+ && be16_and(ddf->phys->entries[pdnum].state,
+ cpu_to_be16(DDF_Transition))) {
+ /* skip this one unless in dlist*/
+ for (dl = ddf->dlist; dl; dl = dl->next)
+ if (dl->pdnum == (int)pdnum)
+ break;
+ if (!dl)
+ continue;
+ }
+ 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++;
+ }
+}
+
+static void ddf_update_vlist(struct ddf_super *ddf, struct dl *dl)
+{
+ struct vcl *vcl;
+ unsigned int vn = 0;
+ int in_degraded = 0;
+
+ if (dl->pdnum < 0)
+ return;
+ for (vcl = ddf->conflist; vcl ; vcl = vcl->next) {
+ unsigned int dn, ibvd;
+ const struct vd_config *conf;
+ int vstate;
+ dn = get_pd_index_from_refnum(vcl,
+ dl->disk.refnum,
+ ddf->mppe,
+ &conf, &ibvd);
+ if (dn == DDF_NOTFOUND)
+ continue;
+ dprintf("dev %d/%08x has %s (sec=%u) at %d\n",
+ dl->pdnum,
+ be32_to_cpu(dl->disk.refnum),
+ guid_str(conf->guid),
+ conf->sec_elmnt_seq, vn);
+ /* Clear the Transition flag */
+ if (be16_and
+ (ddf->phys->entries[dl->pdnum].state,
+ cpu_to_be16(DDF_Failed)))
+ be16_clear(ddf->phys
+ ->entries[dl->pdnum].state,
+ cpu_to_be16(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;
+ }
+ while (vn < ddf->max_part)
+ dl->vlist[vn++] = NULL;
+ if (dl->vlist[0]) {
+ be16_clear(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Global_Spare));
+ if (!be16_and(ddf->phys
+ ->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Active_in_VD))) {
+ be16_set(ddf->phys
+ ->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Active_in_VD));
+ if (in_degraded)
+ be16_set(ddf->phys
+ ->entries[dl->pdnum]
+ .state,
+ cpu_to_be16
+ (DDF_Rebuilding));
+ }
+ }
+ if (dl->spare) {
+ be16_clear(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Global_Spare));
+ be16_set(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Spare));
+ }
+ if (!dl->vlist[0] && !dl->spare) {
+ be16_set(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Global_Spare));
+ be16_clear(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Spare));
+ be16_clear(ddf->phys->entries[dl->pdnum].type,
+ cpu_to_be16(DDF_Active_in_VD));
+ }
+}
+
+static void ddf_process_conf_update(struct supertype *st,
+ struct metadata_update *update)
+{
+ struct ddf_super *ddf = st->sb;
+ struct vd_config *vc;
+ struct vcl *vcl;
+ struct dl *dl;
+ unsigned int ent;
+ unsigned int pdnum, len;
+
+ vc = (struct vd_config*)update->buf;
+ len = ddf->conf_rec_len * 512;
+ if ((unsigned int)update->len != len * vc->sec_elmnt_count) {
+ pr_err("%s: insufficient data (%d) for %u BVDs\n",
+ guid_str(vc->guid), update->len,
+ vc->sec_elmnt_count);
+ return;
+ }
+ for (vcl = ddf->conflist; vcl ; vcl = vcl->next)
+ if (memcmp(vcl->conf.guid, vc->guid, DDF_GUID_LEN) == 0)
+ break;
+ dprintf("conf update for %s (%s)\n",
+ guid_str(vc->guid), (vcl ? "old" : "new"));
+ if (vcl) {
+ /* An update, just copy the phys_refnum and lba_offset
+ * fields
+ */
+ unsigned int i;
+ unsigned int k;
+ copy_matching_bvd(ddf, &vcl->conf, update);
+ for (k = 0; k < be16_to_cpu(vc->prim_elmnt_count); k++)
+ dprintf("BVD %u has %08x at %llu\n", 0,
+ be32_to_cpu(vcl->conf.phys_refnum[k]),
+ be64_to_cpu(LBA_OFFSET(ddf,
+ &vcl->conf)[k]));
+ for (i = 1; i < vc->sec_elmnt_count; i++) {
+ copy_matching_bvd(ddf, vcl->other_bvds[i-1],
+ update);
+ for (k = 0; k < be16_to_cpu(
+ vc->prim_elmnt_count); k++)
+ dprintf("BVD %u has %08x at %llu\n", i,
+ be32_to_cpu
+ (vcl->other_bvds[i-1]->
+ phys_refnum[k]),
+ be64_to_cpu
+ (LBA_OFFSET
+ (ddf,
+ vcl->other_bvds[i-1])[k]));
+ }
+ } else {
+ /* A new VD_CONF */
+ unsigned int i;
+ if (!update->space)
+ return;
+ vcl = update->space;
+ update->space = NULL;
+ vcl->next = ddf->conflist;
+ memcpy(&vcl->conf, vc, len);
+ ent = find_vde_by_guid(ddf, vc->guid);
+ if (ent == DDF_NOTFOUND)
+ return;
+ vcl->vcnum = ent;
+ ddf->conflist = vcl;
+ for (i = 1; i < vc->sec_elmnt_count; i++)
+ memcpy(vcl->other_bvds[i-1],
+ update->buf + len * i, len);
+ }
+ /* 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->max_pdes);
+ pdnum++)
+ if (be16_and(ddf->phys->entries[pdnum].state,
+ cpu_to_be16(DDF_Failed)))
+ be16_set(ddf->phys->entries[pdnum].state,
+ cpu_to_be16(DDF_Transition));
+
+ /* Now make sure vlist is correct for each dl. */
+ for (dl = ddf->dlist; dl; dl = dl->next)
+ ddf_update_vlist(ddf, dl);
+ ddf_remove_failed(ddf);
+
+ ddf_set_updates_pending(ddf, vc);
+}
+
static void ddf_process_update(struct supertype *st,
struct metadata_update *update)
{
* and offset. This will also mark the spare as active with
* a spare-assignment record.
*/
- struct ddf_super *ddf = st->sb;
be32 *magic = (be32 *)update->buf;
- struct phys_disk *pd;
- struct virtual_disk *vd;
- struct vd_config *vc;
- struct vcl *vcl;
- struct dl *dl;
- unsigned int ent;
- unsigned int pdnum, pd2, len;
dprintf("Process update %x\n", be32_to_cpu(*magic));
if (be32_eq(*magic, DDF_PHYS_RECORDS_MAGIC)) {
- if (update->len != (sizeof(struct phys_disk) +
+ if (update->len == (sizeof(struct phys_disk) +
sizeof(struct phys_disk_entry)))
- return;
- pd = (struct phys_disk*)update->buf;
-
- ent = be16_to_cpu(pd->used_pdes);
- if (ent >= be16_to_cpu(ddf->phys->max_pdes))
- return;
- if (be16_and(pd->entries[0].state, cpu_to_be16(DDF_Missing))) {
- struct dl **dlp;
- /* removing this disk. */
- be16_set(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_set_updates_pending(ddf, NULL);
- return;
- }
- if (!all_ff(ddf->phys->entries[ent].guid))
- return;
- ddf->phys->entries[ent] = pd->entries[0];
- ddf->phys->used_pdes = cpu_to_be16
- (1 + be16_to_cpu(ddf->phys->used_pdes));
- ddf_set_updates_pending(ddf, NULL);
- if (ddf->add_list) {
- struct active_array *a;
- struct dl *al = ddf->add_list;
- ddf->add_list = al->next;
-
- al->next = ddf->dlist;
- ddf->dlist = al;
-
- /* As a device has been added, we should check
- * for any degraded devices that might make
- * use of this spare */
- for (a = st->arrays ; a; a=a->next)
- a->check_degraded = 1;
- }
+ ddf_process_phys_update(st, update);
} else if (be32_eq(*magic, DDF_VIRT_RECORDS_MAGIC)) {
- if (update->len != (sizeof(struct virtual_disk) +
+ if (update->len == (sizeof(struct virtual_disk) +
sizeof(struct virtual_entry)))
- return;
- vd = (struct virtual_disk*)update->buf;
-
- if (vd->entries[0].state == DDF_state_deleted) {
- if (_kill_subarray_ddf(ddf, vd->entries[0].guid))
- return;
- } else {
- ent = find_vde_by_guid(ddf, vd->entries[0].guid);
- if (ent != DDF_NOTFOUND) {
- dprintf("%s: VD %s exists already in slot %d\n",
- __func__, guid_str(vd->entries[0].guid),
- ent);
- return;
- }
- ent = find_unused_vde(ddf);
- if (ent == DDF_NOTFOUND)
- return;
- ddf->virt->entries[ent] = vd->entries[0];
- ddf->virt->populated_vdes =
- cpu_to_be16(
- 1 + be16_to_cpu(
- ddf->virt->populated_vdes));
- dprintf("%s: added VD %s in slot %d(s=%02x i=%02x)\n",
- __func__, guid_str(vd->entries[0].guid), ent,
- ddf->virt->entries[ent].state,
- ddf->virt->entries[ent].init_state);
- }
- ddf_set_updates_pending(ddf, NULL);
- }
-
- else if (be32_eq(*magic, DDF_VD_CONF_MAGIC)) {
- vc = (struct vd_config*)update->buf;
- len = ddf->conf_rec_len * 512;
- if ((unsigned int)update->len != len * vc->sec_elmnt_count) {
- pr_err("%s: %s: insufficient data (%d) for %u BVDs\n",
- __func__, guid_str(vc->guid), update->len,
- vc->sec_elmnt_count);
- return;
- }
- for (vcl = ddf->conflist; vcl ; vcl = vcl->next)
- if (memcmp(vcl->conf.guid, vc->guid, DDF_GUID_LEN) == 0)
- break;
- dprintf("%s: conf update for %s (%s)\n", __func__,
- guid_str(vc->guid), (vcl ? "old" : "new"));
- if (vcl) {
- /* An update, just copy the phys_refnum and lba_offset
- * fields
- */
- unsigned int i;
- unsigned int k;
- copy_matching_bvd(ddf, &vcl->conf, update);
- for (k = 0; k < be16_to_cpu(vc->prim_elmnt_count); k++)
- dprintf("BVD %u has %08x at %llu\n", 0,
- be32_to_cpu(vcl->conf.phys_refnum[k]),
- be64_to_cpu(LBA_OFFSET(ddf,
- &vcl->conf)[k]));
- for (i = 1; i < vc->sec_elmnt_count; i++) {
- copy_matching_bvd(ddf, vcl->other_bvds[i-1],
- update);
- for (k = 0; k < be16_to_cpu(
- vc->prim_elmnt_count); k++)
- dprintf("BVD %u has %08x at %llu\n", i,
- be32_to_cpu
- (vcl->other_bvds[i-1]->
- phys_refnum[k]),
- be64_to_cpu
- (LBA_OFFSET
- (ddf,
- vcl->other_bvds[i-1])[k]));
- }
- } else {
- /* A new VD_CONF */
- unsigned int i;
- if (!update->space)
- return;
- vcl = update->space;
- update->space = NULL;
- vcl->next = ddf->conflist;
- memcpy(&vcl->conf, vc, len);
- ent = find_vde_by_guid(ddf, vc->guid);
- if (ent == DDF_NOTFOUND)
- return;
- vcl->vcnum = ent;
- ddf->conflist = vcl;
- for (i = 1; i < vc->sec_elmnt_count; i++)
- memcpy(vcl->other_bvds[i-1],
- update->buf + len * i, len);
- }
- /* 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->max_pdes);
- pdnum++)
- if (be16_and(ddf->phys->entries[pdnum].state,
- cpu_to_be16(DDF_Failed)))
- be16_set(ddf->phys->entries[pdnum].state,
- cpu_to_be16(DDF_Transition));
- /* Now make sure vlist is correct for each dl. */
- for (dl = ddf->dlist; dl; dl = dl->next) {
- unsigned int vn = 0;
- int in_degraded = 0;
-
- if (dl->pdnum < 0)
- continue;
- for (vcl = ddf->conflist; vcl ; vcl = vcl->next) {
- unsigned int dn, ibvd;
- const struct vd_config *conf;
- int vstate;
- dn = get_pd_index_from_refnum(vcl,
- dl->disk.refnum,
- ddf->mppe,
- &conf, &ibvd);
- if (dn == DDF_NOTFOUND)
- continue;
- dprintf("dev %d/%08x has %s (sec=%u) at %d\n",
- dl->pdnum,
- be32_to_cpu(dl->disk.refnum),
- guid_str(conf->guid),
- conf->sec_elmnt_seq, vn);
- /* Clear the Transition flag */
- if (be16_and
- (ddf->phys->entries[dl->pdnum].state,
- cpu_to_be16(DDF_Failed)))
- be16_clear(ddf->phys
- ->entries[dl->pdnum].state,
- cpu_to_be16(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;
- }
- while (vn < ddf->max_part)
- dl->vlist[vn++] = NULL;
- if (dl->vlist[0]) {
- be16_clear(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Global_Spare));
- if (!be16_and(ddf->phys
- ->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Active_in_VD))) {
- be16_set(ddf->phys
- ->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Active_in_VD));
- if (in_degraded)
- be16_set(ddf->phys
- ->entries[dl->pdnum]
- .state,
- cpu_to_be16
- (DDF_Rebuilding));
- }
- }
- if (dl->spare) {
- be16_clear(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Global_Spare));
- be16_set(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Spare));
- }
- if (!dl->vlist[0] && !dl->spare) {
- be16_set(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Global_Spare));
- be16_clear(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(DDF_Spare));
- be16_clear(ddf->phys->entries[dl->pdnum].type,
- cpu_to_be16(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->max_pdes);
- pdnum++) {
- if (be32_to_cpu(ddf->phys->entries[pdnum].refnum) ==
- 0xFFFFFFFF)
- continue;
- if (be16_and(ddf->phys->entries[pdnum].state,
- cpu_to_be16(DDF_Failed))
- && be16_and(ddf->phys->entries[pdnum].state,
- cpu_to_be16(DDF_Transition))) {
- /* skip this one unless in dlist*/
- for (dl = ddf->dlist; dl; dl = dl->next)
- if (dl->pdnum == (int)pdnum)
- break;
- if (!dl)
- continue;
- }
- 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_set_updates_pending(ddf, vc);
+ ddf_process_virt_update(st, update);
+ } else if (be32_eq(*magic, DDF_VD_CONF_MAGIC)) {
+ ddf_process_conf_update(st, update);
}
/* case DDF_SPARE_ASSIGN_MAGIC */
}
-static void ddf_prepare_update(struct supertype *st,
- struct metadata_update *update)
+static int ddf_prepare_update(struct supertype *st,
+ struct metadata_update *update)
{
/* This update arrived at managemon.
* We are about to pass it to monitor.
* If a malloc is needed, do it here.
*/
struct ddf_super *ddf = st->sb;
- be32 *magic = (be32 *)update->buf;
+ be32 *magic;
+ if (update->len < 4)
+ return 0;
+ magic = (be32 *)update->buf;
if (be32_eq(*magic, DDF_VD_CONF_MAGIC)) {
struct vcl *vcl;
- struct vd_config *conf = (struct vd_config *) update->buf;
+ struct vd_config *conf;
+ if (update->len < (int)sizeof(*conf))
+ return 0;
+ conf = (struct vd_config *) update->buf;
if (posix_memalign(&update->space, 512,
offsetof(struct vcl, conf)
+ ddf->conf_rec_len * 512) != 0) {
update->space = NULL;
- return;
+ return 0;
}
vcl = update->space;
vcl->conf.sec_elmnt_count = conf->sec_elmnt_count;
if (alloc_other_bvds(ddf, vcl) != 0) {
free(update->space);
update->space = NULL;
+ return 0;
}
}
+ return 1;
}
/*
for (d = info->devs; d; d = d->next) {
i = d->disk.raid_disk / n_prim;
if (i >= n_bvds) {
- pr_err("%s: BUG: invalid raid disk\n", __func__);
+ pr_err("BUG: invalid raid disk\n");
goto out;
}
if (d->state_fd > 0)
ret = 2;
for (i = 0; i < n_bvds; i++)
if (!found[i]) {
- dprintf("%s: BVD %d/%d failed\n", __func__, i, n_bvds);
+ dprintf("BVD %d/%d failed\n", i, n_bvds);
ret = 0;
goto out;
} else if (found[i] < n_prim) {
- dprintf("%s: BVD %d/%d degraded\n", __func__, i,
- n_bvds);
+ dprintf("BVD %d/%d degraded\n", i, n_bvds);
ret = 1;
}
out:
working ++;
}
- dprintf("%s: working=%d (%d) level=%d\n", __func__, working,
+ dprintf("working=%d (%d) level=%d\n", working,
a->info.array.raid_disks,
a->info.array.level);
if (working == a->info.array.raid_disks)
struct mdinfo *d2;
int is_global = 0;
int is_dedicated = 0;
- struct extent *ex;
- unsigned int j;
be16 state;
if (dl->pdnum < 0)
if (dl->spare) {
if (dl->spare->type & DDF_spare_dedicated) {
/* check spare_ents for guid */
+ unsigned int j;
for (j = 0 ;
j < be16_to_cpu
(dl->spare
/* We are allowed to use this device - is there space?
* We need a->info.component_size sectors */
- ex = get_extents(ddf, dl);
- if (!ex) {
- dprintf("cannot get extents\n");
- continue;
- }
- j = 0; pos = 0;
- esize = 0;
+ esize = a->info.component_size;
+ pos = find_space(ddf, dl, INVALID_SECTORS, &esize);
- do {
- esize = ex[j].start - pos;
- if (esize >= a->info.component_size)
- break;
- 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,
&& dl->minor == di->disk.minor)
break;
if (!dl || dl->pdnum < 0) {
- pr_err("%s: BUG: can't find disk %d (%d/%d)\n",
- __func__, di->disk.raid_disk,
+ pr_err("BUG: can't find disk %d (%d/%d)\n",
+ di->disk.raid_disk,
di->disk.major, di->disk.minor);
return NULL;
}
*updates = mu;
return rv;
}
-#endif /* MDASSEMBLE */
static int ddf_level_to_layout(int level)
{
}
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,
.load_container = load_container_ddf,
.copy_metadata = copy_metadata_ddf,
.kill_subarray = kill_subarray_ddf,
-#endif
.match_home = match_home_ddf,
.uuid_from_super= uuid_from_super_ddf,
.getinfo_super = getinfo_super_ddf,
.external = 1,
-#ifndef MDASSEMBLE
/* for mdmon */
.open_new = ddf_open_new,
.set_array_state= ddf_set_array_state,
.process_update = ddf_process_update,
.prepare_update = ddf_prepare_update,
.activate_spare = ddf_activate_spare,
-#endif
.name = "ddf",
};