Date: Wed, 26 Jan 2011 19:24:41 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r217892 - in projects/graid/head: sbin/geom/class/raid sys/geom/raid Message-ID: <201101261924.p0QJOfgF086849@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Wed Jan 26 19:24:41 2011 New Revision: 217892 URL: http://svn.freebsd.org/changeset/base/217892 Log: Implement two more `graid` subcommands: add - add second volume into existing array; delete - delete specified volume or whole array. Modified: projects/graid/head/sbin/geom/class/raid/geom_raid.c projects/graid/head/sys/geom/raid/g_raid_ctl.c projects/graid/head/sys/geom/raid/md_intel.c Modified: projects/graid/head/sbin/geom/class/raid/geom_raid.c ============================================================================== --- projects/graid/head/sbin/geom/class/raid/geom_raid.c Wed Jan 26 19:01:05 2011 (r217891) +++ projects/graid/head/sbin/geom/class/raid/geom_raid.c Wed Jan 26 19:24:41 2011 (r217892) @@ -57,23 +57,34 @@ struct g_command class_commands[] = { { 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER }, G_OPT_SENTINEL }, - "[-S size] [-s stripsize] format name level prov ..." + "[-S size] [-s stripsize] format label level prov ..." + }, + { "add", G_FLAG_VERBOSE, NULL, + { + { 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER }, + { 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER }, + G_OPT_SENTINEL + }, + "[-S size] [-s stripsize] name label level" + }, + { "delete", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, + "[-v] name [label|num]" }, { "insert", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" + "[-v] name prov ..." }, { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" + "[-v] name prov ..." }, { "fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" + "[-v] name prov ..." }, { "stop", G_FLAG_VERBOSE, NULL, { { 'f', "force", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - "[-fv] name ..." + "[-fv] name" }, G_CMD_SENTINEL }; Modified: projects/graid/head/sys/geom/raid/g_raid_ctl.c ============================================================================== --- projects/graid/head/sys/geom/raid/g_raid_ctl.c Wed Jan 26 19:01:05 2011 (r217891) +++ projects/graid/head/sys/geom/raid/g_raid_ctl.c Wed Jan 26 19:24:41 2011 (r217892) @@ -119,7 +119,7 @@ g_raid_ctl_stop(struct gctl_req *req, st gctl_error(req, "No '%s' argument.", "nargs"); return; } - if (*nargs < 1) { + if (*nargs != 1) { gctl_error(req, "Invalid number of arguments."); return; } Modified: projects/graid/head/sys/geom/raid/md_intel.c ============================================================================== --- projects/graid/head/sys/geom/raid/md_intel.c Wed Jan 26 19:01:05 2011 (r217891) +++ projects/graid/head/sys/geom/raid/md_intel.c Wed Jan 26 19:24:41 2011 (r217892) @@ -542,7 +542,7 @@ g_raid_md_intel_start_disk(struct g_raid /* Make sure this disk is big enough. */ TAILQ_FOREACH(sd, &olddisk->d_subdisks, sd_next) { if (sd->sd_offset + sd->sd_size + 4096 > - (uint64_t)pd->pd_disk_meta.sectors * 512) { + (off_t)pd->pd_disk_meta.sectors * 512) { G_RAID_DEBUG(1, "Disk too small (%llu < %llu)", ((unsigned long long) @@ -1168,7 +1168,7 @@ g_raid_md_ctl_intel(struct g_raid_md_obj struct gctl_req *req) { struct g_raid_softc *sc; - struct g_raid_volume *vol; + struct g_raid_volume *vol, *vol1; struct g_raid_subdisk *sd; struct g_raid_disk *disk; struct g_raid_md_intel_object *mdi; @@ -1177,8 +1177,9 @@ g_raid_md_ctl_intel(struct g_raid_md_obj struct g_provider *pp; char arg[16], serial[INTEL_SERIAL_LEN]; const char *verb, *volname, *levelname, *diskname; + char *tmp; int *nargs; - uint64_t size, sectorsize, strip; + off_t off, size, sectorsize, strip; intmax_t *sizearg, *striparg; int numdisks, i, len, level, qual, update; int error; @@ -1218,7 +1219,7 @@ g_raid_md_ctl_intel(struct g_raid_md_obj /* Search for disks, connect them and probe. */ numdisks = *nargs - 3; - size = 0xffffffffffffffffllu; + size = 0x7fffffffffffffffllu; sectorsize = 0; for (i = 0; i < numdisks; i++) { snprintf(arg, sizeof(arg), "arg%d", i + 3); @@ -1304,7 +1305,8 @@ g_raid_md_ctl_intel(struct g_raid_md_obj sizearg = gctl_get_param(req, "size", &len); if (sizearg != NULL && len == sizeof(*sizearg)) { if (*sizearg > size) { - gctl_error(req, "Size too big."); + gctl_error(req, "Size too big %lld > %lld.", + (long long)*sizearg, (long long)size); return (-9); } size = *sizearg; @@ -1366,6 +1368,217 @@ g_raid_md_ctl_intel(struct g_raid_md_obj g_raid_md_write_intel(md, NULL, NULL, NULL); return (0); } + 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); + } + if (level != G_RAID_VOLUME_RL_RAID0 && + level != G_RAID_VOLUME_RL_RAID1 && + level != G_RAID_VOLUME_RL_RAID5 && + level != G_RAID_VOLUME_RL_RAID10) { + gctl_error(req, "Unsupported RAID level."); + return (-5); + } + + /* 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); + } + + /* Collect info about present disks. */ + size = 0x7fffffffffffffffllu; + sectorsize = 512; + numdisks = vol1->v_disks_count; + for (i = 0; i < numdisks; i++) { + disk = vol1->v_subdisks[i].sd_disk; + pd = (struct g_raid_md_intel_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 -= ((4096 + sectorsize - 1) / sectorsize) * 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 size argument. */ + len = sizeof(*sizearg); + sizearg = gctl_get_param(req, "size", &len); + if (sizearg != NULL && len == sizeof(*sizearg)) { + if (*sizearg > size) { + gctl_error(req, "Size too big %lld > %lld.", + (long long)*sizearg, (long long)size); + return (-9); + } + size = *sizearg; + } + + /* Handle strip argument. */ + strip = 131072; + len = sizeof(*striparg); + striparg = gctl_get_param(req, "strip", &len); + if (striparg != NULL && len == sizeof(*striparg)) { + 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; + } + size -= ((strip - off) % strip); + off += ((strip - off) % strip); + size -= (size % strip); + + if (size <= 0) { + gctl_error(req, "No free space."); + return (-13); + } + + /* 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_RAID5) + vol->v_mediasize = size * (numdisks - 1); + else + vol->v_mediasize = size * (numdisks / 2); + 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_intel(md, NULL, NULL, NULL); + return (0); + } + if (strcmp(verb, "delete") == 0) { + + /* Full node destruction. */ + if (*nargs == 1) { + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_consumer) + intel_meta_erase(disk->d_consumer); + } + g_raid_destroy_node(sc, 0); + return (0); + } + + /* Destroy specified volume. If it was last - all node. */ + if (*nargs != 2) { + 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); + } + + /* Search for volume. */ + TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { + if (strcmp(vol->v_name, volname) == 0) + break; + } + if (vol == NULL) { + i = strtol(volname, &tmp, 10); + if (verb != volname && tmp[0] == 0) { + TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { + if ((intptr_t)vol->v_md_data == i) + break; + } + } + } + if (vol == NULL) { + gctl_error(req, "Volume '%s' not found.", volname); + return (-3); + } + + /* Destroy volume and potentially node. */ + i = 0; + TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next) + i++; + if (i >= 2) { + g_raid_destroy_volume(vol); + g_raid_md_write_intel(md, NULL, NULL, NULL); + } else { + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_consumer) + intel_meta_erase(disk->d_consumer); + } + g_raid_destroy_node(sc, 0); + } + return (0); + } if (strcmp(verb, "remove") == 0 || strcmp(verb, "fail") == 0) { if (*nargs < 2) { @@ -1614,6 +1827,8 @@ g_raid_md_write_intel(struct g_raid_md_o vi = 0; version = INTEL_VERSION_1000; TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { + if (vol->v_stopping) + continue; mvol = intel_get_volume(meta, vi); /* New metadata may have different volumes order. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101261924.p0QJOfgF086849>