summaryrefslogtreecommitdiffstats
path: root/sys/geom/vinum
diff options
context:
space:
mode:
authorle <le@FreeBSD.org>2005-11-19 20:25:18 +0000
committerle <le@FreeBSD.org>2005-11-19 20:25:18 +0000
commit7f74b7e0865d73a2acccc73cf72fb4f34ab54934 (patch)
treefda3443a50d99eceb3a79540e4c41b22a631e9e3 /sys/geom/vinum
parente13ba63af7fc008bda87a1f3797acbb461c87715 (diff)
downloadFreeBSD-src-7f74b7e0865d73a2acccc73cf72fb4f34ab54934.zip
FreeBSD-src-7f74b7e0865d73a2acccc73cf72fb4f34ab54934.tar.gz
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 <chris.jones@ualberta.ca> Sponsored by: Google Summer of Code 2005 MFC in: 1 week
Diffstat (limited to 'sys/geom/vinum')
-rw-r--r--sys/geom/vinum/geom_vinum.c6
-rw-r--r--sys/geom/vinum/geom_vinum.h9
-rw-r--r--sys/geom/vinum/geom_vinum_drive.c1
-rw-r--r--sys/geom/vinum/geom_vinum_move.c213
-rw-r--r--sys/geom/vinum/geom_vinum_rename.c284
-rw-r--r--sys/geom/vinum/geom_vinum_rm.c4
6 files changed, 513 insertions, 4 deletions
diff --git a/sys/geom/vinum/geom_vinum.c b/sys/geom/vinum/geom_vinum.c
index 7cddd3a..5f115e4 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 15216dc..1a31b3b 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 04a53cb..9554a7f 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 0000000..6d094ba
--- /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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <geom/geom.h>
+#include <geom/vinum/geom_vinum_var.h>
+#include <geom/vinum/geom_vinum.h>
+#include <geom/vinum/geom_vinum_share.h>
+
+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 0000000..666f94d
--- /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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <geom/geom.h>
+#include <geom/vinum/geom_vinum_var.h>
+#include <geom/vinum/geom_vinum.h>
+#include <geom/vinum/geom_vinum_share.h>
+
+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 44b6110..eb188b7 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;
OpenPOWER on IntegriCloud