Author: mav
Date: Wed Oct 26 21:50:10 2011
New Revision: 226816
URL: http://svn.freebsd.org/changeset/base/226816

Log:
  Clarify disks/volumes above 2TiB support in geom_raid:
   - add support for volumes above 2TiB with Promise metadata format;
   - enforse and document other limitations:
     - Intel and Promise metadata formats do not support disks above 2TiB;
     - NVIDIA metadata format does not support volumes above 2TiB.
  
  Sponsored by: iXsystems, Inc.
  MFC after:    2 weeks

Modified:
  head/sbin/geom/class/raid/graid.8
  head/sys/geom/raid/md_intel.c
  head/sys/geom/raid/md_nvidia.c
  head/sys/geom/raid/md_promise.c

Modified: head/sbin/geom/class/raid/graid.8
==============================================================================
--- head/sbin/geom/class/raid/graid.8   Wed Oct 26 21:11:40 2011        
(r226815)
+++ head/sbin/geom/class/raid/graid.8   Wed Oct 26 21:50:10 2011        
(r226816)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 22, 2011
+.Dd October 26, 2011
 .Dt GRAID 8
 .Os
 .Sh NAME
@@ -250,6 +250,9 @@ If you started migration using BIOS or i
 complete it there.
 Do not run GEOM RAID class on migrating volumes under pain of possible data
 corruption!
+.Sh 2TiB BARRIERS
+Intel and Promise metadata formats do not support disks above 2TiB.
+NVIDIA metadata format does not support volumes above 2TiB.
 .Sh EXIT STATUS
 Exit status is 0 on success, and non-zero if the command fails.
 .Sh SEE ALSO

