[PATCH 07/13] imsm: extension of delete subarray to handle active container

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

 



For active container with remaining raid0 volume (mdmon is not running)
patch adds possibility to delete subarray and update metadata on all
component devices belonging to this volume.

Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@xxxxxxxxx>
---
 Makefile      |    4 +-
 mdadm.h       |   21 +++++
 super-intel.c |   40 +++++++++
 util.c        |  262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 325 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 1035ea8..1eb3e4b 100644
--- a/Makefile
+++ b/Makefile
@@ -96,12 +96,12 @@ SRCS =  mdadm.c config.c mdstat.c  ReadMe.c util.c Manage.c Assemble.c Build.c \
 
 MON_OBJS = mdmon.o monitor.o managemon.o util.o mdstat.o sysfs.o config.o \
 	Kill.o sg_io.o dlink.o ReadMe.o super0.o super1.o super-intel.o \
-	super-ddf.o sha1.o crc32.o msg.o bitmap.o \
+	super-ddf.o sha1.o crc32.o msg.o bitmap.o mdopen.o mapfile.o \
 	platform-intel.o probe_roms.o
 
 MON_SRCS = mdmon.c monitor.c managemon.c util.c mdstat.c sysfs.c config.c \
 	Kill.c sg_io.c dlink.c ReadMe.c super0.c super1.c super-intel.c \
-	super-ddf.c sha1.c crc32.c msg.c bitmap.c \
+	super-ddf.c sha1.c crc32.c msg.c bitmap.c mdopen.c mapfile.c \
 	platform-intel.c probe_roms.c
 
 STATICSRC = pwgr.c
diff --git a/mdadm.h b/mdadm.h
index cfbe407..2a5ca3b 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -722,6 +722,20 @@ extern void get_one_disk(int mdfd, mdu_array_info_t *ainf,
 			 mdu_disk_info_t *disk);
 void wait_for(char *dev, int fd);
 
+/*
+ * Array dynamic list holds the most important data to remember
+ * during the validation of the devices passed to some metadata
+ * manipulation functions (eg. delete subarray).
+ */
+struct array_dev_list {
+	int major;
+	int minor;
+	int found; /* mark here if disk is found in command line */
+	int fd; /* file descriptor of opened device*/
+	struct supertype *st; /* supertype record obtained from this device */
+	struct array_dev_list *next; /* next item */
+};
+
 #if __GNUC__ < 3
 struct stat64;
 #endif
@@ -928,6 +942,13 @@ extern int devname2devnum(char *name);
 extern int stat2devnum(struct stat *st);
 extern int fd2devnum(int fd);
 
+extern int find_array_minor(char *text_version, struct map_ent *map, int *minor);
+extern struct array_dev_list *get_devs_from_container(char *name, struct supertype **st);
+extern struct array_dev_list *array_dev_list_add(struct array_dev_list **dl, int maj, int min, struct supertype *st);
+extern void free_array_dev_list(struct array_dev_list *dl);
+extern struct array_dev_list *check_find_devices(mddev_dev_t devlist, int force, int quiet, struct mddev_ident_s *ident, char *meta_type, int *index, int *mon_managed);
+extern struct array_dev_list *check_devices(mddev_dev_t devlist, int force, int quiet, char *meta_type);
+
 static inline int dev2major(int d)
 {
 	if (d >= 0)
diff --git a/super-intel.c b/super-intel.c
index ff6fb52..10cf814 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -3470,8 +3470,12 @@ int delete_subarray_imsm(struct supertype *st, int fd)
 		return 1;
 	}
 
