Date: Mon, 21 Mar 2011 15:51:23 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r219838 - projects/graid/head/sys/geom/raid Message-ID: <201103211551.p2LFpN2F010731@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103211551.p2LFpN2F010731>