Set status of devices in ddf.
Might work a little bit....
This commit is contained in:
parent
4e5528c6f7
commit
7a7cc50430
8
mdadm.h
8
mdadm.h
|
@ -421,6 +421,14 @@ extern struct superswitch {
|
|||
* write to an array with redundancy is allowed.
|
||||
*/
|
||||
void (*mark_clean)(struct active_array *a, unsigned long long sync_pos);
|
||||
|
||||
/* When the state of a device might have changed, we call set_disk to
|
||||
* tell the metadata what the current state is.
|
||||
* Typically this happens on spare->in_sync and (spare|in_sync)->faulty
|
||||
* transitions.
|
||||
* set_disk might be called when the state of the particular disk has
|
||||
* not in fact changed.
|
||||
*/
|
||||
void (*set_disk)(struct active_array *a, int n, int state);
|
||||
void (*sync_metadata)(struct active_array *a);
|
||||
|
||||
|
|
191
super-ddf.c
191
super-ddf.c
|
@ -255,6 +255,7 @@ struct virtual_disk {
|
|||
#define DDF_state_deleted 0x2
|
||||
#define DDF_state_missing 0x3
|
||||
#define DDF_state_failed 0x4
|
||||
#define DDF_state_part_optimal 0x5
|
||||
|
||||
#define DDF_state_morphing 0x8
|
||||
#define DDF_state_inconsistent 0x10
|
||||
|
@ -262,7 +263,8 @@ struct virtual_disk {
|
|||
/* virtual_entry.init_state is a bigendian bitmap */
|
||||
#define DDF_initstate_mask 0x03
|
||||
#define DDF_init_not 0x00
|
||||
#define DDF_init_quick 0x01
|
||||
#define DDF_init_quick 0x01 /* initialisation is progress.
|
||||
* i.e. 'state_inconsistent' */
|
||||
#define DDF_init_full 0x02
|
||||
|
||||
#define DDF_access_mask 0xc0
|
||||
|
@ -1116,10 +1118,29 @@ static int match_home_ddf(struct supertype *st, char *homehost)
|
|||
ddf->controller.vendor_data[len] == 0);
|
||||
}
|
||||
|
||||
static struct vd_config *find_vdcr(struct ddf_super *ddf)
|
||||
static struct vd_config *find_vdcr(struct ddf_super *ddf, int inst)
|
||||
{
|
||||
/* FIXME this just picks off the first one */
|
||||
return &ddf->conflist->conf;
|
||||
struct vcl *v;
|
||||
if (inst < 0 || inst > __be16_to_cpu(ddf->virt->populated_vdes))
|
||||
return NULL;
|
||||
for (v = ddf->conflist; v; v = v->next)
|
||||
if (memcmp(v->conf.guid,
|
||||
ddf->virt->entries[inst].guid,
|
||||
DDF_GUID_LEN) == 0)
|
||||
return &v->conf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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++)
|
||||
if (ddf->phys->entries[i].refnum == phys_refnum)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uuid_from_super_ddf(struct supertype *st, int uuid[4])
|
||||
|
@ -1141,7 +1162,7 @@ static void uuid_from_super_ddf(struct supertype *st, int uuid[4])
|
|||
* The first 16 bytes of the sha1 of these is used.
|
||||
*/
|
||||
struct ddf_super *ddf = st->sb;
|
||||
struct vd_config *vd = find_vdcr(ddf);
|
||||
struct vd_config *vd = find_vdcr(ddf, st->container_member);
|
||||
|
||||
if (!vd)
|
||||
memset(uuid, 0, sizeof (uuid));
|
||||
|
@ -1211,7 +1232,7 @@ static int rlq_to_layout(int rlq, int prl, int raiddisks);
|
|||
static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
|
||||
{
|
||||
struct ddf_super *ddf = st->sb;
|
||||
struct vd_config *vd = find_vdcr(ddf);
|
||||
struct vd_config *vd = find_vdcr(ddf, info->container_member);
|
||||
|
||||
/* FIXME this returns BVD info - what if we want SVD ?? */
|
||||
|
||||
|
@ -1284,7 +1305,7 @@ static int update_super_ddf(struct supertype *st, struct mdinfo *info,
|
|||
*/
|
||||
int rv = 0;
|
||||
// struct ddf_super *ddf = st->sb;
|
||||
// struct vd_config *vd = find_vdcr(ddf);
|
||||
// struct vd_config *vd = find_vdcr(ddf, info->container_member);
|
||||
// struct virtual_entry *ve = find_ve(ddf);
|
||||
|
||||
|
||||
|
@ -1671,10 +1692,12 @@ static int init_super_ddf_bvd(struct supertype *st,
|
|||
ve->pad0 = 0xFFFF;
|
||||
ve->guid_crc = crc32(0, (unsigned char*)ddf->anchor.guid, DDF_GUID_LEN);
|
||||
ve->type = 0;
|
||||
ve->state = 0;
|
||||
ve->init_state = 0;
|
||||
if (!(info->state & 1))
|
||||
ve->init_state = DDF_state_inconsistent;
|
||||
ve->state = DDF_state_degraded; /* Will be modified as devices are added */
|
||||
if (info->state & 1) /* clean */
|
||||
ve->init_state = DDF_init_full;
|
||||
else
|
||||
ve->init_state = DDF_init_not;
|
||||
|
||||
memset(ve->pad1, 0xff, 14);
|
||||
memset(ve->name, ' ', 16);
|
||||
if (name)
|
||||
|
@ -1750,6 +1773,7 @@ static void add_to_super_ddf_bvd(struct supertype *st,
|
|||
struct vd_config *vc;
|
||||
__u64 *lba_offset;
|
||||
int mppe;
|
||||
int working;
|
||||
|
||||
for (dl = ddf->dlist; dl ; dl = dl->next)
|
||||
if (dl->major == dk->major &&
|
||||
|
@ -1764,10 +1788,28 @@ static void add_to_super_ddf_bvd(struct supertype *st,
|
|||
lba_offset = (__u64*)(vc->phys_refnum + mppe);
|
||||
lba_offset[dk->raid_disk] = 0; /* FIXME */
|
||||
|
||||
dl->vlist[0] =ddf->newconf; /* FIXME */
|
||||
dl->vlist[0] = ddf->newconf; /* FIXME */
|
||||
|
||||
dl->fd = fd;
|
||||
dl->devname = devname;
|
||||
|
||||
/* Check how many working raid_disks, and if we can mark
|
||||
* array as optimal yet
|
||||
*/
|
||||
working = 0;
|
||||
#if 0
|
||||
for (i=0; i < __be16_to_cpu(vc->prim_elmnt_count); i++)
|
||||
if (vc->phys_refnum[i] != 0xffffffff)
|
||||
working++;
|
||||
if (working == __be16_to_cpu(vc->prim_elmnt_count))
|
||||
->entries[xx].state = (->entries[xx].state & ~DDF_state_mask)
|
||||
| DDF_state_optimal;
|
||||
|
||||
if (vc->prl == DDF_RAID6 &&
|
||||
working+1 == __be16_to_cpu(vc->prim_elmnt_count))
|
||||
->entries[xx].state = (->entries[xx].state & ~DDF_state_mask)
|
||||
| DDF_state_part_optimal;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* add a device to a container, either while creating it or while
|
||||
|
@ -1838,7 +1880,7 @@ static void add_to_super_ddf(struct supertype *st,
|
|||
*/
|
||||
|
||||
#ifndef MDASSEMBLE
|
||||
static int write_init_super_ddf(struct supertype *st)
|
||||
static int __write_init_super_ddf(struct supertype *st, int do_close)
|
||||
{
|
||||
|
||||
struct ddf_super *ddf = st->sb;
|
||||
|
@ -1918,10 +1960,19 @@ static int write_init_super_ddf(struct supertype *st)
|
|||
|
||||
lseek64(fd, (size-1)*512, SEEK_SET);
|
||||
write(fd, &ddf->anchor, 512);
|
||||
close(fd);
|
||||
if (do_close) {
|
||||
close(fd);
|
||||
d->fd = -1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int write_init_super_ddf(struct supertype *st)
|
||||
{
|
||||
return __write_init_super_ddf(st, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
|
||||
|
@ -2260,11 +2311,11 @@ static int load_super_ddf_all(struct supertype *st, int fd,
|
|||
for (sd = sra->devs ; sd ; sd = sd->next) {
|
||||
int rv;
|
||||
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
|
||||
dfd = dev_open(nm, keep_fd? O_RDWR : O_RDONLY);
|
||||
if (!dfd)
|
||||
dfd = dev_open(nm, O_RDONLY);
|
||||
if (dfd < 0)
|
||||
return 2;
|
||||
rv = load_ddf_headers(dfd, super, NULL);
|
||||
if (!keep_fd) close(dfd);
|
||||
close(dfd);
|
||||
if (rv == 0) {
|
||||
seq = __be32_to_cpu(super->active->seq);
|
||||
if (super->active->openflag)
|
||||
|
@ -2280,7 +2331,7 @@ static int load_super_ddf_all(struct supertype *st, int fd,
|
|||
/* OK, load this ddf */
|
||||
sprintf(nm, "%d:%d", best->disk.major, best->disk.minor);
|
||||
dfd = dev_open(nm, O_RDONLY);
|
||||
if (!dfd)
|
||||
if (dfd < 0)
|
||||
return 1;
|
||||
load_ddf_headers(dfd, super, NULL);
|
||||
load_ddf_global(dfd, super, NULL);
|
||||
|
@ -2289,7 +2340,7 @@ static int load_super_ddf_all(struct supertype *st, int fd,
|
|||
for (sd = sra->devs ; sd ; sd = sd->next) {
|
||||
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
|
||||
dfd = dev_open(nm, keep_fd? O_RDWR : O_RDONLY);
|
||||
if (!dfd)
|
||||
if (dfd < 0)
|
||||
return 2;
|
||||
seq = load_ddf_local(dfd, super, NULL, keep_fd);
|
||||
if (!keep_fd) close(dfd);
|
||||
|
@ -2349,7 +2400,9 @@ static struct mdinfo *container_content_ddf(struct supertype *st)
|
|||
if (memcmp(ddf->virt->entries[i].guid,
|
||||
vc->conf.guid, DDF_GUID_LEN) == 0)
|
||||
break;
|
||||
if (ddf->virt->entries[i].state & DDF_state_inconsistent)
|
||||
if ((ddf->virt->entries[i].state & DDF_state_inconsistent) ||
|
||||
(ddf->virt->entries[i].init_state & DDF_initstate_mask) !=
|
||||
DDF_init_full)
|
||||
this->array.state = 0;
|
||||
else
|
||||
this->array.state = 1;
|
||||
|
@ -2478,13 +2531,110 @@ static void ddf_mark_clean(struct active_array *a, unsigned long long sync_pos)
|
|||
ddf->virt->entries[inst].state &= ~DDF_state_inconsistent;
|
||||
}
|
||||
|
||||
/*
|
||||
* The state of each disk is stored in the global phys_disk structure
|
||||
* in phys_disk.entries[n].state.
|
||||
* This makes various combinations awkward.
|
||||
* - When a device fails in any array, it must be failed in all arrays
|
||||
* that include a part of this device.
|
||||
* - When a component is rebuilding, we cannot include it officially in the
|
||||
* array unless this is the only array that uses the device.
|
||||
*
|
||||
* So: when transitioning:
|
||||
* Online -> failed, just set failed flag. monitor will propagate
|
||||
* spare -> online, the device might need to be added to the array.
|
||||
* spare -> failed, just set failed. Don't worry if in array or not.
|
||||
*/
|
||||
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;
|
||||
struct vd_config *vc = find_vdcr(ddf, inst);
|
||||
int pd = find_phys(ddf, vc->phys_refnum[n]);
|
||||
int i, st, working;
|
||||
|
||||
if (vc == NULL) {
|
||||
fprintf(stderr, "ddf: cannot find instance %d!!\n", inst);
|
||||
return;
|
||||
}
|
||||
if (pd < 0) {
|
||||
/* disk doesn't currently exist. 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 */
|
||||
}
|
||||
} else {
|
||||
if (state & DS_FAULTY)
|
||||
ddf->phys->entries[pd].state |= __cpu_to_be16(DDF_Failed);
|
||||
if (state & DS_INSYNC) {
|
||||
ddf->phys->entries[pd].state |= __cpu_to_be16(DDF_Online);
|
||||
ddf->phys->entries[pd].state &= __cpu_to_be16(~DDF_Rebuilding);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to check the state of the array and update
|
||||
* virtual_disk.entries[n].state.
|
||||
* It needs to be one of "optimal", "degraded", "failed".
|
||||
* I don't understand 'deleted' or 'missing'.
|
||||
*/
|
||||
working = 0;
|
||||
for (i=0; i < a->info.array.raid_disks; i++) {
|
||||
pd = find_phys(ddf, vc->phys_refnum[i]);
|
||||
if (pd < 0)
|
||||
continue;
|
||||
st = ddf->phys->entries[pd].state;
|
||||
if ((state & (DDF_Online|DDF_Failed|DDF_Rebuilding))
|
||||
== DDF_Online)
|
||||
working++;
|
||||
}
|
||||
state = DDF_state_degraded;
|
||||
if (working == a->info.array.raid_disks)
|
||||
state = DDF_state_optimal;
|
||||
else switch(vc->prl) {
|
||||
case DDF_RAID0:
|
||||
case DDF_CONCAT:
|
||||
case DDF_JBOD:
|
||||
state = DDF_state_failed;
|
||||
break;
|
||||
case DDF_RAID1:
|
||||
if (working == 0)
|
||||
state = DDF_state_failed;
|
||||
break;
|
||||
case DDF_RAID4:
|
||||
case DDF_RAID5:
|
||||
if (working < a->info.array.raid_disks-1)
|
||||
state = DDF_state_failed;
|
||||
break;
|
||||
case DDF_RAID6:
|
||||
if (working < a->info.array.raid_disks-2)
|
||||
state = DDF_state_failed;
|
||||
else if (working == a->info.array.raid_disks-1)
|
||||
state = DDF_state_part_optimal;
|
||||
break;
|
||||
}
|
||||
|
||||
ddf->virt->entries[inst].state =
|
||||
(ddf->virt->entries[inst].state & ~DDF_state_mask)
|
||||
| state;
|
||||
|
||||
fprintf(stderr, "ddf: set_disk %d\n", n);
|
||||
}
|
||||
|
||||
static void ddf_sync_metadata(struct active_array *a)
|
||||
{
|
||||
|
||||
/*
|
||||
* Write all data to all devices.
|
||||
* Later, we might be able to track whether only local changes
|
||||
* have been made, or whether any global data has been changed,
|
||||
* but ddf is sufficiently weird that it probably always
|
||||
* changes global data ....
|
||||
*/
|
||||
__write_init_super_ddf(a->container, 0);
|
||||
fprintf(stderr, "ddf: sync_metadata\n");
|
||||
}
|
||||
|
||||
|
@ -2543,6 +2693,7 @@ struct superswitch super_ddf_container = {
|
|||
.free_super = free_super_ddf,
|
||||
|
||||
.container_content = container_content_ddf,
|
||||
.getinfo_super_n = getinfo_super_n_container,
|
||||
|
||||
.major = 1000,
|
||||
.swapuuid = 0,
|
||||
|
|
Loading…
Reference in New Issue