[PATCH] Assemble: start dirty and degraded array.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The case when array is already degraded has been omitted
by commit 7b99edab2834 ("Assemble.c: respect force flag.").
Appropriative support has been added now.

Handlers for "run" and "force" have been divided into independent
routines. Especially force has to be as meaningless as possible.
It respects following rules:
    - user agrees to start array as degraded (by --run) or is already
      degraded
    - raid456 module is in use
    - some drives are missing (to limit potential abuses)

It doesn't allow to skip resync on dirty, but not degraded array.

This patch cleans up message generation for external array and makes it
consistent. Following code could be reused also for native.

In current implementation assemble_container_content is called once, in
both Incremental or Assembly mode. Thus makes that partial assembly is
not likely to happen. It is possible, but requires user input.
Partial assembly during reshape fails (sysfs_set_array
error - not yet investigated). For now I put FIXME to mark current
logic as known to be buggy because preexist_cnt contains both exp_cnt
and new_cnt which may produce an incorrect message.

Check for new disks and runstop is unnecessary, so has been removed.
This allows to print assemble status in every case, even if nothing new
happens.

Reported-by: Devon Beets <devon@xxxxxxxxxxxxxxxx>
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@xxxxxxxxxxxxxxx>
---
 Assemble.c    | 176 +++++++++++++++++++++++++++++---------------------
 mdadm.8.in    |   3 +-
 super-intel.c |   4 --
 3 files changed, 103 insertions(+), 80 deletions(-)

diff --git a/Assemble.c b/Assemble.c
index 5c6aca92..f954b4db 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -25,6 +25,63 @@
 #include	"mdadm.h"
 #include	<ctype.h>
 
+mapping_t assemble_statuses[] = {
+	{ "but cannot be started", INCR_NO },
+	{ "but not safe to start", INCR_UNSAFE },
+	{ "and started", INCR_YES },
+	{ NULL, INCR_ALREADY }
+};
+
+
+/**
+ * struct assembly_array_info - General, meaningful information for assembly.
+ * @name: Array name.
+ * @new_cnt: Count of drives known to be members, recently added.
+ * @preexist_cnt: Count of member drives in pre-assembled array.
+ * @exp_cnt: Count of known expansion targets.
+ *
+ * FIXME: @exp_new_cnt for recently added expansion targets.
+ */
+struct assembly_array_info {
+	char *name;
+	int new_cnt;
+	int preexist_cnt;
+	int exp_cnt;
+};
+
+/**
+ * set_array_assembly_status() - generate status of assembly for an array.
+ * @c: Global settings.
+ * @result: Pointer to status mask.
+ * @status: Status to be set/printed.
+ * @arr: Array information.
+ *
+ *  Print status message to user or set it in @result if it is not NULL.
+ */
+static void set_array_assembly_status(struct context *c,
+				   int *result, int status,
+				   struct assembly_array_info *arr)
+{
+	int raid_disks = arr->preexist_cnt + arr->new_cnt;
+	char *status_msg = map_num(assemble_statuses, status);
+
+	if (c->export && result)
+		*result |= status;
+
+	if (c->export || c->verbose < 0)
+		return;
+
+	pr_err("%s has been assembled with %d device%s", arr->name,
+	       raid_disks, raid_disks == 1 ? "":"s");
+	if (arr->preexist_cnt > 0)
+		fprintf(stderr, " (%d new)", arr->new_cnt);
+	if (arr->exp_cnt)
+		fprintf(stderr, " ( + %d for expansion)", arr->exp_cnt);
+	if (status_msg)
+		fprintf(stderr, " %s", status_msg);
+	fprintf(stderr, ".\n");
+}
+
 static int name_matches(char *found, char *required, char *homehost, int require_homehost)
 {
 	/* See if the name found matches the required name, possibly
@@ -1911,12 +1968,12 @@ int assemble_container_content(struct supertype *st, int mdfd,
 			       char *chosen_name, int *result)
 {
 	struct mdinfo *dev, *sra, *dev2;
-	int working = 0, preexist = 0;
-	int expansion = 0;
+	struct assembly_array_info array = {chosen_name, 0, 0, 0};
 	int old_raid_disks;
 	int start_reshape;
 	char *avail;
 	int err;
+	int is_raid456, is_clean, all_disks;
 
 	if (sysfs_init(content, mdfd, NULL)) {
 		pr_err("Unable to initialize sysfs\n");
@@ -1973,17 +2030,16 @@ int assemble_container_content(struct supertype *st, int mdfd,
 		if (sysfs_add_disk(content, dev, 1) == 0) {
 			if (dev->disk.raid_disk >= old_raid_disks &&
 			    content->reshape_active)
-				expansion++;
+				array.exp_cnt++;
 			else
-				working++;
+				array.new_cnt++;
 		} else if (errno == EEXIST)
-			preexist++;
+			array.preexist_cnt++;
 	}
 	sysfs_free(sra);
-	if (working + expansion == 0 && c->runstop <= 0) {
-		free(avail);
-		return 1;/* Nothing new, don't try to start */
-	}
+
+	all_disks = array.new_cnt + array.exp_cnt + array.preexist_cnt;
+
 	map_update(NULL, fd2devnm(mdfd), content->text_version,
 		   content->uuid, chosen_name);
 
@@ -2045,53 +2101,40 @@ int assemble_container_content(struct supertype *st, int mdfd,
 		content->array.state |= 1;
 	}
 
