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

Alexander Motin mav at FreeBSD.org
Mon Mar 21 14:11:37 UTC 2011


Author: mav
Date: Mon Mar 21 14:11:37 2011
New Revision: 219826
URL: http://svn.freebsd.org/changeset/base/219826

Log:
  - When reading Promise metadata, drop useless records about empty areas
  (extents). Reconstruct them on write, referring largest empty disk area,
  to allow BIOS still see empty areas.
  - Implement global spare metadata writing.
  - Increase space reserved at the end of disk to 131072 sectors, mimicing
  BIOS behaviour. Not sure why it is so, 63 sectors would be enough.

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 13:28:38 2011	(r219825)
+++ projects/graid/head/sys/geom/raid/md_promise.c	Mon Mar 21 14:11:37 2011	(r219826)
@@ -248,6 +248,39 @@ promise_meta_find_disk(struct promise_ra
 }
 
 static int
+promise_meta_unused_range(struct promise_raid_conf **metaarr, int nsd,
+    uint32_t sectors, uint32_t *off, uint32_t *size)
+{
+	uint32_t coff, csize;
+	int i, j;
+
+	sectors -= 131072;
+	*off = 0;
+	*size = 0;
+	coff = 0;
+	csize = sectors;
+	i = 0;
+	while (1) {
+		for (j = 0; j < nsd; j++) {
+			if (metaarr[j]->disk_offset >= coff) {
+				csize = min(csize,
+				    metaarr[j]->disk_offset - coff);
+			}
+		}
+		if (csize > *size) {
+			*off = coff;
+			*size = csize;
+		}
+		if (i >= nsd)
+			break;
+		coff = metaarr[i]->disk_offset + metaarr[i]->disk_sectors;
+		csize = sectors - coff;
+		i++;
+	};
+	return ((*size > 0) ? 1 : 0);
+}
+
+static int
 promise_meta_translate_disk(struct g_raid_volume *vol, int md_disk_pos)
 {
 	int disk_pos, width;
@@ -358,15 +391,35 @@ promise_meta_write(struct g_consumer *cp
 	struct g_provider *pp;
 	struct promise_raid_conf *meta;
 	char *buf;
-	int error, i, subdisk;
-	uint32_t checksum, *ptr;
+	int error, i, subdisk, fake;
+	uint32_t checksum, *ptr, off, size;
 
 	pp = cp->provider;
 	subdisk = 0;
+	fake = 0;
 next:
 	buf = malloc(pp->sectorsize * 4, M_MD_PROMISE, M_WAITOK | M_ZERO);
+	meta = NULL;
 	if (subdisk < nsd) {
 		meta = metaarr[subdisk];
+	} else if (nsd < PROMISE_MAX_SUBDISKS && !fake &&
+	    promise_meta_unused_range(metaarr, nsd,
+	    cp->provider->mediasize / cp->provider->sectorsize,
+	    &off, &size)) {
+		/* Optionally add record for unused space. */
+		meta = (struct promise_raid_conf *)buf;
+		memcpy(&meta->promise_id[0], PROMISE_MAGIC, sizeof(PROMISE_MAGIC));
+		meta->dummy_0 = 0x00020000;
+		meta->integrity = PROMISE_I_VALID;
+		meta->disk.flags = PROMISE_F_ONLINE | PROMISE_F_VALID;
+		meta->disk.number = 0xff;
+		arc4rand(&meta->disk.id, sizeof(meta->disk.id), 0);
+		meta->disk_offset = off;
+		meta->disk_sectors = size;
+		meta->rebuild_lba = UINT32_MAX;
+		fake = 1;
+	}
+	if (meta != NULL) {
 		/* Recalculate checksum for case if metadata were changed. */
 		meta->checksum = 0;
 		for (checksum = 0, ptr = (uint32_t *)meta, i = 0; i < 511; i++)
@@ -412,26 +465,26 @@ promise_meta_erase(struct g_consumer *cp
 	return (error);
 }
 
-#if 0
 static int
-promise_meta_write_spare(struct g_consumer *cp, struct promise_raid_disk *d)
+promise_meta_write_spare(struct g_consumer *cp)
 {
 	struct promise_raid_conf *meta;
 	int error;
 
-	/* Fill anchor and single disk. */
 	meta = malloc(sizeof(*meta), M_MD_PROMISE, M_WAITOK | M_ZERO);
 	memcpy(&meta->promise_id[0], PROMISE_MAGIC, sizeof(PROMISE_MAGIC));
-	memcpy(&meta->version[0], PROMISE_VERSION_1000,
-	    sizeof(PROMISE_VERSION_1000));
-	meta->generation = 1;
-	meta->total_disks = 1;
-	meta->disk[0] = *d;
-	error = promise_meta_write(cp, meta);
+	meta->dummy_0 = 0x00020000;
+	meta->integrity = PROMISE_I_VALID;
+	meta->disk.flags = PROMISE_F_SPARE | PROMISE_F_ONLINE | PROMISE_F_VALID;
+	meta->disk.number = 0xff;
+	arc4rand(&meta->disk.id, sizeof(meta->disk.id), 0);
+	meta->disk_sectors = cp->provider->mediasize / cp->provider->sectorsize;
+	meta->disk_sectors -= 131072;
+	meta->rebuild_lba = UINT32_MAX;
+	error = promise_meta_write(cp, &meta, 1);
 	free(meta, M_MD_PROMISE);
 	return (error);
 }
-#endif
 
 static struct g_raid_volume *
 g_raid_md_promise_get_volume(struct g_raid_softc *sc, uint64_t id)
@@ -1040,7 +1093,7 @@ g_raid_md_taste_promise(struct g_raid_md
 	struct promise_raid_conf *meta, *metaarr[4];
 	struct g_raid_md_promise_perdisk *pd;
 	struct g_geom *geom;
-	int error, i, result, spare, len, subdisks;
+	int error, i, j, result, spare, len, subdisks;
 	char name[16];
 	uint16_t vendor;
 
@@ -1081,6 +1134,20 @@ g_raid_md_taste_promise(struct g_raid_md
 	/* Metadata valid. Print it. */
 	for (i = 0; i < subdisks; i++)
 		g_raid_md_promise_print(metaarr[i]);
+
+	/* Purge meaningless records. */
+	for (i = 0; i < subdisks; ) {
+		if ((metaarr[i]->disk.flags & PROMISE_F_ASSIGNED) ||
+		    (metaarr[i]->disk.flags & PROMISE_F_SPARE)) {
+			i++;
+			continue;
+		}
+		free(metaarr[i], M_MD_PROMISE);
+		for (j = i; j < subdisks - 1; j++)
+			metaarr[i] = metaarr[j + 1];
+		metaarr[PROMISE_MAX_SUBDISKS - 1] = NULL;
+		subdisks--;
+	}
 	spare = 0;//meta->disks[disk_pos].flags & PROMISE_F_SPARE;
 
 search:
@@ -1268,7 +1335,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 		}
 
 		/* Search for disks, connect them and probe. */
-		size = 0x7fffffffffffffffllu;
+		size = INT64_MAX;
 		sectorsize = 0;
 		bzero(disks, sizeof(disks));
 		for (i = 0; i < numdisks; i++) {
@@ -1318,8 +1385,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 			return (error);
 
 		/* Reserve some space for metadata. */
-		size -= size % (63 * sectorsize);
-		size -= 63 * sectorsize;
+		size -= 131072 * sectorsize;
 
 		/* Handle size argument. */
 		len = sizeof(*sizearg);
@@ -1471,7 +1537,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 		}
 
 		/* Collect info about present disks. */
-		size = 0x7fffffffffffffffllu;
+		size = INT64_MAX;
 		sectorsize = 512;
 		for (i = 0; i < numdisks; i++) {
 			disk = vol1->v_subdisks[i].sd_disk;
@@ -1489,7 +1555,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 		}
 
 		/* Reserve some space for metadata. */
-		size -= ((4096 + sectorsize - 1) / sectorsize) * sectorsize;
+		size -= 131072 * sectorsize;
 
 		/* Decide insert before or after. */
 		sd = &vol1->v_subdisks[0];
@@ -1783,7 +1849,7 @@ g_raid_md_ctl_promise(struct g_raid_md_o
 			/* Welcome the "new" disk. */
 			update += g_raid_md_promise_start_disk(disk, 0);
 			if (disk->d_state == G_RAID_DISK_S_SPARE) {
-//				promise_meta_write_spare(cp, &pd->pd_disk_meta);
+				promise_meta_write_spare(cp);
 				g_raid_destroy_disk(disk);
 			} else if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
 				gctl_error(req, "Disk '%s' doesn't fit.",


More information about the svn-src-projects mailing list