+	if (mdmon_running(st->container_dev))
+		return 1;
+
 	/* First case: 2 volumes */
 	if (mpb->num_raid_devs > 1) {
+		struct map_ent *map;
 		struct intel_dev *dp;
 		struct intel_dev *d = super->devlist->next;
 
@@ -3503,6 +3507,42 @@ int delete_subarray_imsm(struct supertype *st, int fd)
 		if (!st->loaded_container)
 			super->disks->fd = fd;
 		rv = write_super_imsm(super, 0);
+
+		/* if necessary re-index all container members */
+		if (st->loaded_container && container_index < mpb->num_raid_devs) {
+			struct map_ent *m;
+			map_read(&map);
+			map_lock(&map);
+			for (m = map; m; m = m->next) {
+				char *ind = strrchr(m->metadata, '/');
+				if (ind++) { /* array */
+					int index = atoi(ind);
+					if (index > container_index) { /* change needed */
+						char path[PATH_MAX];
+						char buf[1024];
+						struct mdinfo info_new;
+						*ind = '0' + --index;
+						/* sysfs */
+						snprintf(path, sizeof(path), "/sys/block/md%d/md/metadata_version", m->devnum);
+						snprintf(buf, sizeof(buf), "external:%s", m->metadata);
+						if (sysfs_set_str_simple(path, buf)) {
+							rv = 1;
+							break;
+						}
+						/* map */
+						strcpy(path, m->path);
+						super->current_vol = index;
+						getinfo_super_imsm_volume(st, &info_new);
+						map_do_update(&map, m->devnum,
+							      info_new.text_version,
+							      info_new.uuid, path);
+					}
+				}
+			}
+			map_write(map);
+			map_unlock(&map);
+			map_free(map);
+		}
 	} else { /* second case: 1 volume */
 		struct dl *d;
 		for (d = super->disks; d; d = d->next)
diff --git a/util.c b/util.c
index 423b66f..7ae0ba7 100644
--- a/util.c
+++ b/util.c
@@ -1649,3 +1649,265 @@ void append_metadata_update(struct supertype *st, void *buf, int len)
 unsigned int __invalid_size_argument_for_IOC = 0;
 #endif
 
+/* Function finds device minor of the device located in map file */
+int find_array_minor(char *text_version, struct map_ent *map, int *minor)
+{
+	if (!text_version || !minor)
+		return -1;
+
+	while (map)
+	{
+		if (!strcmp(map->metadata, text_version)) {
+			*minor = map->devnum;
+			return 0;
+		}
+		map = map->next;
+	}
+	return -1;
+}
+
+void free_array_dev_list(struct array_dev_list *dl)
+{
+	struct array_dev_list *t;
+	while(dl) {
+		t = dl;
+		dl = dl->next;
+		if (t->st)
+			t->st->ss->free_super(t->st);
+		free(t->st);
+		if (t->fd != -1)
+			close(t->fd);
+		free(t);
+	}
+}
+
+struct array_dev_list *array_dev_list_add(struct array_dev_list **dl, int maj, int min, struct supertype *st)
+{
+	struct array_dev_list *temp;
+
+	if (!dl)
+		return NULL;
+
+	temp = malloc(sizeof(*temp));
+	if (!temp) {
+		free_array_dev_list(*dl);
+		return NULL;
+	}
+	temp->next = *dl;
+	temp->major = maj;
+	temp->minor = min;
+	temp->found = 0;
+	temp->fd = -1;
+	temp->st = st;
+
+	*dl = temp;
+	return *dl;
+}
+
+struct array_dev_list *get_devs_from_container(char *name, struct supertype **st)
+{
+	int fd;
+	struct array_dev_list *dl = NULL;
+	struct mdinfo *mdi, *devs;
+
+	if (!st || !name)
+		return NULL;
+
+	if ((fd = open_mddev(name, 0)) == -1)
+		return NULL;
+
+	(*st) = guess_super(fd);
+
+	if (!*st) {
+		close(fd);
+		*st = NULL;
+		return NULL;
+	}
+
+	if ((*st)->ss->load_super(*st, fd, name)) {
+		*st = NULL;
+		close(fd);
+		return NULL;
+	}
+
+	mdi = sysfs_read(fd, 0, GET_DEVS);
+	if (!mdi) {
+		close(fd);
+		return NULL;
+	}
+
+	for (devs = mdi->devs; devs; devs = devs->next) {
+		if (devs->disk.state & (1 << MD_DISK_FAULTY))
+			continue;
+		if (!array_dev_list_add(&dl, devs->disk.major, devs->disk.minor, NULL)) {
+			close(fd);
+			(*st)->ss->free_super(*st);
+			*st = NULL;
+			sysfs_free(mdi);
+			return NULL;
+		}
+	}
+	close(fd);
+	sysfs_free(mdi);
+	return dl;
+}
+
+struct array_dev_list *check_devices(mddev_dev_t devlist, int force, int quiet, char *meta_type)
+{
+	int	fd;
+	struct supertype *st, *cst = NULL, *ref = NULL;
+	char	container_devname[255];
+	mddev_dev_t dv;
+	int	active_container = 0;
+	struct array_dev_list *dl = NULL, *d;
+
+	if (!devlist)
+		return NULL;
+
+	container_devname[0] = '\0';
+
+	for (dv = devlist; dv; dv = dv->next) {
+		fd = open(dv->devname, O_RDWR|(force ? O_NONBLOCK : 0));
+		if (fd < 0) {
+			if (!quiet)
+				fprintf(stderr, Name ": Couldn't open %s for read/write\n",
+					dv->devname);
+			free_array_dev_list(dl);
+			close(fd);
+			return NULL;
+		}
+		st = guess_super(fd);
+
+		if (!st) {
+			if (!quiet)
+				fprintf(stderr, Name ": Unrecognised md component device - %s\n",
+					dv->devname);
+			free_array_dev_list(dl);
+			close(fd);
+			return NULL;
+		}
+
+		if (!st->ss->match_metadata_desc(meta_type)) {
+			if (!quiet)
+				fprintf(stderr, Name ": Only %s metadata allowed\n", meta_type);
+			free_array_dev_list(dl);
+			close(fd);
+			return NULL;
+		}
+
+		if (st->ss->load_super(st, fd, dv->devname)) {
+			if (!quiet)
+				fprintf(stderr, Name ": Could not load superblock on %s\n", dv->devname);
+			free_array_dev_list(dl);
+			close(fd);
+			return NULL;
+		}
+		/* this device is a container */
+		if (st->loaded_container) { /* check if other devices passed */
+			if (ref || dv->next) {
+				fprintf(stderr, Name ": Container device should be the only one provided\n");
+				free_array_dev_list(dl);
+				close(fd);
+				return NULL;
+			}
+			active_container = 1;
+			strncpy(container_devname, dv->devname, sizeof(container_devname));
+			cst = st;
+			break;
+		} else {
+			/* so find active container comprises this device */
+			struct mdstat_ent *ent;
+			char *name = strrchr(dv->devname, '/');
+			if (name++) {
+				ent = mdstat_by_component(name);
+				if (ent) {
+					active_container = 1;
+					if (container_devname[0]) {
+						char *tmp = strrchr(container_devname, '/');
+						if (!tmp++) {
+							fprintf(stderr, Name ": Container device path is invalid\n");
+							free_array_dev_list(dl);
+							close(fd);
+							return NULL;
+						}
+						if (strcmp(tmp, ent->dev)) {
+							fprintf(stderr, Name ": Given devices does not belong to the same container\n");
+							free_array_dev_list(dl);
+							close(fd);
+							return NULL;
+						}
+					}
+					else
+						snprintf(container_devname, sizeof(container_devname), "/dev/%s", ent->dev);
+					if (!dl)
+						dl = get_devs_from_container(container_devname, &cst);
+
+					/* and get valid container disk members */
+					for (d = dl; d; d = d->next) {
+						struct stat stat;
+						if (fstat(fd, &stat) == -1) {
+							close(fd);
+							free_array_dev_list(dl);
+							return NULL;
+						}
+						if (d->major == MAJOR(stat.st_rdev) && d->minor == MINOR(stat.st_rdev)) {
+							d->found = 1;
+							d->st = st;
+							d->fd = fd;
+							break;
+						}
+					}
+				} else {
+					struct mdinfo i;
+					st->ss->getinfo_super(st, &i);
+					array_dev_list_add(&dl, i.disk.major, i.disk.minor, st);
+					dl->fd = fd;
+					continue;
+				}
+			}
+			close(fd);
+		}
+
+		if (!ref) {
+			ref = st;
+			close(fd);
+			continue;
+		}
+		if (st->ss->compare_super(st, ref)) {
+			free_array_dev_list(dl);
+			close(fd);
+			fprintf(stderr, Name ": Given devices does not belong to the same array\n");
+			return NULL;
+		}
+	}
+
+	if (active_container) {
+		for (d = dl; d; d = d->next) {
+			if (!d->found)
+				break;
+		}
+		if (d) {
+			free_array_dev_list(dl);
+			fprintf(stderr, Name ": Array containing given devices is active. "
+				"Please provide full set of drives\n");
+			return NULL;
+		}
+	}
+
+	/* For case of active container, use container's supertype data
+	 */
+	if (cst)
+	{
+		free_array_dev_list(dl);
+		dl = NULL;
+		array_dev_list_add(&dl, -1, -1, cst);
+		if ((dl->fd = open_mddev(container_devname, 0)) == -1) {
+			free_array_dev_list(dl);
+			fprintf(stderr, Name ": Could not reopen container device\n");
+			return NULL;
+		}
+	}
+
+	return dl;
+}
+
-- 
1.6.4.2


--
Best Regards,
Przemyslaw Hawrylewicz-Czarnowski
Software Development Engineer


--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[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