Date: Fri, 28 Jan 2011 13:48:22 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r218016 - projects/graid/head/sys/geom/raid Message-ID: <201101281348.p0SDmMhw081302@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101281348.p0SDmMhw081302>