+	is_raid456 = (content->array.level >= 4 && content->array.level <= 6);
+	is_clean = content->array.state & 1;
+
 	if (enough(content->array.level, content->array.raid_disks,
-		   content->array.layout, content->array.state & 1, avail) == 0) {
-		if (c->export && result)
-			*result |= INCR_NO;
-		else if (c->verbose >= 0) {
-			pr_err("%s assembled with %d device%s",
-			       chosen_name, preexist + working,
-			       preexist + working == 1 ? "":"s");
-			if (preexist)
-				fprintf(stderr, " (%d new)", working);
-			fprintf(stderr, " but not started\n");
-		}
+		   content->array.layout, is_clean, avail) == 0) {
+		set_array_assembly_status(c, result, INCR_NO, &array);
+
+		if (c->verbose >= 0 && is_raid456 && !is_clean)
+			pr_err("Consider --force to start dirty degraded array\n");
+
 		free(avail);
 		return 1;
 	}
 	free(avail);
 
-	if ((working + preexist + expansion) < content->array.working_disks) {
-		if (c->runstop <= 0) {
-			if (c->export && result)
-				*result |= INCR_UNSAFE;
-			else if (c->verbose >= 0) {
-				pr_err("%s assembled with %d device%s",
-					chosen_name, preexist + working,
-					preexist + working == 1 ? "":"s");
-				if (preexist)
-					fprintf(stderr, " (%d new)", working);
-				fprintf(stderr, " but not safe to start\n");
-				if (c->force)
-					pr_err("Consider --run to start array as degraded.\n");
-			}
+	if (c->runstop <= 0 && all_disks < content->array.working_disks) {
+
+		set_array_assembly_status(c, result, INCR_UNSAFE, &array);
+
+		if (c->verbose >= 0 && c->force)
+			pr_err("Consider --run to start array as degraded.\n");
+		return 1;
+	}
+
+	if (is_raid456 && content->resync_start != MaxSector && c->force &&
+	    all_disks < content->array.raid_disks) {
+
+		content->resync_start = MaxSector;
+		err = sysfs_set_num(content, NULL, "resync_start", MaxSector);
+		if (err)
 			return 1;
-		} else if (content->array.level >= 4 &&
-			   content->array.level <= 6 &&
-			   content->resync_start != MaxSector &&
-			   c->force) {
-			/* Don't inform the kernel that the array is not
-			 * clean and requires resync.
-			 */
-			content->resync_start = MaxSector;
-			err = sysfs_set_num(content, NULL, "resync_start",
-					    MaxSector);
-			if (err)
-				return 1;
-			pr_err("%s array state forced to clean. It may cause data corruption.\n",
-				chosen_name);
-		}
+
+		pr_err("%s array state forced to clean. It may cause data corruption.\n",
+		       chosen_name);
 	}
 
 	/*
@@ -2103,9 +2146,9 @@ int assemble_container_content(struct supertype *st, int mdfd,
 		st->ss->set_bitmap(st, content);
 
 	if (start_reshape) {
-		int spare = content->array.raid_disks + expansion;
+		int spare = content->array.raid_disks + array.exp_cnt;
 		if (restore_backup(st, content,
-				   working,
+				   array.new_cnt,
 				   spare, &c->backup_file, c->verbose) == 1)
 			return 1;
 
@@ -2168,31 +2211,14 @@ int assemble_container_content(struct supertype *st, int mdfd,
 	    !start_reshape)
 		block_subarray(content);
 
-	if (c->export && result) {
-		if (err)
-			*result |= INCR_NO;
-		else
-			*result |= INCR_YES;
-	} else if (c->verbose >= 0) {
-		if (err)
-			pr_err("array %s now has %d device%s",
-			       chosen_name, working + preexist,
-			       working + preexist == 1 ? "":"s");
-		else {
-			sysfs_rules_apply(chosen_name, content);
-			pr_err("Started %s with %d device%s",
-			       chosen_name, working + preexist,
-			       working + preexist == 1 ? "":"s");
-		}
-		if (preexist)
-			fprintf(stderr, " (%d new)", working);
-		if (expansion)
-			fprintf(stderr, " ( + %d for expansion)",
-				expansion);
-		fprintf(stderr, "\n");
-	}
-	if (!err)
+	if (err)
+		set_array_assembly_status(c, result, INCR_NO, &array);
+	else {
+		set_array_assembly_status(c, result, INCR_YES, &array);
 		wait_for(chosen_name, mdfd);
+		sysfs_rules_apply(chosen_name, content);
+	}
+
 	return err;
 	/* FIXME should have an O_EXCL and wait for read-auto */
 }
diff --git a/mdadm.8.in b/mdadm.8.in
index 7cdb465d..8d7aad0c 100644
--- a/mdadm.8.in
+++ b/mdadm.8.in
@@ -1132,7 +1132,8 @@ out-of-date.  If
 .I mdadm
 cannot find enough working devices to start the array, but can find
 some devices that are recorded as having failed, then it will mark
-those devices as working so that the array can be started.
+those devices as working so that the array can be started. This works only for
+native. For external metadata it allows to start dirty degraded RAID 4, 5, 6.
 An array which requires
 .B \-\-force
 to be started may contain data corruption.  Use it carefully.
diff --git a/super-intel.c b/super-intel.c
index 54699129..c8fd0971 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -8108,10 +8108,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 				if ((!able_to_resync(level, missing) ||
 				     recovery_start == 0))
 					this->resync_start = MaxSector;
-			} else {
-				/*
-				 * FIXME handle dirty degraded
-				 */
 			}
 
 			if (skip)
-- 
2.26.2




[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux