diff options
Diffstat (limited to 'lib/geom/mirror')
-rw-r--r-- | lib/geom/mirror/Makefile | 7 | ||||
-rw-r--r-- | lib/geom/mirror/Makefile.depend | 17 | ||||
-rw-r--r-- | lib/geom/mirror/geom_mirror.c | 495 | ||||
-rw-r--r-- | lib/geom/mirror/gmirror.8 | 454 |
4 files changed, 973 insertions, 0 deletions
diff --git a/lib/geom/mirror/Makefile b/lib/geom/mirror/Makefile new file mode 100644 index 000000000000..cf0174ee0766 --- /dev/null +++ b/lib/geom/mirror/Makefile @@ -0,0 +1,7 @@ +PACKAGE=geom + +GEOM_CLASS= mirror + +LIBADD= md + +.include <bsd.lib.mk> diff --git a/lib/geom/mirror/Makefile.depend b/lib/geom/mirror/Makefile.depend new file mode 100644 index 000000000000..27e87393b549 --- /dev/null +++ b/lib/geom/mirror/Makefile.depend @@ -0,0 +1,17 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + lib/libgeom \ + lib/libmd \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/lib/geom/mirror/geom_mirror.c b/lib/geom/mirror/geom_mirror.c new file mode 100644 index 000000000000..8b47592803d9 --- /dev/null +++ b/lib/geom/mirror/geom_mirror.c @@ -0,0 +1,495 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * 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 THE AUTHORS 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 THE AUTHORS 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/param.h> +#include <err.h> +#include <errno.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <assert.h> +#include <libgeom.h> +#include <geom/mirror/g_mirror.h> +#include <core/geom.h> +#include <misc/subr.h> + +uint32_t lib_version = G_LIB_VERSION; +uint32_t version = G_MIRROR_VERSION; + +#define GMIRROR_BALANCE "load" +#define GMIRROR_SLICE "4096" +#define GMIRROR_PRIORITY "0" + +static void mirror_main(struct gctl_req *req, unsigned flags); +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, + "[-v] name prov ..." + }, + { "clear", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, + "[-v] prov ..." + }, + { "configure", G_FLAG_VERBOSE, NULL, + { + { 'a', "autosync", NULL, G_TYPE_BOOL }, + { 'b', "balance", "", G_TYPE_STRING }, + { 'd', "dynamic", NULL, G_TYPE_BOOL }, + { 'f', "failsync", NULL, G_TYPE_BOOL }, + { 'F', "nofailsync", NULL, G_TYPE_BOOL }, + { 'h', "hardcode", NULL, G_TYPE_BOOL }, + { 'n', "noautosync", NULL, G_TYPE_BOOL }, + { 'p', "priority", "-1", G_TYPE_NUMBER }, + { 's', "slice", "-1", G_TYPE_NUMBER }, + G_OPT_SENTINEL + }, + "[-adfFhnv] [-b balance] [-s slice] name\n" + "[-v] -p priority name prov" + }, + { "create", G_FLAG_VERBOSE, NULL, + { + { 'b', "balance", GMIRROR_BALANCE, G_TYPE_STRING }, + { 'F', "nofailsync", NULL, G_TYPE_BOOL }, + { 'n', "noautosync", NULL, G_TYPE_BOOL }, + { 's', "slice", GMIRROR_SLICE, G_TYPE_NUMBER }, + G_OPT_SENTINEL + }, + "[-Fnv] [-b balance] [-s slice] name prov ..." + }, + { "deactivate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, + "[-v] name prov ..." + }, + { "destroy", G_FLAG_VERBOSE, NULL, + { + { 'f', "force", NULL, G_TYPE_BOOL }, + G_OPT_SENTINEL + }, + "[-fv] name ..." + }, + { "dump", 0, mirror_main, G_NULL_OPTS, + "prov ..." + }, + { "forget", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, + "name ..." + }, + { "label", G_FLAG_VERBOSE, mirror_main, + { + { 'b', "balance", GMIRROR_BALANCE, G_TYPE_STRING }, + { 'F', "nofailsync", NULL, G_TYPE_BOOL }, + { 'h', "hardcode", NULL, G_TYPE_BOOL }, + { 'n', "noautosync", NULL, G_TYPE_BOOL }, + { 's', "slice", GMIRROR_SLICE, G_TYPE_NUMBER }, + G_OPT_SENTINEL + }, + "[-Fhnv] [-b balance] [-s slice] name prov ..." + }, + { "insert", G_FLAG_VERBOSE, NULL, + { + { 'h', "hardcode", NULL, G_TYPE_BOOL }, + { 'i', "inactive", NULL, G_TYPE_BOOL }, + { 'p', "priority", GMIRROR_PRIORITY, G_TYPE_NUMBER }, + G_OPT_SENTINEL + }, + "[-hiv] [-p priority] name prov ..." + }, + { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, + "[-v] name prov ..." + }, + { "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 }, + G_OPT_SENTINEL + }, + "[-fv] name ..." + }, + G_CMD_SENTINEL +}; + +static int verbose = 0; + +static void +mirror_main(struct gctl_req *req, unsigned flags) +{ + const char *name; + + if ((flags & G_FLAG_VERBOSE) != 0) + verbose = 1; + + name = gctl_get_ascii(req, "verb"); + if (name == NULL) { + gctl_error(req, "No '%s' argument.", "verb"); + return; + } + if (strcmp(name, "label") == 0) + mirror_label(req); + else if (strcmp(name, "clear") == 0) + mirror_clear(req); + else if (strcmp(name, "dump") == 0) + mirror_dump(req); + else if (strcmp(name, "activate") == 0) + mirror_activate(req); + else + gctl_error(req, "Unknown command: %s.", name); +} + +static void +mirror_label(struct gctl_req *req) +{ + struct g_mirror_metadata md; + u_char sector[512]; + const char *str; + unsigned sectorsize; + off_t mediasize; + intmax_t val; + int error, i, nargs, bal, hardcode; + + bzero(sector, sizeof(sector)); + nargs = gctl_get_int(req, "nargs"); + if (nargs < 2) { + gctl_error(req, "Too few arguments."); + return; + } + + strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic)); + md.md_version = G_MIRROR_VERSION; + str = gctl_get_ascii(req, "arg0"); + strlcpy(md.md_name, str, sizeof(md.md_name)); + md.md_mid = arc4random(); + md.md_all = nargs - 1; + md.md_mflags = 0; + md.md_dflags = 0; + md.md_genid = 0; + md.md_syncid = 1; + md.md_sync_offset = 0; + val = gctl_get_intmax(req, "slice"); + md.md_slice = val; + str = gctl_get_ascii(req, "balance"); + bal = balance_id(str); + if (bal == -1) { + gctl_error(req, "Invalid balance algorithm."); + return; + } + md.md_balance = bal; + if (gctl_get_int(req, "noautosync")) + md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; + if (gctl_get_int(req, "nofailsync")) + md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC; + hardcode = gctl_get_int(req, "hardcode"); + + /* + * Calculate sectorsize by finding least common multiple from + * sectorsizes of every disk and find the smallest mediasize. + */ + mediasize = 0; + sectorsize = 0; + for (i = 1; i < nargs; i++) { + unsigned ssize; + off_t msize; + + str = gctl_get_ascii(req, "arg%d", i); + msize = g_get_mediasize(str); + ssize = g_get_sectorsize(str); + if (msize == 0 || ssize == 0) { + gctl_error(req, "Can't get informations about %s: %s.", + str, strerror(errno)); + return; + } + msize -= ssize; + if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) + mediasize = msize; + if (sectorsize == 0) + sectorsize = ssize; + else + sectorsize = g_lcm(sectorsize, ssize); + } + md.md_mediasize = mediasize; + md.md_sectorsize = sectorsize; + md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); + + /* + * Clear last sector first, to spoil all components if device exists. + */ + for (i = 1; i < nargs; i++) { + str = gctl_get_ascii(req, "arg%d", i); + error = g_metadata_clear(str, NULL); + if (error != 0) { + gctl_error(req, "Can't store metadata on %s: %s.", str, + strerror(error)); + return; + } + } + + /* + * Ok, store metadata (use disk number as priority). + */ + for (i = 1; i < nargs; i++) { + str = gctl_get_ascii(req, "arg%d", i); + md.md_did = arc4random(); + md.md_priority = i - 1; + md.md_provsize = g_get_mediasize(str); + assert(md.md_provsize != 0); + if (!hardcode) + bzero(md.md_provider, sizeof(md.md_provider)); + else { + if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + str += sizeof(_PATH_DEV) - 1; + strlcpy(md.md_provider, str, sizeof(md.md_provider)); + } + mirror_metadata_encode(&md, sector); + error = g_metadata_store(str, sector, sizeof(sector)); + if (error != 0) { + fprintf(stderr, "Can't store metadata on %s: %s.\n", + str, strerror(error)); + gctl_error(req, "Not fully done."); + continue; + } + if (verbose) + printf("Metadata value stored on %s.\n", str); + } +} + +static void +mirror_clear(struct gctl_req *req) +{ + const char *name; + int error, i, nargs; + + nargs = gctl_get_int(req, "nargs"); + if (nargs < 1) { + gctl_error(req, "Too few arguments."); + return; + } + + for (i = 0; i < nargs; i++) { + name = gctl_get_ascii(req, "arg%d", i); + error = g_metadata_clear(name, G_MIRROR_MAGIC); + if (error != 0) { + fprintf(stderr, "Can't clear metadata on %s: %s.\n", + name, strerror(error)); + gctl_error(req, "Not fully done."); + continue; + } + if (verbose) + printf("Metadata cleared on %s.\n", name); + } +} + +static void +mirror_dump(struct gctl_req *req) +{ + struct g_mirror_metadata md, tmpmd; + const char *name; + int error, i, nargs; + + nargs = gctl_get_int(req, "nargs"); + if (nargs < 1) { + gctl_error(req, "Too few arguments."); + return; + } + + for (i = 0; i < nargs; i++) { + name = gctl_get_ascii(req, "arg%d", i); + error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), + G_MIRROR_MAGIC); + if (error != 0) { + fprintf(stderr, "Can't read metadata from %s: %s.\n", + name, strerror(error)); + gctl_error(req, "Not fully done."); + continue; + } + if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) { + fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", + name); + gctl_error(req, "Not fully done."); + continue; + } + printf("Metadata on %s:\n", name); + mirror_metadata_dump(&md); + printf("\n"); + } +} + +static void +mirror_activate(struct gctl_req *req) +{ + struct g_mirror_metadata md, tmpmd; + const char *name, *path; + int error, i, nargs; + + nargs = gctl_get_int(req, "nargs"); + if (nargs < 2) { + gctl_error(req, "Too few arguments."); + return; + } + name = gctl_get_ascii(req, "arg0"); + + for (i = 1; i < nargs; i++) { + path = gctl_get_ascii(req, "arg%d", i); + error = g_metadata_read(path, (u_char *)&tmpmd, sizeof(tmpmd), + G_MIRROR_MAGIC); + if (error != 0) { + fprintf(stderr, "Cannot read metadata from %s: %s.\n", + path, strerror(error)); + gctl_error(req, "Not fully done."); + continue; + } + if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) { + fprintf(stderr, + "MD5 hash mismatch for provider %s, skipping.\n", + path); + gctl_error(req, "Not fully done."); + continue; + } + if (strcmp(md.md_name, name) != 0) { + fprintf(stderr, + "Provider %s is not the mirror %s component.\n", + path, name); + gctl_error(req, "Not fully done."); + continue; + } + md.md_dflags &= ~G_MIRROR_DISK_FLAG_INACTIVE; + mirror_metadata_encode(&md, (u_char *)&tmpmd); + error = g_metadata_store(path, (u_char *)&tmpmd, sizeof(tmpmd)); + if (error != 0) { + fprintf(stderr, "Cannot write metadata from %s: %s.\n", + path, strerror(error)); + gctl_error(req, "Not fully done."); + continue; + } + if (verbose) + 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, *g; + char ssize[30]; + + nargs = gctl_get_int(req, "nargs"); + if (nargs != 1) + errx(EXIT_FAILURE, "Invalid number of arguments."); + name = gctl_get_ascii(req, "class"); + if (name == NULL) + abort(); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, name, g, 1); + if (error) + errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); + classp = find_class(&mesh, name); + if (classp == NULL) + errx(EXIT_FAILURE, "Class %s not found.", name); + gp = find_geom(classp, g); + if (gp == NULL) + errx(EXIT_FAILURE, "No such geom: %s.", g); + pp = LIST_FIRST(&gp->lg_provider); + if (pp == NULL) + errx(EXIT_FAILURE, "Provider of geom %s not found.", g); + 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/lib/geom/mirror/gmirror.8 b/lib/geom/mirror/gmirror.8 new file mode 100644 index 000000000000..aeffb2d948b1 --- /dev/null +++ b/lib/geom/mirror/gmirror.8 @@ -0,0 +1,454 @@ +.\" Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org> +.\" All rights reserved. +.\" +.\" 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 THE AUTHORS 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 THE AUTHORS 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. +.\" +.Dd January 23, 2025 +.Dt GMIRROR 8 +.Os +.Sh NAME +.Nm gmirror +.Nd "control utility for mirrored devices" +.Sh SYNOPSIS +To compile GEOM_MIRROR into your kernel, add the following lines to your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "options GEOM_MIRROR" +.Ed +.Pp +Alternatively, to load the GEOM_MIRROR module at boot time, add the following +line to your +.Xr loader.conf 5 : +.Bd -literal -offset indent +geom_mirror_load="YES" +.Ed +.Pp +.No Usage of the Nm +utility: +.Pp +.Nm +.Cm label +.Op Fl Fhnv +.Op Fl b Ar balance +.Op Fl s Ar slice +.Ar name +.Ar prov ... +.Nm +.Cm clear +.Op Fl v +.Ar prov ... +.Nm +.Cm create +.Op Fl Fnv +.Op Fl b Ar balance +.Op Fl s Ar slice +.Ar name +.Ar prov ... +.Nm +.Cm configure +.Op Fl adfFhnv +.Op Fl b Ar balance +.Op Fl s Ar slice +.Ar name +.Nm +.Cm configure +.Op Fl v +.Fl p Ar priority +.Ar name +.Ar prov +.Nm +.Cm rebuild +.Op Fl v +.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 +.Ar name +.Ar prov ... +.Nm +.Cm remove +.Op Fl v +.Ar name +.Ar prov ... +.Nm +.Cm activate +.Op Fl v +.Ar name +.Ar prov ... +.Nm +.Cm deactivate +.Op Fl v +.Ar name +.Ar prov ... +.Nm +.Cm destroy +.Op Fl fv +.Ar name ... +.Nm +.Cm forget +.Op Fl v +.Ar name ... +.Nm +.Cm stop +.Op Fl fv +.Ar name ... +.Nm +.Cm dump +.Ar prov ... +.Nm +.Cm list +.Nm +.Cm status +.Nm +.Cm load +.Nm +.Cm unload +.Sh DESCRIPTION +The +.Nm +utility is used for mirror (RAID1) configurations. +After a mirror's creation, all components are detected and configured +automatically. +All operations like failure detection, stale component detection, rebuild +of stale components, etc.\& are also done automatically. +The +.Nm +utility uses on-disk metadata (stored in the provider's last sector) to store all needed +information. +Since the last sector is used for this purpose, it is possible to place a root +file system on a mirror. +.Pp +The first argument to +.Nm +indicates an action to be performed: +.Bl -tag -width ".Cm deactivate" +.It Cm label +Create a mirror. +The order of components is important, because a component's priority is based on its position +(starting from 0 to 255). +The component with the biggest priority is used by the +.Cm prefer +balance algorithm +and is also used as a master component when resynchronization is needed, +e.g.\& after a power failure when the device was open for writing. +.Pp +Additional options include: +.Bl -tag -width ".Fl b Ar balance" +.It Fl b Ar balance +Specifies balance algorithm to use, one of: +.Bl -tag -width ".Cm round-robin" +.It Cm load +Read from the component with the lowest load. +This is the default balance algorithm. +.It Cm prefer +Read from the component with the biggest priority. +.It Cm round-robin +Use round-robin algorithm when choosing component to read. +.It Cm split +Split read requests, which are bigger than or equal to slice size on N pieces, +where N is the number of active components. +.El +.It Fl F +Do not synchronize after a power failure or system crash. +Assumes device is in consistent state. +.It Fl h +Hardcode providers' names in metadata. +.It Fl n +Turn off autosynchronization of stale components. +.It Fl s Ar slice +When using the +.Cm split +balance algorithm and an I/O READ request is bigger than or equal to this value, +the I/O request will be split into N pieces, where N is the number of active +components. +Defaults to 4096 bytes. +.El +.It Cm clear +Clear metadata on the given providers. +.It Cm create +Similar to +.Cm label , +but creates mirror without storing on-disk metadata in last sector. +This special "manual" operation mode assumes some external control to manage +mirror detection after reboot, device hot-plug and other external events. +.It Cm configure +Configure the given device. +.Pp +Additional options include: +.Bl -tag -width ".Fl p Ar priority" +.It Fl a +Turn on autosynchronization of stale components. +.It Fl b Ar balance +Specifies balance algorithm to use. +.It Fl d +Do not hardcode providers' names in metadata. +.It Fl f +Synchronize device after a power failure or system crash. +.It Fl F +Do not synchronize after a power failure or system crash. +Assumes device is in consistent state. +.It Fl h +Hardcode providers' names in metadata. +.It Fl n +Turn off autosynchronization of stale components. +.It Fl p Ar priority +Specifies priority for the given component +.Ar prov . +.It Fl s Ar slice +Specifies slice size for +.Cm split +balance algorithm. +.El +.It Cm rebuild +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 +Additional options include: +.Bl -tag -width ".Fl p Ar priority" +.It Fl h +Hardcode providers' names in metadata. +.It Fl i +Mark component(s) as inactive immediately after insertion. +.It Fl p Ar priority +Specifies priority of the given component(s). +.El +.It Cm remove +Remove the given component(s) from the mirror and clear metadata on it. +.It Cm activate +Activate the given component(s), which were marked as inactive before. +.It Cm deactivate +Mark the given component(s) as inactive, so it will not be automatically +connected to the mirror. +.It Cm destroy +Stop the given mirror and clear metadata on all its components. +.Pp +Additional options include: +.Bl -tag -width ".Fl f" +.It Fl f +Stop the given mirror even if it is opened. +.El +.It Cm forget +Forget about components which are not connected. +This command is useful when a disk has failed and cannot be reconnected, preventing the +.Cm remove +command from being used to remove it. +.It Cm stop +Stop the given mirror. +.Pp +Additional options include: +.Bl -tag -width ".Fl f" +.It Fl f +Stop the given mirror even if it is opened. +.El +.It Cm dump +Dump metadata stored on the given providers. +.It Cm list +See +.Xr geom 8 . +.It Cm status +See +.Xr geom 8 . +.It Cm load +See +.Xr geom 8 . +.It Cm unload +See +.Xr geom 8 . +.El +.Pp +Additional options include: +.Bl -tag -width ".Fl v" +.It Fl v +Be more verbose. +.El +.Sh EXIT STATUS +Exit status is 0 on success, and 1 if the command fails. +.Sh EXAMPLES +Use 3 disks to setup a mirror. +Choose split balance algorithm, split only +requests which are bigger than or equal to 2kB. +Create file system, +mount it, then unmount it and stop device: +.Bd -literal -offset indent +gmirror label -v -b split -s 2048 data da0 da1 da2 +newfs /dev/mirror/data +mount /dev/mirror/data /mnt +\&... +umount /mnt +gmirror stop data +gmirror unload +.Ed +.Pp +Create a mirror on disk with valid data (note that the last sector of the disk +will be overwritten). +Add another disk to this mirror, +so it will be synchronized with existing disk: +.Bd -literal -offset indent +gmirror label -v -b round-robin data da0 +gmirror insert data da1 +.Ed +.Pp +Create a mirror, but do not use automatic synchronization feature. +Add another disk and rebuild it: +.Bd -literal -offset indent +gmirror label -v -n -b load data da0 da1 +gmirror insert data da2 +gmirror rebuild data da2 +.Ed +.Pp +One disk failed. +Replace it with a brand new one: +.Bd -literal -offset indent +gmirror forget data +gmirror insert data da1 +.Ed +.Pp +Create a mirror, deactivate one component, do the backup and connect it again. +It will not be resynchronized, if there is no need to do so (there were no writes in +the meantime): +.Bd -literal -offset indent +gmirror label data da0 da1 +gmirror deactivate data da1 +dd if=/dev/da1 of=/backup/data.img bs=1m +gmirror activate data da1 +.Ed +.Sh SYSCTL VARIABLES +The following +.Xr sysctl 8 +variables can be used to configure behavior for all mirrors. +.Bl -tag -width indent +.It Va kern.geom.mirror.debug +Control the verbosity of kernel logging related to mirrors. +A value larger than 0 will enable debug logging. +.It Va kern.geom.mirror.timeout +The amount of time, in seconds, to wait for all copies of a mirror to +appear before starting the mirror. +Disks that appear after the mirror has been started are not automatically +added to the mirror. +.It Va kern.geom.mirror.idletime +The amount of time, in seconds, which must elapse after the last write to +a mirror before that mirror is marked clean. +Clean mirrors do not need to be synchronized after a power failure or +system crash. +A small value may result in frequent overwrites of the disks' metadata +sectors, and thus may reduce the longevity of the disks. +.It Va kern.geom.mirror.disconnect_on_failure +Determine whether a disk is automatically removed from its mirror when an +I/O request to that disk fails. +.It Va kern.geom.mirror.sync_requests +The number of parallel I/O requests used while synchronizing a mirror. +This parameter may only be configured as a +.Xr loader.conf 5 +tunable. +.It Va kern.geom.mirror.sync_update_period +The period, in seconds, at which a synchronizing mirror's metadata is +updated. +Periodic updates are used to record a synchronization's progress so that +an interrupted synchronization may be resumed starting at the recorded +offset, rather than at the beginning. +A smaller value results in more accurate progress tracking, but also +increases the number of non-sequential writes to the disk being synchronized. +If the sysctl value is 0, no updates are performed until the synchronization +is complete. +.El +.Sh NOTES +Doing kernel dumps to +.Nm +providers is possible, but some conditions have to be met. +First of all, a kernel dump will go only to one component and +.Nm +always chooses the component with the highest priority. +Reading a dump from the mirror on boot will only work if the +.Cm prefer +balance algorithm is used (that way +.Nm +will read only from the component with the highest priority). +If you use a different balance algorithm, you should create an +.Xr rc 8 +script that sets the balance algorithm to +.Cm prefer , +for example with the following command: +.Bd -literal -offset indent +gmirror configure -b prefer data +.Ed +.Pp +Make sure that +.Xr rcorder 8 +schedules the new script before +.Xr savecore 8 . +The desired balance algorithm can be restored later on +by placing the following command in +.Xr rc.local 8 : +.Bd -literal -offset indent +gmirror configure -b round-robin data +.Ed +.Pp +The decision which component to choose for dumping is made when +.Xr dumpon 8 +is called. +If on the next boot a component with a higher priority will be available, +the prefer algorithm will choose to read from it and +.Xr savecore 8 +will find nothing. +If on the next boot a component with the highest priority will be synchronized, +the prefer balance algorithm will read from the next one, thus will find nothing +there. +.Sh SEE ALSO +.Xr geom 4 , +.Xr dumpon 8 , +.Xr geom 8 , +.Xr mount 8 , +.Xr newfs 8 , +.Xr savecore 8 , +.Xr sysctl 8 , +.Xr umount 8 +.Sh HISTORY +The +.Nm +utility appeared in +.Fx 5.3 . +.Sh AUTHORS +.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org +.Sh BUGS +There should be a way to change a component's priority inside a running mirror. +.Pp +There should be a section with an implementation description. |