summaryrefslogtreecommitdiffstats
path: root/sbin/geom
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2014-01-10 07:43:40 +0000
committerae <ae@FreeBSD.org>2014-01-10 07:43:40 +0000
commit5308ec580218db5152159128ab830fcdf297c82d (patch)
tree247e12a038d718dd5d8bd2a75820882191ba856c /sbin/geom
parenta956d3e4f75ef8d4c0bd9c1d597c34ec1c97edef (diff)
downloadFreeBSD-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/geom')
-rw-r--r--sbin/geom/class/mirror/geom_mirror.c102
-rw-r--r--sbin/geom/class/mirror/gmirror.817
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
OpenPOWER on IntegriCloud