diff options
author | ae <ae@FreeBSD.org> | 2014-01-10 07:43:40 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2014-01-10 07:43:40 +0000 |
commit | 5308ec580218db5152159128ab830fcdf297c82d (patch) | |
tree | 247e12a038d718dd5d8bd2a75820882191ba856c /sbin | |
parent | a956d3e4f75ef8d4c0bd9c1d597c34ec1c97edef (diff) | |
download | FreeBSD-src-5308ec580218db5152159128ab830fcdf297c82d.zip FreeBSD-src-5308ec580218db5152159128ab830fcdf297c82d.tar.gz |
MFC r258357:
Add "resize" verb to gmirror(8) and such functionality to geom_mirror(4).
Now it is easy to expand the size of the mirror when all its components
are replaced. Also add g_resize method to geom_mirror class. It will write
updated metadata to new last sector, when parent provider is resized.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/geom/class/mirror/geom_mirror.c | 102 | ||||
-rw-r--r-- | sbin/geom/class/mirror/gmirror.8 | 17 |
2 files changed, 118 insertions, 1 deletions
diff --git a/sbin/geom/class/mirror/geom_mirror.c b/sbin/geom/class/mirror/geom_mirror.c index 9f0acc6..17cfccb 100644 --- a/sbin/geom/class/mirror/geom_mirror.c +++ b/sbin/geom/class/mirror/geom_mirror.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <err.h> #include <errno.h> #include <paths.h> #include <stdio.h> @@ -53,6 +54,7 @@ static void mirror_activate(struct gctl_req *req); static void mirror_clear(struct gctl_req *req); static void mirror_dump(struct gctl_req *req); static void mirror_label(struct gctl_req *req); +static void mirror_resize(struct gctl_req *req, unsigned flags); struct g_command class_commands[] = { { "activate", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, @@ -112,6 +114,13 @@ struct g_command class_commands[] = { { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, "[-v] name prov ..." }, + { "resize", G_FLAG_VERBOSE, mirror_resize, + { + { 's', "size", "*", G_TYPE_STRING }, + G_OPT_SENTINEL + }, + "[-s size] [-v] name" + }, { "stop", G_FLAG_VERBOSE, NULL, { { 'f', "force", NULL, G_TYPE_BOOL }, @@ -376,3 +385,96 @@ mirror_activate(struct gctl_req *req) printf("Provider %s activated.\n", path); } } + +static struct gclass * +find_class(struct gmesh *mesh, const char *name) +{ + struct gclass *classp; + + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { + if (strcmp(classp->lg_name, name) == 0) + return (classp); + } + return (NULL); +} + +static struct ggeom * +find_geom(struct gclass *classp, const char *name) +{ + struct ggeom *gp; + + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { + if (strcmp(gp->lg_name, name) == 0) + return (gp); + } + return (NULL); +} + +static void +mirror_resize(struct gctl_req *req, unsigned flags __unused) +{ + struct gmesh mesh; + struct gclass *classp; + struct ggeom *gp; + struct gprovider *pp; + struct gconsumer *cp; + off_t size; + int error, nargs; + const char *name; + char ssize[30]; + + nargs = gctl_get_int(req, "nargs"); + if (nargs < 1) { + gctl_error(req, "Too few arguments."); + return; + } + error = geom_gettree(&mesh); + if (error) + errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); + name = gctl_get_ascii(req, "class"); + if (name == NULL) + abort(); + classp = find_class(&mesh, name); + if (classp == NULL) + errx(EXIT_FAILURE, "Class %s not found.", name); + name = gctl_get_ascii(req, "arg0"); + if (name == NULL) + abort(); + gp = find_geom(classp, name); + if (gp == NULL) + errx(EXIT_FAILURE, "No such geom: %s.", name); + pp = LIST_FIRST(&gp->lg_provider); + if (pp == NULL) + errx(EXIT_FAILURE, "Provider of geom %s not found.", name); + size = pp->lg_mediasize; + name = gctl_get_ascii(req, "size"); + if (name == NULL) + errx(EXIT_FAILURE, "The size is not specified."); + if (*name == '*') { +#define CSZ(c) ((c)->lg_provider->lg_mediasize - \ + (c)->lg_provider->lg_sectorsize) + /* Find the maximum possible size */ + LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { + if (CSZ(cp) > size) + size = CSZ(cp); + } + LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { + if (CSZ(cp) < size) + size = CSZ(cp); + } +#undef CSZ + if (size == pp->lg_mediasize) + errx(EXIT_FAILURE, + "Cannot expand provider %s\n", + pp->lg_name); + } else { + error = g_parse_lba(name, pp->lg_sectorsize, &size); + if (error) + errc(EXIT_FAILURE, error, "Invalid size param"); + size *= pp->lg_sectorsize; + } + snprintf(ssize, sizeof(ssize), "%ju", (uintmax_t)size); + gctl_change_param(req, "size", -1, ssize); + geom_deletetree(&mesh); + gctl_issue(req); +} diff --git a/sbin/geom/class/mirror/gmirror.8 b/sbin/geom/class/mirror/gmirror.8 index 58ff8af..cabeac6 100644 --- a/sbin/geom/class/mirror/gmirror.8 +++ b/sbin/geom/class/mirror/gmirror.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 8, 2009 +.Dd November 20, 2013 .Dt GMIRROR 8 .Os .Sh NAME @@ -60,6 +60,11 @@ .Ar name .Ar prov ... .Nm +.Cm resize +.Op Fl v +.Op Fl s Ar size +.Ar name +.Nm .Cm insert .Op Fl hiv .Op Fl p Ar priority @@ -193,6 +198,16 @@ balance algorithm. Rebuild the given mirror components forcibly. If autosynchronization was not turned off for the given device, this command should be unnecessary. +.It Cm resize +Change the size of the given mirror. +.Pp +Additional options include: +.Bl -tag -width ".Fl s Ar size" +.It Fl s Ar size +New size of the mirror is expressed in logical block numbers. +This option can be omitted, then it will be automatically calculated to +maximum available size. +.El .It Cm insert Add the given component(s) to the existing mirror. .Pp |