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

Alexander Motin mav at FreeBSD.org
Fri Jan 28 13:48:23 UTC 2011


Author: mav
Date: Fri Jan 28 13:48:22 2011
New Revision: 218016
URL: http://svn.freebsd.org/changeset/base/218016

Log:
  Add `graid label` ability to create arrays missing some disks by specifying
  NONE instead of their names. It can be used, for example, to migrate from
  non-RAID setup to RAID1 or if further redundant disks are not available at
  the moment.
  
  Add some checks to validate subdisk sizes. Creating too small subdisk could
  cause crash, while for too large it may be impossible to write metadata.

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

Modified: projects/graid/head/sys/geom/raid/md_intel.c
==============================================================================
--- projects/graid/head/sys/geom/raid/md_intel.c	Fri Jan 28 11:56:14 2011	(r218015)
+++ projects/graid/head/sys/geom/raid/md_intel.c	Fri Jan 28 13:48:22 2011	(r218016)
@@ -1229,6 +1229,11 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 				error = -6;
 				break;
 			}
+			if (strcmp(diskname, "NONE") == 0) {
+				cp = NULL;
+				pp = NULL;
+				goto makedisk;
+			}
 			if (strncmp(diskname, "/dev/", 5) == 0)
 				diskname += 5;
 			g_topology_lock();
@@ -1258,12 +1263,19 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 				error = -7;
 				break;
 			}
-
+makedisk:
 			pd = malloc(sizeof(*pd), M_MD_INTEL, M_WAITOK | M_ZERO);
 			pd->pd_disk_pos = i;
 			disk = g_raid_create_disk(sc);
 			disk->d_md_data = (void *)pd;
 			disk->d_consumer = cp;
+			if (cp == NULL) {
+				strcpy(&pd->pd_disk_meta.serial[0], "NONE");
+				pd->pd_disk_meta.id = 0;
+				pd->pd_disk_meta.id = 0xffffffff;
+				pd->pd_disk_meta.flags = INTEL_F_ASSIGNED;
+				continue;
+			}
 			cp->private = disk;
 
 			g_topology_unlock();
@@ -1331,7 +1343,20 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 			}
 			strip = *striparg;
 		}
-		size -= (size % strip);
+
+		/* 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, ... */
 		mdi->mdio_started = 1;
@@ -1343,9 +1368,11 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 		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
+		else /* RAID10 */
 			vol->v_mediasize = size * (numdisks / 2);
 		vol->v_sectorsize = sectorsize;
 		g_raid_start_volume(vol);
@@ -1358,14 +1385,23 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 			sd->sd_offset = 0;
 			sd->sd_size = size;
 			TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
-			g_raid_change_disk_state(disk, 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);
+			if (sd->sd_disk->d_consumer != NULL) {
+				g_raid_change_disk_state(disk,
+				    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);
+			} else {
+				g_raid_change_disk_state(disk, G_RAID_DISK_S_OFFLINE);
+			}
 		}
 
 		/* Write metadata based on created entities. */
 		g_raid_md_write_intel(md, NULL, NULL, NULL);
+
+		/* Pickup any STALE/SPARE disks to refill array if needed. */
+		g_raid_md_intel_refill(sc);
 		return (0);
 	}
 	if (strcmp(verb, "add") == 0) {
@@ -1476,14 +1512,24 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 			}
 			strip = *striparg;
 		}
+
+		/* Round offset up to strip. */
 		size -= ((strip - off) % strip);
 		off += ((strip - off) % strip);
-		size -= (size % strip);
 
+		/* 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, "No free space.");
+			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);
@@ -1494,9 +1540,11 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
 		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
+		else /* RAID10 */
 			vol->v_mediasize = size * (numdisks / 2);
 		vol->v_sectorsize = sectorsize;
 		g_raid_start_volume(vol);


More information about the svn-src-projects mailing list