summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-03-15 15:35:04 +1100
committerNeilBrown <neilb@suse.de>2011-03-15 15:35:04 +1100
commit88b496c2697ed531ffecf2f8ced76f437297e5fe (patch)
tree59eaa8dc9f7fd06f8bf54191c0c790e332c02768
parente26c926209d84683815275bf8a3850b00731937e (diff)
parent666bba9b5011150ff01de421dd44b06c0a6610a5 (diff)
downloadmdadm-88b496c2697ed531ffecf2f8ced76f437297e5fe.tar.gz
Merge branch 'master' into devel-3.2
Conflicts: Manage.c managemon.c super-ddf.c super-intel.c
-rw-r--r--Manage.c12
-rw-r--r--managemon.c7
-rw-r--r--mdadm.8.in11
-rw-r--r--super-ddf.c73
4 files changed, 91 insertions, 12 deletions
diff --git a/Manage.c b/Manage.c
index 5fc67d7..5996646 100644
--- a/Manage.c
+++ b/Manage.c
@@ -796,7 +796,7 @@ int Manage_subdevs(char *devname, int fd,
disc.minor = minor(stb.st_rdev);
disc.number =j;
disc.state = 0;
- if (array.not_persistent==0 || tst->ss->external) {
+ if (array.not_persistent==0) {
int dfd;
if (dv->writemostly == 1)
disc.state |= 1 << MD_DISK_WRITEMOSTLY;
@@ -852,6 +852,7 @@ int Manage_subdevs(char *devname, int fd,
struct mdinfo *sra;
int container_fd;
int devnum = fd2devnum(fd);
+ int dfd;
container_fd = open_dev_excl(devnum);
if (container_fd < 0) {
@@ -862,6 +863,15 @@ int Manage_subdevs(char *devname, int fd,
return 1;
}
+ dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
+ if (tst->ss->add_to_super(tst, &disc, dfd,
+ dv->devname)) {
+ close(dfd);
+ close(container_fd);
+ return 1;
+ }
+ close(dfd);
+
sra = sysfs_read(container_fd, -1, 0);
if (!sra) {
fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n",
diff --git a/managemon.c b/managemon.c
index 15b6e69..d6c57f7 100644
--- a/managemon.c
+++ b/managemon.c
@@ -465,7 +465,12 @@ static void manage_member(struct mdstat_ent *mdstat,
}
}
- if (a->check_degraded && !frozen) {
+ /* We don't check the array while any update is pending, as it
+ * might container a change (such as a spare assignment) which
+ * could affect our decisions.
+ */
+ if (a->check_degraded && !frozen &&
+ update_queue == NULL && update_queue_pending == NULL) {
struct metadata_update *updates = NULL;
struct mdinfo *newdev = NULL;
struct active_array *newa;
diff --git a/mdadm.8.in b/mdadm.8.in
index d99bc05..4b70e20 100644
--- a/mdadm.8.in
+++ b/mdadm.8.in
@@ -2240,8 +2240,12 @@ space to start being used. If the size is increased in this way, a
are synchronised.
Note that when an array changes size, any filesystem that may be
-stored in the array will not automatically grow to use the space. The
-filesystem will need to be explicitly told to use the extra space.
+stored in the array will not automatically grow for shrink to use or
+vacate the space. The
+filesystem will need to be explicitly told to use the extra space
+after growing, or to reduce its size
+.B prior
+to shrinking the array.
Also the size of an array cannot be changed while it has an active
bitmap. If an array has a bitmap, it must be removed before the size
@@ -2281,7 +2285,8 @@ the reshape happen, and then convert the RAID4 back to RAID0.
When decreasing the number of devices, the size of the array will also
decrease. If there was data in the array, it could get destroyed and
-this is not reversible. To help prevent accidents,
+this is not reversible, so you should firstly shrink the filesystem on
+the array to fit within the new size. To help prevent accidents,
.I mdadm
requires that the size of the array be decreased first with
.BR "mdadm --grow --array-size" .
diff --git a/super-ddf.c b/super-ddf.c
index bdce4a7..72b87ff 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -3211,7 +3211,8 @@ static void ddf_set_disk(struct active_array *a, int n, int state)
/* and find the 'dl' entry corresponding to that. */
for (dl = ddf->dlist; dl; dl = dl->next)
- if (mdi->disk.major == dl->major &&
+ if (mdi->state_fd >= 0 &&
+ mdi->disk.major == dl->major &&
mdi->disk.minor == dl->minor)
break;
if (!dl)
@@ -3273,6 +3274,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:
@@ -3356,6 +3359,7 @@ static void ddf_process_update(struct supertype *st,
struct dl *dl;
unsigned int mppe;
unsigned int ent;
+ unsigned int pdnum, pd2;
dprintf("Process update %x\n", *magic);
@@ -3466,17 +3470,38 @@ static void ddf_process_update(struct supertype *st,
}
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) {
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)
@@ -3484,8 +3509,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 &=
@@ -3501,6 +3532,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:
@@ -3657,13 +3715,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;