svn commit: r217892 - in projects/graid/head: sbin/geom/class/raid sys/geom/raid

Alexander Motin mav at FreeBSD.org
Wed Jan 26 19:24:42 UTC 2011


Author: mav
Date: Wed Jan 26 19:24:41 2011
New Revision: 217892
URL: http://svn.freebsd.org/changeset/base/217892

Log:
  Implement two more `graid` subcommands:
   add - add second volume into existing array;
   delete - delete specified volume or whole array.

Modified:
  projects/graid/head/sbin/geom/class/raid/geom_raid.c
  projects/graid/head/sys/geom/raid/g_raid_ctl.c
  projects/graid/head/sys/geom/raid/md_intel.c

Modified: projects/graid/head/sbin/geom/class/raid/geom_raid.c
==============================================================================
--- projects/graid/head/sbin/geom/class/raid/geom_raid.c	Wed Jan 26 19:01:05 2011	(r217891)
+++ projects/graid/head/sbin/geom/class/raid/geom_raid.c	Wed Jan 26 19:24:41 2011	(r217892)
@@ -57,23 +57,34 @@ struct g_command class_commands[] = {
 		{ 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER },
 		G_OPT_SENTINEL
 	    },
-	    "[-S size] [-s stripsize] format name level prov ..."
+	    "[-S size] [-s stripsize] format label level prov ..."
+	},
+	{ "add", G_FLAG_VERBOSE, NULL,
+	    {
+		{ 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER },
+		{ 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER },
+		G_OPT_SENTINEL
+	    },
+	    "[-S size] [-s stripsize] name label level"
+	},
+	{ "delete", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
+	    "[-v] name [label|num]"
 	},
 	{ "insert", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
-	    "[-v] name prov"
+	    "[-v] name prov ..."
 	},
 	{ "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
-	    "[-v] name prov"
+	    "[-v] name prov ..."
 	},
 	{ "fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
-	    "[-v] name prov"
+	    "[-v] name prov ..."
 	},
 	{ "stop", G_FLAG_VERBOSE, NULL,
 	    {
 		{ 'f', "force", NULL, G_TYPE_BOOL },
 		G_OPT_SENTINEL
 	    },
-	    "[-fv] name ..."
+	    "[-fv] name"
 	},
 	G_CMD_SENTINEL
 };

Modified: projects/graid/head/sys/geom/raid/g_raid_ctl.c
==============================================================================
--- projects/graid/head/sys/geom/raid/g_raid_ctl.c	Wed Jan 26 19:01:05 2011	(r217891)
+++ projects/graid/head/sys/geom/raid/g_raid_ctl.c	Wed Jan 26 19:24:41 2011	(r217892)
@@ -119,7 +119,7 @@ g_raid_ctl_stop(struct gctl_req *req, st
 		gctl_error(req, "No '%s' argument.", "nargs");
 		return;
 	}
