From 7f74b7e0865d73a2acccc73cf72fb4f34ab54934 Mon Sep 17 00:00:00 2001 From: le Date: Sat, 19 Nov 2005 20:25:18 +0000 Subject: [PATCH] Finally bring in what was produced during Google SoC 2005: Add functions to rename objects and to move a subdisk from one drive to another. Obtained from: Chris Jones Sponsored by: Google Summer of Code 2005 MFC in: 1 week --- sys/geom/vinum/geom_vinum.c | 6 + sys/geom/vinum/geom_vinum.h | 9 + sys/geom/vinum/geom_vinum_drive.c | 1 - sys/geom/vinum/geom_vinum_move.c | 213 ++++++++++++++++++++ sys/geom/vinum/geom_vinum_rename.c | 284 +++++++++++++++++++++++++++ sys/geom/vinum/geom_vinum_rm.c | 4 +- sys/modules/geom/geom_vinum/Makefile | 3 +- 7 files changed, 515 insertions(+), 5 deletions(-) create mode 100644 sys/geom/vinum/geom_vinum_move.c create mode 100644 sys/geom/vinum/geom_vinum_rename.c diff --git a/sys/geom/vinum/geom_vinum.c b/sys/geom/vinum/geom_vinum.c index 7cddd3a0972..5f115e40869 100644 --- a/sys/geom/vinum/geom_vinum.c +++ b/sys/geom/vinum/geom_vinum.c @@ -502,12 +502,18 @@ gv_config(struct gctl_req *req, struct g_class *mp, char const *verb) } else if (!strcmp(verb, "create")) { gv_create(gp, req); + } else if (!strcmp(verb, "move")) { + gv_move(gp, req); + } else if (!strcmp(verb, "parityop")) { gv_parityop(gp, req); } else if (!strcmp(verb, "remove")) { gv_remove(gp, req); + } else if (!strcmp(verb, "rename")) { + gv_rename(gp, req); + } else if (!strcmp(verb, "start")) { gv_start_obj(gp, req); diff --git a/sys/geom/vinum/geom_vinum.h b/sys/geom/vinum/geom_vinum.h index 15216dc0954..1a31b3bfffe 100644 --- a/sys/geom/vinum/geom_vinum.h +++ b/sys/geom/vinum/geom_vinum.h @@ -33,6 +33,7 @@ /* geom_vinum_drive.c */ void gv_config_new_drive(struct gv_drive *); +void gv_drive_modify(struct gv_drive *); void gv_save_config_all(struct gv_softc *); void gv_save_config(struct g_consumer *, struct gv_drive *, struct gv_softc *); @@ -48,8 +49,16 @@ void gv_ls(struct g_geom *, struct gctl_req *, struct sbuf *); void gv_lv(struct g_geom *, struct gctl_req *, struct sbuf *); void gv_list(struct g_geom *, struct gctl_req *); +/* geom_vinum_move.c */ +void gv_move(struct g_geom *, struct gctl_req *); + +/* geom_vinum_rename.c */ +void gv_rename(struct g_geom *, struct gctl_req *); + /* geom_vinum_rm.c */ void gv_remove(struct g_geom *, struct gctl_req *); +int gv_rm_sd(struct gv_softc *sc, struct gctl_req *req, + struct gv_sd *s, int flags); /* geom_vinum_state.c */ int gv_sdstatemap(struct gv_plex *); diff --git a/sys/geom/vinum/geom_vinum_drive.c b/sys/geom/vinum/geom_vinum_drive.c index 04a53cbb921..9554a7f949d 100644 --- a/sys/geom/vinum/geom_vinum_drive.c +++ b/sys/geom/vinum/geom_vinum_drive.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); static void gv_drive_dead(void *, int); static void gv_drive_worker(void *); -void gv_drive_modify(struct gv_drive *); void gv_config_new_drive(struct gv_drive *d) diff --git a/sys/geom/vinum/geom_vinum_move.c b/sys/geom/vinum/geom_vinum_move.c new file mode 100644 index 00000000000..6d094ba2061 --- /dev/null +++ b/sys/geom/vinum/geom_vinum_move.c @@ -0,0 +1,213 @@ +/*- + * Copyright (c) 2005 Chris Jones + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Chris Jones + * thanks to the support of Google's Summer of Code program and + * mentoring by Lukas Ertl. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include + +static int gv_move_sd(struct gv_softc *, struct gctl_req *, + struct gv_sd *, char *, int); + +void +gv_move(struct g_geom *gp, struct gctl_req *req) +{ + struct gv_softc *sc; + struct gv_sd *s; + char buf[20], *destination, *object; + int *argc, err, *flags, i, type; + + sc = gp->softc; + + argc = gctl_get_paraml(req, "argc", sizeof(*argc)); + flags = gctl_get_paraml(req, "flags", sizeof(*flags)); + destination = gctl_get_param(req, "destination", NULL); + if (destination == NULL) { + gctl_error(req, "no destination given"); + return; + } + if (gv_object_type(sc, destination) != GV_TYPE_DRIVE) { + gctl_error(req, "destination '%s' is not a drive", destination); + return; + } + + /* + * We start with 1 here, because argv[0] on the command line is the + * destination drive. + */ + for (i = 1; i < *argc; i++) { + snprintf(buf, sizeof(buf), "argv%d", i); + object = gctl_get_param(req, buf, NULL); + if (object == NULL) + continue; + + type = gv_object_type(sc, object); + if (type != GV_TYPE_SD) { + gctl_error(req, "you can only move subdisks; " + "'%s' isn't one", object); + return; + } + + s = gv_find_sd(sc, object); + if (s == NULL) { + gctl_error(req, "unknown subdisk '%s'", object); + return; + } + err = gv_move_sd(sc, req, s, destination, *flags); + if (err) + return; + } + + gv_save_config_all(sc); +} + +/* Move a subdisk. */ +static int +gv_move_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *cursd, char *destination, int flags) +{ + struct gv_drive *d; + struct gv_sd *newsd, *s, *s2; + struct gv_plex *p; + struct g_consumer *cp; + char errstr[ERRBUFSIZ]; + int err; + + g_topology_assert(); + KASSERT(cursd != NULL, ("gv_move_sd: NULL cursd")); + + cp = cursd->consumer; + + if (cp->acr || cp->acw || cp->ace) { + gctl_error(req, "subdisk '%s' is busy", cursd->name); + return (-1); + } + + if (!(flags && GV_FLAG_F)) { + gctl_error(req, "-f flag not passed; move would be " + "destructive"); + return (-1); + } + + d = gv_find_drive(sc, destination); + if (d == NULL) { + gctl_error(req, "destination drive '%s' not found", + destination); + return (-1); + } + + if (d == cursd->drive_sc) { + gctl_error(req, "subdisk '%s' already on drive '%s'", + cursd->name, destination); + return (-1); + } + + /* XXX: Does it have to be part of a plex? */ + p = gv_find_plex(sc, cursd->plex); + if (p == NULL) { + gctl_error(req, "subdisk '%s' is not part of a plex", + cursd->name); + return (-1); + } + + /* Stale the old subdisk. */ + err = gv_set_sd_state(cursd, GV_SD_STALE, + GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); + if (err) { + gctl_error(req, "could not set the subdisk '%s' to state " + "'stale'", cursd->name); + return (err); + } + + /* + * Create new subdisk. Ideally, we'd use gv_new_sd, but that requires + * us to create a string for it to parse, which is silly. + * TODO: maybe refactor gv_new_sd such that this is no longer the case. + */ + newsd = g_malloc(sizeof(struct gv_sd), M_WAITOK | M_ZERO); + newsd->plex_offset = cursd->plex_offset; + newsd->size = cursd->size; + newsd->drive_offset = -1; + strncpy(newsd->name, cursd->name, GV_MAXSDNAME); + strncpy(newsd->drive, destination, GV_MAXDRIVENAME); + strncpy(newsd->plex, cursd->plex, GV_MAXPLEXNAME); + newsd->state = GV_SD_STALE; + newsd->vinumconf = cursd->vinumconf; + + err = gv_sd_to_drive(sc, d, newsd, errstr, ERRBUFSIZ); + if (err) { + /* XXX not enough free space? */ + gctl_error(req, errstr); + g_free(newsd); + return (err); + } + + /* Replace the old sd by the new one. */ + g_detach(cp); + LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) { + if (s == cursd) { + p->sdcount--; + p->size -= s->size; + err = gv_rm_sd(sc, req, s, 0); + if (err) + return (err); + + } + } + + gv_sd_to_plex(p, newsd, 1); + + /* Creates the new providers.... */ + gv_drive_modify(d); + + /* And reconnect the consumer ... */ + newsd->consumer = cp; + err = g_attach(cp, newsd->provider); + if (err) { + g_destroy_consumer(cp); + gctl_error(req, "proposed move would create a loop in GEOM " + "config"); + return (err); + } + + LIST_INSERT_HEAD(&sc->subdisks, newsd, sd); + + gv_save_config_all(sc); + + return (0); +} diff --git a/sys/geom/vinum/geom_vinum_rename.c b/sys/geom/vinum/geom_vinum_rename.c new file mode 100644 index 00000000000..666f94d5a23 --- /dev/null +++ b/sys/geom/vinum/geom_vinum_rename.c @@ -0,0 +1,284 @@ +/*- + * Copyright (c) 2005 Chris Jones + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Chris Jones + * thanks to the support of Google's Summer of Code program and + * mentoring by Lukas Ertl. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include + +static int gv_rename_drive(struct gv_softc *, struct gctl_req *, + struct gv_drive *, char *, int); +static int gv_rename_plex(struct gv_softc *, struct gctl_req *, + struct gv_plex *, char *, int); +static int gv_rename_sd(struct gv_softc *, struct gctl_req *, + struct gv_sd *, char *, int); +static int gv_rename_vol(struct gv_softc *, struct gctl_req *, + struct gv_volume *, char *, int); + +void +gv_rename(struct g_geom *gp, struct gctl_req *req) +{ + struct gv_softc *sc; + struct gv_volume *v; + struct gv_plex *p; + struct gv_sd *s; + struct gv_drive *d; + char *newname, *object; + int err, *flags, type; + + sc = gp->softc; + + flags = gctl_get_paraml(req, "flags", sizeof(*flags)); + + newname = gctl_get_param(req, "newname", NULL); + if (newname == NULL) { + gctl_error(req, "no new name given"); + return; + } + + object = gctl_get_param(req, "object", NULL); + if (object == NULL) { + gctl_error(req, "no object given"); + return; + } + + type = gv_object_type(sc, object); + switch (type) { + case GV_TYPE_VOL: + v = gv_find_vol(sc, object); + if (v == NULL) { + gctl_error(req, "unknown volume '%s'", object); + return; + } + err = gv_rename_vol(sc, req, v, newname, *flags); + if (err) + return; + break; + case GV_TYPE_PLEX: + p = gv_find_plex(sc, object); + if (p == NULL) { + gctl_error(req, "unknown plex '%s'", object); + return; + } + err = gv_rename_plex(sc, req, p, newname, *flags); + if (err) + return; + break; + case GV_TYPE_SD: + s = gv_find_sd(sc, object); + if (s == NULL) { + gctl_error(req, "unknown subdisk '%s'", object); + return; + } + err = gv_rename_sd(sc, req, s, newname, *flags); + if (err) + return; + break; + case GV_TYPE_DRIVE: + d = gv_find_drive(sc, object); + if (d == NULL) { + gctl_error(req, "unknown drive '%s'", object); + return; + } + err = gv_rename_drive(sc, req, d, newname, *flags); + if (err) + return; + break; + default: + gctl_error(req, "unknown object '%s'", object); + return; + } + + gv_save_config_all(sc); +} + +static int +gv_rename_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, char *newname, int flags) +{ + struct gv_sd *s; + + g_topology_assert(); + KASSERT(d != NULL, ("gv_rename_drive: NULL d")); + + if (gv_object_type(sc, newname) != -1) { + gctl_error(req, "drive name '%s' already in use", newname); + return (-1); + } + + strncpy(d->name, newname, GV_MAXDRIVENAME); + + /* XXX can we rename providers here? */ + + LIST_FOREACH(s, &d->subdisks, from_drive) + strncpy(s->drive, d->name, GV_MAXDRIVENAME); + + return (0); +} + +static int +gv_rename_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, char *newname, int flags) +{ + struct gv_sd *s; + char plexnumber[GV_MAXPLEXNAME], *pplexnumber; + char oldplexname[GV_MAXPLEXNAME], *poldplexname; + int err; + + pplexnumber = plexnumber; + poldplexname = oldplexname; + + g_topology_assert(); + KASSERT(p != NULL, ("gv_rename_plex: NULL p")); + + if (gv_object_type(sc, newname) != -1) { + gctl_error(req, "plex name '%s' already in use", newname); + return (-1); + } + + strncpy(oldplexname, p->name, GV_MAXPLEXNAME); + strsep(&poldplexname, "."); + strncpy(plexnumber, p->name, GV_MAXPLEXNAME); + strsep(&pplexnumber, "."); + if (strcmp(poldplexname, pplexnumber)) { + gctl_error(req, "current and proposed plex numbers (%s, %s) " + "do not match", pplexnumber, poldplexname); + return (-1); + } + + strncpy(p->name, newname, GV_MAXPLEXNAME); + + /* XXX can we rename providers here? */ + + /* Fix up references and potentially rename subdisks. */ + LIST_FOREACH(s, &p->subdisks, in_plex) { + strncpy(s->plex, p->name, GV_MAXPLEXNAME); + if (flags && GV_FLAG_R) { + char newsdname[GV_MAXSDNAME]; + char oldsdname[GV_MAXSDNAME]; + char *poldsdname = oldsdname; + strncpy(oldsdname, s->name, GV_MAXSDNAME); + strsep(&poldsdname, "."); + strsep(&poldsdname, "."); + snprintf(newsdname, GV_MAXSDNAME, "%s.%s", p->name, + poldsdname); + err = gv_rename_sd(sc, req, s, newsdname, flags); + if (err) + return (err); + } + } + + return (0); +} + +/* + * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored, + * since there are no structures below a subdisk. Similarly, we don't have to + * clean up any references elsewhere to the subdisk's name. + */ +static int +gv_rename_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, char * newname, int flags) +{ + char newsdnumber[GV_MAXSDNAME], *pnewsdnumber; + char oldsdnumber[GV_MAXSDNAME], *poldsdnumber; + + pnewsdnumber = newsdnumber; + poldsdnumber = oldsdnumber; + + g_topology_assert(); + KASSERT(s != NULL, ("gv_rename_sd: NULL s")); + + if (gv_object_type(sc, newname) != -1) { + gctl_error(req, "subdisk name %s already in use", newname); + return (-1); + } + + strncpy(oldsdnumber, s->name, GV_MAXSDNAME); + strsep(&poldsdnumber, "."); + strsep(&poldsdnumber, "."); + strncpy(newsdnumber, newname, GV_MAXSDNAME); + strsep(&pnewsdnumber, "."); + strsep(&pnewsdnumber, "."); + if (strcmp(pnewsdnumber, poldsdnumber)) { + gctl_error(req, "current and proposed sd numbers (%s, %s) do " + "not match", poldsdnumber, pnewsdnumber); + return (-1); + } + + strncpy(s->name, newname, GV_MAXSDNAME); + + /* XXX: can we rename providers here? */ + + return (0); +} + +static int +gv_rename_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, char *newname, int flags) +{ + struct gv_plex *p; + int err; + + g_topology_assert(); + KASSERT(v != NULL, ("gv_rename_vol: NULL v")); + + if (gv_object_type(sc, newname) != -1) { + gctl_error(req, "volume name %s already in use", newname); + return (-1); + } + + /* Rename the volume. */ + strncpy(v->name, newname, GV_MAXVOLNAME); + + /* Fix up references and potentially rename plexes. */ + LIST_FOREACH(p, &v->plexes, in_volume) { + strncpy(p->volume, v->name, GV_MAXVOLNAME); + if (flags && GV_FLAG_R) { + char newplexname[GV_MAXPLEXNAME]; + char oldplexname[GV_MAXPLEXNAME]; + char *poldplexname = oldplexname; + strncpy(oldplexname, p->name, GV_MAXPLEXNAME); + strsep(&poldplexname, "."); + snprintf(newplexname, GV_MAXPLEXNAME, "%s.%s", + v->name, poldplexname); + err = gv_rename_plex(sc, req, p, newplexname, flags); + if (err) + return err; + } + } + + return (0); +} diff --git a/sys/geom/vinum/geom_vinum_rm.c b/sys/geom/vinum/geom_vinum_rm.c index 44b611053d5..eb188b7e6ed 100644 --- a/sys/geom/vinum/geom_vinum_rm.c +++ b/sys/geom/vinum/geom_vinum_rm.c @@ -43,8 +43,6 @@ static int gv_rm_drive(struct gv_softc *, struct gctl_req *, struct gv_drive *, int); static int gv_rm_plex(struct gv_softc *, struct gctl_req *, struct gv_plex *, int); -static int gv_rm_sd(struct gv_softc *, struct gctl_req *, struct gv_sd *, - int); static int gv_rm_vol(struct gv_softc *, struct gctl_req *, struct gv_volume *, int); @@ -240,7 +238,7 @@ gv_rm_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, int fla } /* Remove a subdisk. */ -static int +int gv_rm_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, int flags) { struct g_provider *pp; diff --git a/sys/modules/geom/geom_vinum/Makefile b/sys/modules/geom/geom_vinum/Makefile index 35a1c9b1d41..190ba5503b8 100644 --- a/sys/modules/geom/geom_vinum/Makefile +++ b/sys/modules/geom/geom_vinum/Makefile @@ -6,6 +6,7 @@ KMOD= geom_vinum SRCS= geom_vinum_drive.c geom_vinum.c geom_vinum_plex.c \ geom_vinum_volume.c geom_vinum_subr.c geom_vinum_raid5.c \ geom_vinum_share.c geom_vinum_list.c geom_vinum_rm.c \ - geom_vinum_init.c geom_vinum_state.c + geom_vinum_init.c geom_vinum_state.c geom_vinum_rename.c \ + geom_vinum_move.c .include -- 2.45.2