svn commit: r219838 - projects/graid/head/sys/geom/raid

Alexander Motin mav at FreeBSD.org
Mon Mar 21 15:51:23 UTC 2011


Author: mav
Date: Mon Mar 21 15:51:22 2011
New Revision: 219838
URL: http://svn.freebsd.org/changeset/base/219838

Log:
  Improve Promise's `graid label` implementation to support multiple volumes
  (extents) per disk. This allows to it create all configurations supported
  by BIOS and even more then can be created by Windows driver.

Modified:
  projects/graid/head/sys/geom/raid/md_promise.c

Modified: projects/graid/head/sys/geom/raid/md_promise.c
==============================================================================
--- projects/graid/head/sys/geom/raid/md_promise.c	Mon Mar 21 15:29:20 2011	(r219837)
+++ projects/graid/head/sys/geom/raid/md_promise.c	Mon Mar 21 15:51:22 2011	(r219838)
@@ -263,7 +263,7 @@ promise_meta_unused_range(struct promise
 	while (1) {
 		for (j = 0; j < nsd; j++) {
 			if (metaarr[j]->disk_offset >= coff) {
-				csize = min(csize,
+				csize = MIN(csize,
 				    metaarr[j]->disk_offset - coff);
 			}
 		}
@@ -1294,8 +1294,9 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 	const char *verb, *volname, *levelname, *diskname;
 	char *tmp;
 	int *nargs, *force;
-	off_t off, size, sectorsize, strip;
+	off_t size, sectorsize, strip;
 	intmax_t *sizearg, *striparg;
+	uint32_t offs[PROMISE_MAX_DISKS], esize;
 	int numdisks, i, len, level, qual, update;
 	int error;
 
@@ -1338,6 +1339,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 		size = INT64_MAX;
 		sectorsize = 0;
 		bzero(disks, sizeof(disks));
+		bzero(offs, sizeof(offs));
 		for (i = 0; i < numdisks; i++) {
 			snprintf(arg, sizeof(arg), "arg%d", i + 3);
 			diskname = gctl_get_asciiparam(req, arg);
@@ -1348,13 +1350,48 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 			}
 			if (strcmp(diskname, "NONE") == 0)
 				continue;
+
+			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
+				if (disk->d_consumer != NULL && 
+				    disk->d_consumer->provider != NULL &&
+				    strcmp(disk->d_consumer->provider->name,
+				     diskname) == 0)
+					break;
+			}
+			if (disk != NULL) {
+				if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
+					gctl_error(req, "Disk '%s' is in a "
+					    "wrong state (%s).", diskname,
+					    g_raid_disk_state2str(disk->d_state));
+					error = -7;
+					break;
+				}
+				pd = disk->d_md_data;
+				if (pd->pd_subdisks >= PROMISE_MAX_SUBDISKS) {
+					gctl_error(req, "Disk '%s' already "
+					    "used by %d volumes.",
+					    diskname, pd->pd_subdisks);
+					error = -7;
+					break;
+				}
+				pp = disk->d_consumer->provider;
+				disks[i] = disk;
+				promise_meta_unused_range(pd->pd_meta,
+				    pd->pd_subdisks,
+				    pp->mediasize / pp->sectorsize,
+				    &offs[i], &esize);
+				size = MIN(size, (off_t)esize * pp->sectorsize);
+				sectorsize = MAX(sectorsize, pp->sectorsize);
+				continue;
+			}
+
 			g_topology_lock();
 			cp = g_raid_open_consumer(sc, diskname);
 			if (cp == NULL) {
 				gctl_error(req, "Can't open disk '%s'.",
 				    diskname);
 				g_topology_unlock();
-				error = -4;
+				error = -8;
 				break;
 			}
 			pp = cp->provider;
@@ -1376,16 +1413,18 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 				    "Dumping not supported by %s.",
 				    cp->provider->name);
 
-			if (size > pp->mediasize)
-				size = pp->mediasize;
-			if (sectorsize < pp->sectorsize)
-				sectorsize = pp->sectorsize;
+			/* Reserve some space for metadata. */
+			size = MIN(size, pp->mediasize - 131072llu * pp->sectorsize);
+			sectorsize = MAX(sectorsize, pp->sectorsize);
 		}
-		if (error != 0)
+		if (error != 0) {
+			for (i = 0; i < numdisks; i++) {
+				if (disks[i] != NULL &&
+				    disks[i]->d_state == G_RAID_DISK_S_NONE)
+					g_raid_destroy_disk(disks[i]);
+			}
 			return (error);
-
-		/* Reserve some space for metadata. */
-		size -= 131072 * sectorsize;
+		}
 
 		/* Handle size argument. */
 		len = sizeof(*sizearg);
@@ -1418,7 +1457,9 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 		}
 
 		/* Round size down to strip or sector. */