-	if (*nargs < 1) {
+	if (*nargs != 1) {
 		gctl_error(req, "Invalid number of arguments.");
 		return;
 	}

Modified: projects/graid/head/sys/geom/raid/md_intel.c
==============================================================================
--- projects/graid/head/sys/geom/raid/md_intel.c	Wed Jan 26 19:01:05 2011	(r217891)
+++ projects/graid/head/sys/geom/raid/md_intel.c	Wed Jan 26 19:24:41 2011	(r217892)
@@ -542,7 +542,7 @@ g_raid_md_intel_start_disk(struct g_raid
 			/* Make sure this disk is big enough. */
 			TAILQ_FOREACH(sd, &olddisk->d_subdisks, sd_next) {
 				if (sd->sd_offset + sd->sd_size + 4096 >
-				    (uint64_t)pd->pd_disk_meta.sectors * 512) {
+				    (off_t)pd->pd_disk_meta.sectors * 512) {
 					G_RAID_DEBUG(1,
 					    "Disk too small (%llu < %llu)",
 					    ((unsigned long long)
@@ -1168,7 +1168,7 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
     struct gctl_req *req)
 {
 	struct g_raid_softc *sc;
-	struct g_raid_volume *vol;
+	struct g_raid_volume *vol, *vol1;
 	struct g_raid_subdisk *sd;
 	struct g_raid_disk *disk;
 	struct g_raid_md_intel_object *mdi;
@@ -1177,8 +1177,9 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 	struct g_provider *pp;
 	char arg[16], serial[INTEL_SERIAL_LEN];
 	const char *verb, *volname, *levelname, *diskname;
+	char *tmp;
 	int *nargs;
-	uint64_t size, sectorsize, strip;
+	off_t off, size, sectorsize, strip;
 	intmax_t *sizearg, *striparg;
 	int numdisks, i, len, level, qual, update;
 	int error;
@@ -1218,7 +1219,7 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 
 		/* Search for disks, connect them and probe. */
 		numdisks = *nargs - 3;
-		size = 0xffffffffffffffffllu;
+		size = 0x7fffffffffffffffllu;
 		sectorsize = 0;
 		for (i = 0; i < numdisks; i++) {
 			snprintf(arg, sizeof(arg), "arg%d", i + 3);
@@ -1304,7 +1305,8 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 		sizearg = gctl_get_param(req, "size", &len);
 		if (sizearg != NULL && len == sizeof(*sizearg)) {
 			if (*sizearg > size) {
-				gctl_error(req, "Size too big.");
+				gctl_error(req, "Size too big %lld > %lld.",
+				    (long long)*sizearg, (long long)size);
 				return (-9);
 			}
 			size = *sizearg;
@@ -1366,6 +1368,217 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 		g_raid_md_write_intel(md, NULL, NULL, NULL);
 		return (0);
 	}
+	if (strcmp(verb, "add") == 0) {
+
+		if (*nargs != 3) {
+			gctl_error(req, "Invalid number of arguments.");
+			return (-1);
+		}
+		volname = gctl_get_asciiparam(req, "arg1");
+		if (volname == NULL) {
+			gctl_error(req, "No volume name.");
+			return (-2);
+		}
+		levelname = gctl_get_asciiparam(req, "arg2");
+		if (levelname == NULL) {
+			gctl_error(req, "No RAID level.");
+			return (-3);
+		}
+		if (g_raid_volume_str2level(levelname, &level, &qual)) {
+			gctl_error(req, "Unknown RAID level '%s'.", levelname);
+			return (-4);
+		}
+		if (level != G_RAID_VOLUME_RL_RAID0 &&
+		    level != G_RAID_VOLUME_RL_RAID1 &&
+		    level != G_RAID_VOLUME_RL_RAID5 &&
+		    level != G_RAID_VOLUME_RL_RAID10) {
+			gctl_error(req, "Unsupported RAID level.");
+			return (-5);
+		}
+
+		/* Look for existing volumes. */
+		i = 0;
+		vol1 = NULL;
+		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
+			vol1 = vol;
+			i++;
+		}
+		if (i > 1) {
+			gctl_error(req, "Maximum two volumes supported.");
+			return (-6);
+		}
+		if (vol1 == NULL) {
+			gctl_error(req, "At least one volume must exist.");
+			return (-7);
+		}
+
+		/* Collect info about present disks. */
+		size = 0x7fffffffffffffffllu;
+		sectorsize = 512;
+		numdisks = vol1->v_disks_count;
+		for (i = 0; i < numdisks; i++) {
+			disk = vol1->v_subdisks[i].sd_disk;
+			pd = (struct g_raid_md_intel_perdisk *)
+			    disk->d_md_data;
+			if ((off_t)pd->pd_disk_meta.sectors * 512 < size)
+				size = (off_t)pd->pd_disk_meta.sectors * 512;
+			if (disk->d_consumer != NULL &&
+			    disk->d_consumer->provider != NULL &&
+			    disk->d_consumer->provider->sectorsize >
+			     sectorsize) {
+				sectorsize =
+				    disk->d_consumer->provider->sectorsize;
+			}
+		}
+
+		/* Reserve some space for metadata. */
+		size -= ((4096 + sectorsize - 1) / sectorsize) * sectorsize;
+
+		/* Decide insert before or after. */
+		sd = &vol1->v_subdisks[0];
+		if (sd->sd_offset >
+		    size - (sd->sd_offset + sd->sd_size)) {
+			off = 0;
+			size = sd->sd_offset;
+		} else {
+			off = sd->sd_offset + sd->sd_size;
+			size = size - (sd->sd_offset + sd->sd_size);
+		}
+
+		/* Handle size argument. */
+		len = sizeof(*sizearg);
+		sizearg = gctl_get_param(req, "size", &len);
+		if (sizearg != NULL && len == sizeof(*sizearg)) {
+			if (*sizearg > size) {
+				gctl_error(req, "Size too big %lld > %lld.",
+				    (long long)*sizearg, (long long)size);
+				return (-9);
+			}
+			size = *sizearg;
+		}
+
+		/* Handle strip argument. */
+		strip = 131072;
+		len = sizeof(*striparg);
+		striparg = gctl_get_param(req, "strip", &len);
+		if (striparg != NULL && len == sizeof(*striparg)) {
+			if (*striparg < sectorsize) {
+				gctl_error(req, "Strip size too small.");
+				return (-10);
+			}
+			if (*striparg % sectorsize != 0) {
+				gctl_error(req, "Incorrect strip size.");
+				return (-11);
+			}
+			if (strip > 65535 * sectorsize) {
+				gctl_error(req, "Strip size too big.");
+				return (-12);
+			}
+			strip = *striparg;
+		}
+		size -= ((strip - off) % strip);
+		off += ((strip - off) % strip);
+		size -= (size % strip);
+
+		if (size <= 0) {
+			gctl_error(req, "No free space.");
+			return (-13);
+		}
+
+		/* We have all we need, create things: volume, ... */
+		vol = g_raid_create_volume(sc, volname);
+		vol->v_md_data = (void *)(intptr_t)i;
+		vol->v_raid_level = level;
+		vol->v_raid_level_qualifier = G_RAID_VOLUME_RLQ_NONE;
+		vol->v_strip_size = strip;
+		vol->v_disks_count = numdisks;
+		if (level == G_RAID_VOLUME_RL_RAID0)
+			vol->v_mediasize = size * numdisks;
+		else if (level == G_RAID_VOLUME_RL_RAID5)
+			vol->v_mediasize = size * (numdisks - 1);
+		else
+			vol->v_mediasize = size * (numdisks / 2);
+		vol->v_sectorsize = sectorsize;
+		g_raid_start_volume(vol);
+
+		/* , and subdisks. */
+		for (i = 0; i < numdisks; i++) {
+			disk = vol1->v_subdisks[i].sd_disk;
+			sd = &vol->v_subdisks[i];
+			sd->sd_disk = disk;
+			sd->sd_offset = off;
+			sd->sd_size = size;
+			TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
+			if (disk->d_state == G_RAID_DISK_S_ACTIVE) {
+				g_raid_change_subdisk_state(sd,
+				    G_RAID_SUBDISK_S_ACTIVE);
+				g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
+				    G_RAID_EVENT_SUBDISK);
+			}
+		}
+
+		/* Write metadata based on created entities. */
+		g_raid_md_write_intel(md, NULL, NULL, NULL);
+		return (0);
+	}
+	if (strcmp(verb, "delete") == 0) {
+
+		/* Full node destruction. */
+		if (*nargs == 1) {
+			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
+				if (disk->d_consumer)
+					intel_meta_erase(disk->d_consumer);
+			}
+			g_raid_destroy_node(sc, 0);
+			return (0);
+		}
+
+		/* Destroy specified volume. If it was last - all node. */
+		if (*nargs != 2) {
+			gctl_error(req, "Invalid number of arguments.");
+			return (-1);
+		}
+		volname = gctl_get_asciiparam(req, "arg1");
+		if (volname == NULL) {
+			gctl_error(req, "No volume name.");
+			return (-2);
+		}
+
+		/* Search for volume. */
+		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
+			if (strcmp(vol->v_name, volname) == 0)
+				break;
+		}
+		if (vol == NULL) {
+			i = strtol(volname, &tmp, 10);
+			if (verb != volname && tmp[0] == 0) {
+				TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
+					if ((intptr_t)vol->v_md_data == i)
+						break;
+				}
+			}
+		}
+		if (vol == NULL) {
+			gctl_error(req, "Volume '%s' not found.", volname);
+			return (-3);
+		}
+
+		/* Destroy volume and potentially node. */
+		i = 0;
+		TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next)
+			i++;
+		if (i >= 2) {
+			g_raid_destroy_volume(vol);
+			g_raid_md_write_intel(md, NULL, NULL, NULL);
+		} else {
+			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
+				if (disk->d_consumer)
+					intel_meta_erase(disk->d_consumer);
+			}
+			g_raid_destroy_node(sc, 0);
+		}
+		return (0);
+	}
 	if (strcmp(verb, "remove") == 0 ||
 	    strcmp(verb, "fail") == 0) {
 		if (*nargs < 2) {
@@ -1614,6 +1827,8 @@ g_raid_md_write_intel(struct g_raid_md_o
 	vi = 0;
 	version = INTEL_VERSION_1000;
 	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
+		if (vol->v_stopping)
+			continue;
 		mvol = intel_get_volume(meta, vi);
 
 		/* New metadata may have different volumes order. */


More information about the svn-src-projects mailing list