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
This commit is contained in:
Lukas Ertl 2005-11-19 20:25:18 +00:00
parent c62f97f558
commit 57335408d4
7 changed files with 515 additions and 5 deletions

View File

@ -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);

View File

@ -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 *);

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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 <bsd.kmod.mk>