-		if (level == G_RAID_VOLUME_RL_RAID1)
+		if (level == G_RAID_VOLUME_RL_RAID1 ||
+		    level == G_RAID_VOLUME_RL_SINGLE ||
+		    level == G_RAID_VOLUME_RL_CONCAT)
 			size -= (size % sectorsize);
 		else if (level == G_RAID_VOLUME_RL_RAID1E &&
 		    (numdisks & 1) != 0)
@@ -1467,7 +1508,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 			pd = (struct g_raid_md_promise_perdisk *)disk->d_md_data;
 			sd = &vol->v_subdisks[i];
 			sd->sd_disk = disk;
-			sd->sd_offset = 0;
+			sd->sd_offset = (off_t)offs[i] * 512;
 			sd->sd_size = size;
 			TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
 			g_raid_change_disk_state(disk,
@@ -1491,179 +1532,9 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 	}
 	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);
-		}
-
-		/* 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);
-		}
-
-		numdisks = vol1->v_disks_count;
-		force = gctl_get_paraml(req, "force", sizeof(*force));
-		if (!g_raid_md_promise_supported(level, qual, numdisks,
-		    force ? *force : 0)) {
-			gctl_error(req, "Unsupported RAID level "
-			    "(0x%02x/0x%02x), or number of disks (%d).",
-			    level, qual, numdisks);
-			return (-5);
-		}
-
-		/* Collect info about present disks. */
-		size = INT64_MAX;
-		sectorsize = 512;
-		for (i = 0; i < numdisks; i++) {
-			disk = vol1->v_subdisks[i].sd_disk;
-			pd = (struct g_raid_md_promise_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 -= 131072 * 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 strip argument. */
-		strip = 131072;
-		len = sizeof(*striparg);
-		striparg = gctl_get_param(req, "strip", &len);
-		if (striparg != NULL && len == sizeof(*striparg) &&
-		    *striparg > 0) {
-			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;
-		}
-
-		/* Round offset up to strip. */
-		if (off % strip != 0) {
-			size -= strip - off % strip;
-			off += strip - off % strip;
-		}
-
-		/* Handle size argument. */
-		len = sizeof(*sizearg);
-		sizearg = gctl_get_param(req, "size", &len);
-		if (sizearg != NULL && len == sizeof(*sizearg) &&
-		    *sizearg > 0) {
-			if (*sizearg > size) {
-				gctl_error(req, "Size too big %lld > %lld.",
-				    (long long)*sizearg, (long long)size);
-				return (-9);
-			}
-			size = *sizearg;
-		}
-
-		/* Round size down to strip or sector. */
-		if (level == G_RAID_VOLUME_RL_RAID1)
-			size -= (size % sectorsize);
-		else
-			size -= (size % strip);
-		if (size <= 0) {
-			gctl_error(req, "Size too small.");
-			return (-13);
-		}
-		if (size > 0xffffffffllu * sectorsize) {
-			gctl_error(req, "Size too big.");
-			return (-14);
-		}
-
-		/* 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_RAID1)
-			vol->v_mediasize = size;
-		else if (level == G_RAID_VOLUME_RL_RAID5)
-			vol->v_mediasize = size * (numdisks - 1);
-		else { /* RAID1E */
-			vol->v_mediasize = ((size * numdisks) / strip / 2) *
-			    strip;
-		}
-		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_promise(md, vol, NULL, NULL);
-
-		g_raid_event_send(vol, G_RAID_VOLUME_E_START,
-		    G_RAID_EVENT_VOLUME);
-		return (0);
+		gctl_error(req, "`add` command is not applicable, "
+		    "use `label` instead.");
+		return (-99);
 	}
 	if (strcmp(verb, "delete") == 0) {
 
@@ -1969,7 +1840,7 @@ g_raid_md_write_promise(struct g_raid_md
 				meta->disks[pos].flags |=
 				    PROMISE_F_ONLINE | PROMISE_F_REDIR;
 				if (sd->sd_state == G_RAID_SUBDISK_S_REBUILD) {
-					rebuild_lba64 = min(rebuild_lba64,
+					rebuild_lba64 = MIN(rebuild_lba64,
 					    sd->sd_rebuild_pos / 512);
 				} else
 					rebuild_lba64 = 0;
@@ -1979,7 +1850,7 @@ g_raid_md_write_promise(struct g_raid_md
 				if (sd->sd_state < G_RAID_SUBDISK_S_ACTIVE) {
 					meta->status |= PROMISE_S_MARKED;
 					if (sd->sd_state == G_RAID_SUBDISK_S_RESYNC) {
-						rebuild_lba64 = min(rebuild_lba64,
+						rebuild_lba64 = MIN(rebuild_lba64,
 						    sd->sd_rebuild_pos / 512);
 					} else
 						rebuild_lba64 = 0;


More information about the svn-src-projects mailing list