Modified: head/sys/geom/raid/md_intel.c
==============================================================================
--- head/sys/geom/raid/md_intel.c       Wed Oct 26 21:11:40 2011        
(r226815)
+++ head/sys/geom/raid/md_intel.c       Wed Oct 26 21:50:10 2011        
(r226816)
@@ -1172,15 +1172,18 @@ g_raid_md_taste_intel(struct g_raid_md_o
        g_access(cp, -1, 0, 0);
        if (meta == NULL) {
                if (g_raid_aggressive_spare) {
-                       if (vendor == 0x8086) {
+                       if (vendor != 0x8086) {
+                               G_RAID_DEBUG(1,
+                                   "Intel vendor mismatch 0x%04x != 0x8086",
+                                   vendor);
+                       } else if (pp->mediasize / pp->sectorsize > UINT32_MAX) 
{
+                               G_RAID_DEBUG(1,
+                                   "Intel disk '%s' is too big.", pp->name);
+                       } else {
                                G_RAID_DEBUG(1,
                                    "No Intel metadata, forcing spare.");
                                spare = 2;
                                goto search;
-                       } else {
-                               G_RAID_DEBUG(1,
-                                   "Intel vendor mismatch 0x%04x != 0x8086",
-                                   vendor);
                        }
                }
                return (G_RAID_MD_TASTE_FAIL);
@@ -1194,9 +1197,9 @@ g_raid_md_taste_intel(struct g_raid_md_o
        }
        if (meta->disk[disk_pos].sectors !=
            (pp->mediasize / pp->sectorsize)) {
-               G_RAID_DEBUG(1, "Intel size mismatch %u != %u",
-                   meta->disk[disk_pos].sectors,
-                   (u_int)(pp->mediasize / pp->sectorsize));
+               G_RAID_DEBUG(1, "Intel size mismatch %ju != %ju",
+                   (off_t)meta->disk[disk_pos].sectors,
+                   (off_t)(pp->mediasize / pp->sectorsize));
                goto fail1;
        }
 
@@ -1449,6 +1452,13 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
                        cp->private = disk;
                        g_topology_unlock();
 
+                       if (pp->mediasize / pp->sectorsize > UINT32_MAX) {
+                               gctl_error(req,
+                                   "Disk '%s' is too big.", diskname);
+                               error = -8;
+                               break;
+                       }
+
                        error = g_raid_md_get_label(cp,
                            &pd->pd_disk_meta.serial[0], INTEL_SERIAL_LEN);
                        if (error != 0) {
@@ -1940,6 +1950,14 @@ g_raid_md_ctl_intel(struct g_raid_md_obj
                        pp = cp->provider;
                        g_topology_unlock();
 
+                       if (pp->mediasize / pp->sectorsize > UINT32_MAX) {
+                               gctl_error(req,
+                                   "Disk '%s' is too big.", diskname);
+                               g_raid_kill_consumer(sc, cp);
+                               error = -8;
+                               break;
+                       }
+
                        /* Read disk serial. */
                        error = g_raid_md_get_label(cp,
                            &serial[0], INTEL_SERIAL_LEN);

Modified: head/sys/geom/raid/md_nvidia.c
==============================================================================
--- head/sys/geom/raid/md_nvidia.c      Wed Oct 26 21:11:40 2011        
(r226815)
+++ head/sys/geom/raid/md_nvidia.c      Wed Oct 26 21:50:10 2011        
(r226816)
@@ -1033,7 +1033,7 @@ g_raid_md_ctl_nvidia(struct g_raid_md_ob
        char arg[16];
        const char *verb, *volname, *levelname, *diskname;
        int *nargs, *force;
-       off_t size, sectorsize, strip;
+       off_t size, sectorsize, strip, volsize;
        intmax_t *sizearg, *striparg;
        int numdisks, i, len, level, qual, update;
        int error;
@@ -1182,7 +1182,20 @@ g_raid_md_ctl_nvidia(struct g_raid_md_ob
                        gctl_error(req, "Size too small.");
                        return (-13);
                }
-               if (size > 0xffffffffffffllu * sectorsize) {
+
+               if (level == G_RAID_VOLUME_RL_RAID0 ||
+                   level == G_RAID_VOLUME_RL_CONCAT ||
+                   level == G_RAID_VOLUME_RL_SINGLE)
+                       volsize = size * numdisks;
+               else if (level == G_RAID_VOLUME_RL_RAID1)
+                       volsize = size;
+               else if (level == G_RAID_VOLUME_RL_RAID5)
+                       volsize = size * (numdisks - 1);
+               else { /* RAID1E */
+                       volsize = ((size * numdisks) / strip / 2) *
+                           strip;
+               }
+               if (volsize > 0xffffffffllu * sectorsize) {
                        gctl_error(req, "Size too big.");
                        return (-14);
                }
@@ -1196,18 +1209,7 @@ g_raid_md_ctl_nvidia(struct g_raid_md_ob
                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 ||
-                   level == G_RAID_VOLUME_RL_CONCAT ||
-                   level == G_RAID_VOLUME_RL_SINGLE)
-                       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_mediasize = volsize;
                vol->v_sectorsize = sectorsize;
                g_raid_start_volume(vol);
 

Modified: head/sys/geom/raid/md_promise.c
==============================================================================
--- head/sys/geom/raid/md_promise.c     Wed Oct 26 21:11:40 2011        
(r226815)
+++ head/sys/geom/raid/md_promise.c     Wed Oct 26 21:50:10 2011        
(r226816)
@@ -121,7 +121,8 @@ struct promise_raid_conf {
        uint64_t        rebuild_lba64;  /* Per-volume rebuild position. */
        uint32_t        magic_4;
        uint32_t        magic_5;
-       uint32_t        filler3[325];
+       uint32_t        total_sectors_high;
+       uint32_t        filler3[324];
        uint32_t        checksum;
 } __packed;
 
@@ -213,6 +214,7 @@ g_raid_md_promise_print(struct promise_r
        printf("rebuild_lba64       %ju\n", meta->rebuild_lba64);
        printf("magic_4             0x%08x\n", meta->magic_4);
        printf("magic_5             0x%08x\n", meta->magic_5);
+       printf("total_sectors_high  0x%08x\n", meta->total_sectors_high);
        printf("=================================================\n");
 }
 
@@ -867,6 +869,9 @@ g_raid_md_promise_start(struct g_raid_vo
        vol->v_strip_size = 512 << meta->stripe_shift; //ZZZ
        vol->v_disks_count = meta->total_disks;
        vol->v_mediasize = (off_t)meta->total_sectors * 512; //ZZZ
+       if (meta->total_sectors_high < 256) /* If value looks sane. */
+               vol->v_mediasize |=
+                   ((off_t)meta->total_sectors_high << 32) * 512; //ZZZ
        vol->v_sectorsize = 512; //ZZZ
        for (i = 0; i < vol->v_disks_count; i++) {
                sd = &vol->v_subdisks[i];
@@ -1318,6 +1323,13 @@ g_raid_md_ctl_promise(struct g_raid_md_o
                        cp->private = disk;
                        g_topology_unlock();
 
+                       if (pp->mediasize / pp->sectorsize > UINT32_MAX) {
+                               gctl_error(req,
+                                   "Disk '%s' is too big.", diskname);
+                               error = -8;
+                               break;
+                       }
+
                        /* Read kernel dumping information. */
                        disk->d_kd.offset = 0;
                        disk->d_kd.length = OFF_MAX;
@@ -1609,8 +1621,17 @@ g_raid_md_ctl_promise(struct g_raid_md_o
                                error = -4;
                                break;
                        }
+                       pp = cp->provider;
                        g_topology_unlock();
 
+                       if (pp->mediasize / pp->sectorsize > UINT32_MAX) {
+                               gctl_error(req,
+                                   "Disk '%s' is too big.", diskname);
+                               g_raid_kill_consumer(sc, cp);
+                               error = -8;
+                               break;
+                       }
+
                        pd = malloc(sizeof(*pd), M_MD_PROMISE, M_WAITOK | 
M_ZERO);
 
                        disk = g_raid_create_disk(sc);
@@ -1716,6 +1737,8 @@ g_raid_md_write_promise(struct g_raid_md
                        meta->array_width /= 2;
                meta->array_number = vol->v_global_id;
                meta->total_sectors = vol->v_mediasize / vol->v_sectorsize;
+               meta->total_sectors_high =
+                   (vol->v_mediasize / vol->v_sectorsize) >> 32;
                meta->cylinders = meta->total_sectors / (255 * 63) - 1;
                meta->heads = 254;
                meta->sectors = 63;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to