aboutsummaryrefslogtreecommitdiff
path: root/lib/geom/concat
diff options
context:
space:
mode:
Diffstat (limited to 'lib/geom/concat')
-rw-r--r--lib/geom/concat/Makefile5
-rw-r--r--lib/geom/concat/Makefile.depend16
-rw-r--r--lib/geom/concat/gconcat.8229
-rw-r--r--lib/geom/concat/geom_concat.c254
4 files changed, 504 insertions, 0 deletions
diff --git a/lib/geom/concat/Makefile b/lib/geom/concat/Makefile
new file mode 100644
index 000000000000..c9f9d0e38c75
--- /dev/null
+++ b/lib/geom/concat/Makefile
@@ -0,0 +1,5 @@
+PACKAGE=geom
+
+GEOM_CLASS= concat
+
+.include <bsd.lib.mk>
diff --git a/lib/geom/concat/Makefile.depend b/lib/geom/concat/Makefile.depend
new file mode 100644
index 000000000000..0dd05cace3c0
--- /dev/null
+++ b/lib/geom/concat/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libgeom \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/geom/concat/gconcat.8 b/lib/geom/concat/gconcat.8
new file mode 100644
index 000000000000..165f809ffba8
--- /dev/null
+++ b/lib/geom/concat/gconcat.8
@@ -0,0 +1,229 @@
+.\" Copyright (c) 2004-2005 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 GCONCAT 8
+.Os
+.Sh NAME
+.Nm gconcat
+.Nd "disk concatenation control utility"
+.Sh SYNOPSIS
+.Nm
+.Cm create
+.Op Fl v
+.Ar name
+.Ar prov ...
+.Nm
+.Cm destroy
+.Op Fl fv
+.Ar name ...
+.Nm
+.Cm label
+.Op Fl hv
+.Ar name
+.Ar prov ...
+.Nm
+.Cm append
+.Op Fl hv
+.Ar name
+.Ar prov
+.Nm
+.Cm stop
+.Op Fl fv
+.Ar name ...
+.Nm
+.Cm clear
+.Op Fl v
+.Ar prov ...
+.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 device concatenation configuration.
+The concatenation can be configured using two different methods:
+.Dq manual
+or
+.Dq automatic .
+When using the
+.Dq manual
+method, no metadata are stored on the devices, so the concatenated
+device has to be configured by hand every time it is needed.
+The
+.Dq automatic
+method uses on-disk metadata to detect devices.
+Once devices are labeled, they will be automatically detected and
+configured.
+.Pp
+The first argument to
+.Nm
+indicates an action to be performed:
+.Bl -tag -width ".Cm destroy"
+.It Cm create
+Concatenate the given devices with specified
+.Ar name .
+This is the
+.Dq manual
+method.
+The kernel module
+.Pa geom_concat.ko
+will be loaded if it is not loaded already.
+.It Cm label
+Concatenate the given devices with the specified
+.Ar name .
+This is the
+.Dq automatic
+method, where metadata are stored in every device's last sector.
+The kernel module
+.Pa geom_concat.ko
+will be loaded if it is not loaded already.
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl h"
+.It Fl h
+Hardcode providers' names in metadata.
+.El
+.It Cm append
+Append a new device to the end of an existing concatenate device
+with the specified
+.Ar name .
+.Pp
+If the existing device is using the
+.Dq manual
+method, the new device is simply appended as-is.
+.Pp
+If the existing device is using the
+.Dq automatic
+method, the device is appended persistently.
+New
+.Cm gconcat
+metadata is written to all existing components, as well as to the
+newly added one.
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl h"
+.It Fl h
+Hardcode providers' names in metadata.
+.El
+.It Cm stop
+Turn off existing concatenate device by its
+.Ar name .
+This command does not touch on-disk metadata!
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl f"
+.It Fl f
+Stop the given device even if it is opened.
+.El
+.It Cm destroy
+Same as
+.Cm stop .
+.It Cm clear
+Clear metadata on the given devices.
+.It Cm dump
+Dump metadata stored on the given devices.
+.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:
+.Bl -tag -width indent
+.It Fl v
+Be more verbose.
+.El
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 8
+variables can be used to control the behavior of the
+.Nm CONCAT
+GEOM class.
+The default value is shown next to each variable.
+.Bl -tag -width indent
+.It Va kern.geom.concat.debug : No 0
+Debug level of the
+.Nm CONCAT
+GEOM class.
+This can be set to a number between 0 and 3 inclusive.
+If set to 0 minimal debug information is printed, and if set to 3 the
+maximum amount of debug information is printed.
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, and 1 if the command fails.
+.Sh EXAMPLES
+The following example shows how to configure four disks for automatic
+concatenation, create a file system on it, and mount it:
+.Bd -literal -offset indent
+gconcat label -v data /dev/da0 /dev/da1 /dev/da2 /dev/da3
+newfs /dev/concat/data
+mount /dev/concat/data /mnt
+[...]
+umount /mnt
+gconcat stop data
+gconcat unload
+.Ed
+.Pp
+Configure concatenated provider on one disk only.
+Create file system.
+Add two more disks and extend existing file system.
+.Bd -literal -offset indent
+gconcat label data /dev/da0
+newfs /dev/concat/data
+gconcat label data /dev/da0 /dev/da1 /dev/da2
+growfs /dev/concat/data
+.Ed
+.Sh SEE ALSO
+.Xr geom 4 ,
+.Xr loader.conf 5 ,
+.Xr geom 8 ,
+.Xr growfs 8 ,
+.Xr mount 8 ,
+.Xr newfs 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
diff --git a/lib/geom/concat/geom_concat.c b/lib/geom/concat/geom_concat.c
new file mode 100644
index 000000000000..424f60ce0179
--- /dev/null
+++ b/lib/geom/concat/geom_concat.c
@@ -0,0 +1,254 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004-2005 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 <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <assert.h>
+#include <libgeom.h>
+#include <geom/concat/g_concat.h>
+
+#include "core/geom.h"
+#include "misc/subr.h"
+
+
+uint32_t lib_version = G_LIB_VERSION;
+uint32_t version = G_CONCAT_VERSION;
+
+static void concat_main(struct gctl_req *req, unsigned flags);
+static void concat_clear(struct gctl_req *req);
+static void concat_dump(struct gctl_req *req);
+static void concat_label(struct gctl_req *req);
+
+struct g_command class_commands[] = {
+ { "append", G_FLAG_VERBOSE, NULL,
+ {
+ { 'h', "hardcode", NULL, G_TYPE_BOOL },
+ G_OPT_SENTINEL
+ },
+ "[-hv] name prov"
+ },
+ { "clear", G_FLAG_VERBOSE, concat_main, G_NULL_OPTS,
+ "[-v] prov ..."
+ },
+ { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, 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, concat_main, G_NULL_OPTS,
+ "prov ..."
+ },
+ { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, concat_main,
+ {
+ { 'h', "hardcode", NULL, G_TYPE_BOOL },
+ G_OPT_SENTINEL
+ },
+ "[-hv] name prov ..."
+ },
+ { "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
+concat_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)
+ concat_label(req);
+ else if (strcmp(name, "clear") == 0)
+ concat_clear(req);
+ else if (strcmp(name, "dump") == 0)
+ concat_dump(req);
+ else
+ gctl_error(req, "Unknown command: %s.", name);
+}
+
+static void
+concat_label(struct gctl_req *req)
+{
+ struct g_concat_metadata md;
+ u_char sector[512];
+ const char *name;
+ int error, i, hardcode, nargs;
+
+ bzero(sector, sizeof(sector));
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs < 2) {
+ gctl_error(req, "Too few arguments.");
+ return;
+ }
+ hardcode = gctl_get_int(req, "hardcode");
+
+ /*
+ * Clear last sector first to spoil all components if device exists.
+ */
+ for (i = 1; i < nargs; i++) {
+ name = gctl_get_ascii(req, "arg%d", i);
+ error = g_metadata_clear(name, NULL);
+ if (error != 0) {
+ gctl_error(req, "Can't store metadata on %s: %s.", name,
+ strerror(error));
+ return;
+ }
+ }
+
+ strlcpy(md.md_magic, G_CONCAT_MAGIC, sizeof(md.md_magic));
+ md.md_version = G_CONCAT_VERSION;
+ name = gctl_get_ascii(req, "arg0");
+ strlcpy(md.md_name, name, sizeof(md.md_name));
+ md.md_id = arc4random();
+ md.md_all = nargs - 1;
+
+ /*
+ * Ok, store metadata.
+ */
+ for (i = 1; i < nargs; i++) {
+ name = gctl_get_ascii(req, "arg%d", i);
+ md.md_no = i - 1;
+ if (!hardcode)
+ bzero(md.md_provider, sizeof(md.md_provider));
+ else {
+ if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ name += sizeof(_PATH_DEV) - 1;
+ strlcpy(md.md_provider, name, sizeof(md.md_provider));
+ }
+ md.md_provsize = g_get_mediasize(name);
+ if (md.md_provsize == 0) {
+ fprintf(stderr, "Can't get mediasize of %s: %s.\n",
+ name, strerror(errno));
+ gctl_error(req, "Not fully done.");
+ continue;
+ }
+ concat_metadata_encode(&md, sector);
+ error = g_metadata_store(name, sector, sizeof(sector));
+ if (error != 0) {
+ fprintf(stderr, "Can't store metadata on %s: %s.\n",
+ name, strerror(error));
+ gctl_error(req, "Not fully done.");
+ continue;
+ }
+ if (verbose)
+ printf("Metadata value stored on %s.\n", name);
+ }
+}
+
+static void
+concat_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_CONCAT_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
+concat_metadata_dump(const struct g_concat_metadata *md)
+{
+
+ printf(" Magic string: %s\n", md->md_magic);
+ printf(" Metadata version: %u\n", (u_int)md->md_version);
+ printf(" Device name: %s\n", md->md_name);
+ printf(" Device ID: %u\n", (u_int)md->md_id);
+ printf(" Disk number: %u\n", (u_int)md->md_no);
+ printf("Total number of disks: %u\n", (u_int)md->md_all);
+ printf(" Hardcoded provider: %s\n", md->md_provider);
+}
+
+static void
+concat_dump(struct gctl_req *req)
+{
+ struct g_concat_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_CONCAT_MAGIC);
+ if (error != 0) {
+ fprintf(stderr, "Can't read metadata from %s: %s.\n",
+ name, strerror(error));
+ gctl_error(req, "Not fully done.");
+ continue;
+ }
+ concat_metadata_decode((u_char *)&tmpmd, &md);
+ printf("Metadata on %s:\n", name);
+ concat_metadata_dump(&md);
+ printf("\n");
+ }
+}