Index: Makefile.inc1 =================================================================== --- Makefile.inc1 +++ Makefile.inc1 @@ -2429,6 +2429,7 @@ ${_cddl_lib_libavl} \ ${_cddl_lib_libzfs_core} \ ${_cddl_lib_libctf} \ + lib/libufs \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ ${_secure_lib_libcrypto} ${_lib_libldns} \ ${_secure_lib_libssh} ${_secure_lib_libssl} Index: etc/mtree/BSD.lib32.dist =================================================================== --- etc/mtree/BSD.lib32.dist +++ etc/mtree/BSD.lib32.dist @@ -8,6 +8,8 @@ lib32 dtrace .. + geom + .. i18n .. .. Index: lib/Makefile =================================================================== --- lib/Makefile +++ lib/Makefile @@ -18,12 +18,14 @@ ${_libcplusplus} \ ${_libcxxrt} \ libelf \ - msun + msun \ + libufs # The main list; please keep these sorted alphabetically. SUBDIR= ${SUBDIR_BOOTSTRAP} \ .WAIT \ + geom \ libalias \ libarchive \ libauditd \ @@ -85,7 +87,6 @@ libtacplus \ libthread_db \ libucl \ - libufs \ libugidfw \ libulog \ libutil \ Index: lib/geom/Makefile =================================================================== --- lib/geom/Makefile +++ lib/geom/Makefile @@ -2,6 +2,7 @@ .include +SUBDIR= ${GEOM_CLASSES} SUBDIR= cache SUBDIR+=concat .if ${MK_OPENSSL} != "no" Index: lib/geom/Makefile.classes =================================================================== --- /dev/null +++ lib/geom/Makefile.classes @@ -0,0 +1,26 @@ +# $FreeBSD$ + +.if !defined(COMPAT_32BIT) +GEOM_CLASS_DIR?=/lib/geom +.else +GEOM_CLASS_DIR?=/usr/lib32/geom +.endif + +GEOM_CLASSES= cache +GEOM_CLASSES+= concat +.if ${MK_OPENSSL} != "no" +GEOM_CLASSES+= eli +.endif +GEOM_CLASSES+= journal +GEOM_CLASSES+= label +GEOM_CLASSES+= mirror +GEOM_CLASSES+= mountver +GEOM_CLASSES+= multipath +GEOM_CLASSES+= nop +GEOM_CLASSES+= part +GEOM_CLASSES+= raid +GEOM_CLASSES+= raid3 +GEOM_CLASSES+= sched +GEOM_CLASSES+= shsec +GEOM_CLASSES+= stripe +GEOM_CLASSES+= virstor Index: lib/geom/Makefile.inc =================================================================== --- lib/geom/Makefile.inc +++ lib/geom/Makefile.inc @@ -1,13 +1,16 @@ # $FreeBSD$ -SHLIBDIR?=${GEOM_CLASS_DIR} +.include + +SHLIBDIR=${GEOM_CLASS_DIR} SHLIB_NAME?=geom_${GEOM_CLASS}.so -LINKS= ${BINDIR}/geom ${BINDIR}/g${GEOM_CLASS} MAN= g${GEOM_CLASS}.8 SRCS+= geom_${GEOM_CLASS}.c subr.c +CFLAGS+=-I${SRCTOP}/sbin/geom -NO_WMISSING_VARIABLE_DECLARATIONS= +.PATH: ${SRCTOP}/sbin/geom/misc -CFLAGS+= -I${.CURDIR:H:H} +NO_WMISSING_VARIABLE_DECLARATIONS= +.include "Makefile.classes" .include "../Makefile.inc" Index: sbin/geom/Makefile =================================================================== --- sbin/geom/Makefile +++ sbin/geom/Makefile @@ -1,28 +1,30 @@ # $FreeBSD$ -PACKAGE=runtime -.if defined(RESCUE) || defined(RELEASE_CRUNCH) +.include -.PATH: ${.CURDIR}/class/part \ - ${.CURDIR}/class/label \ - ${.CURDIR}/core \ - ${.CURDIR}/misc +.PATH: ${.CURDIR}/core ${.CURDIR}/misc -PROG= geom -SRCS= geom.c geom_label.c geom_part.c subr.c -MAN= +PACKAGE=runtime +PROG= geom +SRCS= geom.c subr.c +MAN= geom.8 +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/core +CFLAGS+= -DGEOM_CLASS_DIR=\"${GEOM_CLASS_DIR}\" -WARNS?= 2 -CFLAGS+=-I${.CURDIR} -I${.CURDIR}/core -DSTATIC_GEOM_CLASSES +LIBADD= geom util -LIBADD= geom util +.if defined(RESCUE) || defined(RELEASE_CRUNCH) +.PATH: ${SRCTOP}/lib/geom/part \ + ${SRCTOP}/lib/geom/label -.include +SRCS+= geom_label.c geom_part.c +MAN= +WARNS?= 2 +CFLAGS+=-DSTATIC_GEOM_CLASSES .else - -SUBDIR= core class - -.include - +.include "${SRCTOP}/lib/geom/Makefile.classes" +LINKS= ${GEOM_CLASSES:S|^|${BINDIR}/geom ${BINDIR}/g|} .endif + +.include Index: sbin/geom/Makefile.inc =================================================================== --- sbin/geom/Makefile.inc +++ /dev/null @@ -1,5 +0,0 @@ -# $FreeBSD$ - -GEOM_CLASS_DIR?=/lib/geom - -.include "../Makefile.inc" Index: sbin/geom/class/cache/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/cache/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= cache - -.include Index: sbin/geom/class/cache/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/cache/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/cache/gcache.8 =================================================================== --- /dev/null +++ sbin/geom/class/cache/gcache.8 @@ -1,192 +0,0 @@ -.\"- -.\" Copyright (c) 2010 Edward Tomasz Napierala -.\" 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 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 THE 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. -.\" -.\" $FreeBSD$ -.\" -.Dd January 3, 2010 -.Dt GCACHE 8 -.Os -.Sh NAME -.Nm gcache -.Nd "control utility for CACHE GEOM class" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Op Fl b Ar blocksize -.Op Fl s Ar size -.Ar name -.Ar prov -.Nm -.Cm configure -.Op Fl v -.Op Fl b Ar blocksize -.Op Fl s Ar size -.Ar name -.Nm -.Cm destroy -.Op Fl fv -.Ar name -.Nm -.Cm label -.Op Fl v -.Op Fl b Ar blocksize -.Op Fl s Ar size -.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 -.Op Fl s Ar name -.Nm -.Cm load -.Op Fl v -.Nm -.Cm unload -.Op Fl v -.Sh DESCRIPTION -The -.Nm -utility is used to control GEOM cache, which can -speed up read performance by sending fixed size -read requests to its consumer. It has been developed to address -the problem of a horrible read performance of a 64k blocksize FS -residing on a RAID3 array with 8 data components, where a single -disk component would only get 8k read requests, thus effectively -killing disk performance under high load. -.Pp -Caching 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 cached -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 -Cache the given devices with specified -.Ar name . -This is the -.Dq manual -method. -The kernel module -.Pa geom_cache.ko -will be loaded if it is not loaded already. -.It Cm label -Cache 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_cache.ko -will be loaded if it is not loaded already. -.It Cm stop -Turn off existing cache device by its -.Ar name . -This command does not touch on-disk metadata! -.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 f -Force the removal of the specified cache device. -.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 CACHE -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.cache.used_hi : No 20 -.It Va kern.geom.cache.used_lo : No 5 -.It Va kern.geom.cache.idletime : No 5 -.It Va kern.geom.cache.timeout : No 10 -.It Va kern.geom.cache.enable : No 1 -.It Va kern.geom.cache.debug : No 0 -Debug level of the -.Nm CACHE -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 SEE ALSO -.Xr geom 4 , -.Xr geom 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 7.0 . -.Sh AUTHORS -.An Ruslan Ermilov Aq Mt ru@FreeBSD.org Index: sbin/geom/class/cache/geom_cache.c =================================================================== --- /dev/null +++ sbin/geom/class/cache/geom_cache.c @@ -1,242 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2006 Ruslan Ermilov - * 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 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 THE 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_CACHE_VERSION; - -#define GCACHE_BLOCKSIZE "65536" -#define GCACHE_SIZE "100" - -static void cache_main(struct gctl_req *req, unsigned flags); -static void cache_clear(struct gctl_req *req); -static void cache_dump(struct gctl_req *req); -static void cache_label(struct gctl_req *req); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, cache_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "configure", G_FLAG_VERBOSE, NULL, - { - { 'b', "blocksize", "0", G_TYPE_NUMBER }, - { 's', "size", "0", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] [-b blocksize] [-s size] name" - }, - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - { 'b', "blocksize", GCACHE_BLOCKSIZE, G_TYPE_NUMBER }, - { 's', "size", GCACHE_SIZE, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] [-b blocksize] [-s size] name prov" - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name ..." - }, - { "dump", 0, cache_main, G_NULL_OPTS, - "prov ..." - }, - { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, cache_main, - { - { 'b', "blocksize", GCACHE_BLOCKSIZE, G_TYPE_NUMBER }, - { 's', "size", GCACHE_SIZE, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] [-b blocksize] [-s size] name prov" - }, - { "reset", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-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 -cache_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) - cache_label(req); - else if (strcmp(name, "clear") == 0) - cache_clear(req); - else if (strcmp(name, "dump") == 0) - cache_dump(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static void -cache_label(struct gctl_req *req) -{ - struct g_cache_metadata md; - u_char sector[512]; - const char *name; - int error, nargs; - intmax_t val; - - bzero(sector, sizeof(sector)); - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - - strlcpy(md.md_magic, G_CACHE_MAGIC, sizeof(md.md_magic)); - md.md_version = G_CACHE_VERSION; - name = gctl_get_ascii(req, "arg0"); - strlcpy(md.md_name, name, sizeof(md.md_name)); - val = gctl_get_intmax(req, "blocksize"); - md.md_bsize = val; - val = gctl_get_intmax(req, "size"); - md.md_size = val; - - name = gctl_get_ascii(req, "arg1"); - 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."); - return; - } - cache_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."); - return; - } - if (verbose) - printf("Metadata value stored on %s.\n", name); -} - -static void -cache_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_CACHE_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 -cache_metadata_dump(const struct g_cache_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(" Block size: %u\n", (u_int)md->md_bsize); - printf(" Cache size: %u\n", (u_int)md->md_size); - printf(" Provider size: %ju\n", (uintmax_t)md->md_provsize); -} - -static void -cache_dump(struct gctl_req *req) -{ - struct g_cache_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_CACHE_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - cache_metadata_decode((u_char *)&tmpmd, &md); - printf("Metadata on %s:\n", name); - cache_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/concat/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/concat/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= concat - -.include Index: sbin/geom/class/concat/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/concat/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/concat/gconcat.8 =================================================================== --- /dev/null +++ sbin/geom/class/concat/gconcat.8 @@ -1,197 +0,0 @@ -.\" Copyright (c) 2004-2005 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd May 21, 2004 -.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 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. -.It Cm stop -Turn off existing concatenate device by its -.Ar name . -This command does not touch on-disk metadata! -.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 f -Force the removal of the specified concatenated device. -.It Fl h -Hardcode providers' names in metadata. -.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 gvinum 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 Index: sbin/geom/class/concat/geom_concat.c =================================================================== --- /dev/null +++ sbin/geom/class/concat/geom_concat.c @@ -1,250 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2005 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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[] = { - { "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"); - } -} Index: sbin/geom/class/eli/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/eli/Makefile @@ -1,20 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc ${SRCTOP}/sys/geom/eli ${SRCTOP}/sys/crypto/sha2 - -GEOM_CLASS= eli -SRCS= g_eli_crypto.c -SRCS+= g_eli_hmac.c -SRCS+= g_eli_key.c -SRCS+= pkcs5v2.c -SRCS+= sha256c.c -SRCS+= sha512c.c - -LIBADD= md crypto - -WARNS?= 3 - -CFLAGS+=-I${SRCTOP}/sys - -.include Index: sbin/geom/class/eli/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/eli/Makefile.depend @@ -1,21 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libmd \ - sbin/geom/core \ - secure/lib/libcrypto \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/eli/geli.8 =================================================================== --- /dev/null +++ sbin/geom/class/eli/geli.8 @@ -1,1119 +0,0 @@ -.\" Copyright (c) 2005-2011 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd April 10, 2018 -.Dt GELI 8 -.Os -.Sh NAME -.Nm geli -.Nd "control utility for the cryptographic GEOM class" -.Sh SYNOPSIS -To compile GEOM_ELI into your kernel, add the following lines to your kernel -configuration file: -.Bd -ragged -offset indent -.Cd "device crypto" -.Cd "options GEOM_ELI" -.Ed -.Pp -Alternatively, to load the GEOM_ELI module at boot time, add the following line -to your -.Xr loader.conf 5 : -.Bd -literal -offset indent -geom_eli_load="YES" -.Ed -.Pp -Usage of the -.Nm -utility: -.Pp -.Nm -.Cm init -.Op Fl bdgPTv -.Op Fl a Ar aalgo -.Op Fl B Ar backupfile -.Op Fl e Ar ealgo -.Op Fl i Ar iterations -.Op Fl J Ar newpassfile -.Op Fl K Ar newkeyfile -.Op Fl l Ar keylen -.Op Fl s Ar sectorsize -.Op Fl V Ar version -.Ar prov -.Nm -.Cm label - an alias for -.Cm init -.Nm -.Cm attach -.Op Fl dnprv -.Op Fl j Ar passfile -.Op Fl k Ar keyfile -.Ar prov -.Nm -.Cm detach -.Op Fl fl -.Ar prov ... -.Nm -.Cm stop - an alias for -.Cm detach -.Nm -.Cm onetime -.Op Fl dT -.Op Fl a Ar aalgo -.Op Fl e Ar ealgo -.Op Fl l Ar keylen -.Op Fl s Ar sectorsize -.Ar prov -.Nm -.Cm configure -.Op Fl bBdDgGtT -.Ar prov ... -.Nm -.Cm setkey -.Op Fl pPv -.Op Fl i Ar iterations -.Op Fl j Ar passfile -.Op Fl J Ar newpassfile -.Op Fl k Ar keyfile -.Op Fl K Ar newkeyfile -.Op Fl n Ar keyno -.Ar prov -.Nm -.Cm delkey -.Op Fl afv -.Op Fl n Ar keyno -.Ar prov -.Nm -.Cm kill -.Op Fl av -.Op Ar prov ... -.Nm -.Cm backup -.Op Fl v -.Ar prov -.Ar file -.Nm -.Cm restore -.Op Fl fv -.Ar file -.Ar prov -.Nm -.Cm suspend -.Op Fl v -.Fl a | Ar prov ... -.Nm -.Cm resume -.Op Fl pv -.Op Fl j Ar passfile -.Op Fl k Ar keyfile -.Ar prov -.Nm -.Cm resize -.Op Fl v -.Fl s Ar oldsize -.Ar prov -.Nm -.Cm version -.Op Ar prov ... -.Nm -.Cm clear -.Op Fl v -.Ar prov ... -.Nm -.Cm dump -.Op Fl v -.Ar prov ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used to configure encryption on GEOM providers. -.Pp -The following is a list of the most important features: -.Pp -.Bl -bullet -offset indent -compact -.It -Utilizes the -.Xr crypto 9 -framework, so when there is crypto hardware available, -.Nm -will make use of it automatically. -.It -Supports many cryptographic algorithms (currently -.Nm AES-XTS , -.Nm AES-CBC , -.Nm Blowfish-CBC , -.Nm Camellia-CBC -and -.Nm 3DES-CBC ) . -.It -Can optionally perform data authentication (integrity verification) utilizing -one of the following algorithms: -.Nm HMAC/MD5 , -.Nm HMAC/SHA1 , -.Nm HMAC/RIPEMD160 , -.Nm HMAC/SHA256 , -.Nm HMAC/SHA384 -or -.Nm HMAC/SHA512 . -.It -Can create a User Key from up to two, piecewise components: a passphrase -entered via prompt or read from one or more passfiles; a keyfile read from -one or more files. -.It -Allows encryption of the root partition. -The user will be asked for the -passphrase before the root file system is mounted. -.It -Strengthens the passphrase component of the User Key with: -.Rs -.%A B. Kaliski -.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0." -.%R RFC -.%N 2898 -.Re -.It -Allows the use of two independent User Keys (e.g., a -.Qq "user key" -and a -.Qq "company key" ) . -.It -It is fast - -.Nm -performs simple sector-to-sector encryption. -.It -Allows the encrypted Master Key to be backed up and restored, -so that if a user has to quickly destroy key material, -it is possible to get the data back by restoring keys from -backup. -.It -Providers can be configured to automatically detach on last close -(so users do not have to remember to detach providers after unmounting -the file systems). -.It -Allows attaching a provider with a random, one-time Master Key - -useful for swap partitions and temporary file systems. -.It -Allows verification of data integrity (data authentication). -.It -Allows suspending and resuming encrypted devices. -.El -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm configure" -.It Cm init -Initialize the provider which needs to be encrypted. -Here you can set up the cryptographic algorithm to use, Data Key length, -etc. -The last sector of the provider is used to store metadata. -The -.Cm init -subcommand also automatically writes metadata backups to -.Pa /var/backups/.eli -file. -The metadata can be recovered with the -.Cm restore -subcommand described below. -.Pp -Additional options include: -.Bl -tag -width ".Fl J Ar newpassfile" -.It Fl a Ar aalgo -Enable data integrity verification (authentication) using the given algorithm. -This will reduce the size of storage available and also reduce speed. -For example, when using 4096 bytes sector and -.Nm HMAC/SHA256 -algorithm, 89% of the original provider storage will be available for use. -Currently supported algorithms are: -.Nm HMAC/MD5 , -.Nm HMAC/SHA1 , -.Nm HMAC/RIPEMD160 , -.Nm HMAC/SHA256 , -.Nm HMAC/SHA384 -and -.Nm HMAC/SHA512 . -If the option is not given, there will be no authentication, only encryption. -The recommended algorithm is -.Nm HMAC/SHA256 . -.It Fl b -Try to decrypt this partition during boot, before the root partition is mounted. -This makes it possible to use an encrypted root partition. -One will still need bootable unencrypted storage with a -.Pa /boot/ -directory, which can be a CD-ROM disc or USB pen-drive, that can be removed -after boot. -.It Fl B Ar backupfile -File name to use for metadata backup instead of the default -.Pa /var/backups/.eli . -To inhibit backups, you can use -.Pa none -as the -.Ar backupfile . -.It Fl d -When entering the passphrase to boot from this encrypted root filesystem, echo -.Ql * -characters. -This makes the length of the passphrase visible. -.It Fl e Ar ealgo -Encryption algorithm to use. -Currently supported algorithms are: -.Nm AES-XTS , -.Nm AES-CBC , -.Nm Blowfish-CBC , -.Nm Camellia-CBC , -.Nm 3DES-CBC , -and -.Nm NULL . -The default and recommended algorithm is -.Nm AES-XTS . -.Nm NULL -is unencrypted. -.It Fl g -Enable booting from this encrypted root filesystem. -The boot loader prompts for the passphrase and loads -.Xr loader 8 -from the encrypted partition. -.It Fl i Ar iterations -Number of iterations to use with PKCS#5v2 when processing User Key -passphrase component. -If this option is not specified, -.Nm -will find the number of iterations which is equal to 2 seconds of crypto work. -If 0 is given, PKCS#5v2 will not be used. -PKCS#5v2 processing is performed once, after all parts of the passphrase -component have been read. -.It Fl J Ar newpassfile -Specifies a file which contains the passphrase component of the User Key -(or part of it). -If -.Ar newpassfile -is given as -, standard input will be used. -Only the first line (excluding new-line character) is taken from the given file. -This argument can be specified multiple times, which has the effect of -reassembling a single passphrase split across multiple files. -Cannot be combined with the -.Fl P -option. -.It Fl K Ar newkeyfile -Specifies a file which contains the keyfile component of the User Key -(or part of it). -If -.Ar newkeyfile -is given as -, standard input will be used. -This argument can be specified multiple times, which has the effect of -reassembling a single keyfile split across multiple keyfile parts. -.It Fl l Ar keylen -Data Key length to use with the given cryptographic algorithm. -If the length is not specified, the selected algorithm uses its -.Em default -key length. -.Bl -ohang -offset indent -.It Nm AES-XTS -.Em 128 , -256 -.It Nm AES-CBC , Nm Camellia-CBC -.Em 128 , -192, -256 -.It Nm Blowfish-CBC -.Em 128 -+ n * 32, for n=[0..10] -.It Nm 3DES-CBC -.Em 192 -.El -.It Fl P -Do not use a passphrase as a component of the User Key. -Cannot be combined with the -.Fl J -option. -.It Fl s Ar sectorsize -Change decrypted provider's sector size. -Increasing the sector size allows increased performance, -because encryption/decryption which requires an initialization vector -is done per sector; fewer sectors means less computational work. -.It Fl T -Don't pass through -.Dv BIO_DELETE -calls (i.e., TRIM/UNMAP). -This can prevent an attacker from knowing how much space you're actually -using and which sectors contain live data, but will also prevent the -backing store (SSD, etc) from reclaiming space you're not using, which -may degrade its performance and lifespan. -The underlying provider may or may not actually obliterate the deleted -sectors when TRIM is enabled, so it should not be considered to add any -security. -.It Fl V Ar version -Metadata version to use. -This option is helpful when creating a provider that may be used by older -.Nm FreeBSD/GELI -versions. -Consult the -.Sx HISTORY -section to find which metadata version is supported by which FreeBSD version. -Note that using an older version of metadata may limit the number of -features available. -.El -.It Cm attach -Attach the given provider. -The encrypted Master Key will be loaded from the metadata and decrypted -using the given passphrase/keyfile and a new GEOM provider will be created -using the given provider's name with an -.Qq .eli -suffix. -.Pp -Additional options include: -.Bl -tag -width ".Fl j Ar passfile" -.It Fl d -If specified, a decrypted provider will be detached automatically on last close. -This can help with scarce memory so the user does not have to remember to detach the -provider after unmounting the file system. -It only works when the provider was opened for writing, so it will not work if -the file system on the provider is mounted read-only. -Probably a better choice is the -.Fl l -option for the -.Cm detach -subcommand. -.It Fl j Ar passfile -Specifies a file which contains the passphrase component of the User Key -(or part of it). -For more information see the description of the -.Fl J -option for the -.Cm init -subcommand. -.It Fl k Ar keyfile -Specifies a file which contains the keyfile component of the User Key -(or part of it). -For more information see the description of the -.Fl K -option for the -.Cm init -subcommand. -.It Fl n -Do a dry-run decryption. -This is useful to verify passphrase and keyfile without decrypting the device. -.It Fl p -Do not use a passphrase as a component of the User Key. -Cannot be combined with the -.Fl j -option. -.It Fl r -Attach read-only provider. -It will not be opened for writing. -.El -.It Cm detach -Detach the given providers, which means remove the devfs entry -and clear the Master Key and Data Keys from memory. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Force detach - detach even if the provider is open. -.It Fl l -Mark provider to detach on last close. -If this option is specified, the provider will not be detached -while it is open, but will be automatically detached when it is closed for the -last time even if it was only opened for reading. -.El -.It Cm onetime -Attach the given providers with a random, one-time (ephemeral) Master Key. -The command can be used to encrypt swap partitions or temporary file systems. -.Pp -Additional options include: -.Bl -tag -width ".Fl a Ar sectorsize" -.It Fl a Ar aalgo -Enable data integrity verification (authentication). -For more information, see the description of the -.Cm init -subcommand. -.It Fl e Ar ealgo -Encryption algorithm to use. -For more information, see the description of the -.Cm init -subcommand. -.It Fl d -Detach on last close. -Note: this option is not usable for temporary file systems as the provider will -be detached after creating the file system on it. -It still can (and should be) used for swap partitions. -For more information, see the description of the -.Cm attach -subcommand. -.It Fl l Ar keylen -Data Key length to use with the given cryptographic algorithm. -For more information, see the description of the -.Cm init -subcommand. -.It Fl s Ar sectorsize -Change decrypted provider's sector size. -For more information, see the description of the -.Cm init -subcommand. -.It Fl T -Disable TRIM/UNMAP passthru. -For more information, see the description of the -.Cm init -subcommand. -.El -.It Cm configure -Change configuration of the given providers. -.Pp -Additional options include: -.Bl -tag -width ".Fl b" -.It Fl b -Set the BOOT flag on the given providers. -For more information, see the description of the -.Cm init -subcommand. -.It Fl B -Remove the BOOT flag from the given providers. -.It Fl d -When entering the passphrase to boot from this encrypted root filesystem, echo -.Ql * -characters. -This makes the length of the passphrase visible. -.It Fl D -Disable echoing of any characters when a passphrase is entered to boot from this -encrypted root filesystem. -This hides the passphrase length. -.It Fl g -Enable booting from this encrypted root filesystem. -The boot loader prompts for the passphrase and loads -.Xr loader 8 -from the encrypted partition. -.It Fl G -Deactivate booting from this encrypted root partition. -.It Fl t -Enable TRIM/UNMAP passthru. -For more information, see the description of the -.Cm init -subcommand. -.It Fl T -Disable TRIM/UNMAP passthru. -.El -.It Cm setkey -Install a copy of the Master Key into the selected slot, encrypted with -a new User Key. -If the selected slot is populated, replace the existing copy. -A provider has one Master Key, which can be stored in one or both slots, -each encrypted with an independent User Key. -With the -.Cm init -subcommand, only key number 0 is initialized. -The User Key can be changed at any time: for an attached provider, -for a detached provider, or on the backup file. -When a provider is attached, the user does not have to provide -an existing passphrase/keyfile. -.Pp -Additional options include: -.Bl -tag -width ".Fl J Ar newpassfile" -.It Fl i Ar iterations -Number of iterations to use with PKCS#5v2. -If 0 is given, PKCS#5v2 will not be used. -To be able to use this option with the -.Cm setkey -subcommand, only one key has to be defined and this key must be changed. -.It Fl j Ar passfile -Specifies a file which contains the passphrase component of a current User Key -(or part of it). -.It Fl J Ar newpassfile -Specifies a file which contains the passphrase component of the new User Key -(or part of it). -.It Fl k Ar keyfile -Specifies a file which contains the keyfile component of a current User Key -(or part of it). -.It Fl K Ar newkeyfile -Specifies a file which contains the keyfile component of the new User Key -(or part of it). -.It Fl n Ar keyno -Specifies the index number of the Master Key copy to change (could be 0 or 1). -If the provider is attached and no key number is given, the key -used for attaching the provider will be changed. -If the provider is detached (or we are operating on a backup file) -and no key number is given, the first Master Key copy to be successfully -decrypted with the provided User Key passphrase/keyfile will be changed. -.It Fl p -Do not use a passphrase as a component of the current User Key. -Cannot be combined with the -.Fl j -option. -.It Fl P -Do not use a passphrase as a component of the new User Key. -Cannot be combined with the -.Fl J -option. -.El -.It Cm delkey -Destroy (overwrite with random data) the selected Master Key copy. -If one is destroying keys for an attached provider, the provider -will not be detached even if all copies of the Master Key are destroyed. -It can even be rescued with the -.Cm setkey -subcommand because the Master Key is still in memory. -.Pp -Additional options include: -.Bl -tag -width ".Fl a Ar keyno" -.It Fl a -Destroy all copies of the Master Key (does not need -.Fl f -option). -.It Fl f -Force key destruction. -This option is needed to destroy the last copy of the Master Key. -.It Fl n Ar keyno -Specifies the index number of the Master Key copy. -If the provider is attached and no key number is given, the key -used for attaching the provider will be destroyed. -If provider is detached (or we are operating on a backup file) the key number -has to be given. -.El -.It Cm kill -This command should be used only in emergency situations. -It will destroy all copies of the Master Key on a given provider and will -detach it forcibly (if it is attached). -This is absolutely a one-way command - if you do not have a metadata -backup, your data is gone for good. -In case the provider was attached with the -.Fl r -flag, the keys will not be destroyed, only the provider will be detached. -.Pp -Additional options include: -.Bl -tag -width ".Fl a" -.It Fl a -If specified, all currently attached providers will be killed. -.El -.It Cm backup -Backup metadata from the given provider to the given file. -.It Cm restore -Restore metadata from the given file to the given provider. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Metadata contains the size of the provider to ensure that the correct -partition or slice is attached. -If an attempt is made to restore metadata to a provider that has a different -size, -.Nm -will refuse to restore the data unless the -.Fl f -switch is used. -If the partition or slice has been grown, the -.Cm resize -subcommand should be used rather than attempting to relocate the metadata -through -.Cm backup -and -.Cm restore . -.El -.It Cm suspend -Suspend device by waiting for all inflight requests to finish, clearing all -sensitive information (like the Master Key and Data Keys) from kernel memory, -and blocking all further I/O requests until the -.Cm resume -subcommand is executed. -This functionality is useful for laptops: when one wants to suspend a -laptop, one does not want to leave an encrypted device attached. -Instead of closing all files and directories opened from a file system located -on an encrypted device, unmounting the file system, and detaching the device, -the -.Cm suspend -subcommand can be used. -Any access to the encrypted device will be blocked until the Master Key is -reloaded through the -.Cm resume -subcommand. -Thus there is no need to close nor unmount anything. -The -.Cm suspend -subcommand does not work with devices created with the -.Cm onetime -subcommand. -Please note that sensitive data might still be present in memory after -suspending an encrypted device due to the file system cache, etc. -.Pp -Additional options include: -.Bl -tag -width ".Fl a" -.It Fl a -Suspend all -.Nm -devices. -.El -.It Cm resume -Resume previously suspended device. -The caller must ensure that executing this subcommand does not access the -suspended device, leading to a deadlock. -For example suspending a device which contains the file system where the -.Nm -utility is stored is bad idea. -.Pp -Additional options include: -.Bl -tag -width ".Fl j Ar passfile" -.It Fl j Ar passfile -Specifies a file which contains the passphrase component of the User Key -(or part of it). -For more information see the description of the -.Fl J -option for the -.Cm init -subcommand. -.It Fl k Ar keyfile -Specifies a file which contains the keyfile component of the User Key -(or part of it). -For more information see the description of the -.Fl K -option for the -.Cm init -subcommand. -.It Fl p -Do not use a passphrase as a component of the User Key. -Cannot be combined with the -.Fl j -option. -.El -.It Cm resize -Inform -.Nm -that the provider has been resized. -The old metadata block is relocated to the correct position at the end of the -provider and the provider size is updated. -.Pp -Additional options include: -.Bl -tag -width ".Fl s Ar oldsize" -.It Fl s Ar oldsize -The size of the provider before it was resized. -.El -.It Cm version -If no arguments are given, the -.Cm version -subcommand will print the version of -.Nm -userland utility as well as the version of the -.Nm ELI -GEOM class. -.Pp -If GEOM providers are specified, the -.Cm version -subcommand will print metadata version used by each of them. -.It Cm clear -Clear metadata from the given providers. -.Em WARNING : -This will erase with zeros the encrypted Master Key copies stored in the -metadata. -.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 KEY SUMMARY -.Ss Master Key -Upon -.Cm init , -the -.Nm -utility generates a random Master Key for the provider. -The Master Key never changes during the lifetime of the provider. -Each copy of the provider metadata, active or backed up to a file, can store -up to two, independently-encrypted copies of the Master Key. -.Ss User Key -Each stored copy of the Master Key is encrypted with a User Key, which -is generated by the -.Nm -utility from a passphrase and/or a keyfile. -The -.Nm -utility first reads all parts of the keyfile in the order specified on the -command line, then reads all parts of the stored passphrase in the order -specified on the command line. -If no passphrase parts are specified, the system prompts the user to enter -the passphrase. -The passphrase is optionally strengthened by PKCS#5v2. -The User Key is a digest computed over the concatenated keyfile and passphrase. -.Ss Data Key -During operation, one or more Data Keys are deterministically derived by -the kernel from the Master Key and cached in memory. -The number of Data Keys used by a given provider, and the way they are -derived, depend on the GELI version and whether the provider is configured to -use data authentication. -.Sh SYSCTL VARIABLES -The following -.Xr sysctl 8 -variables can be used to control the behavior of the -.Nm ELI -GEOM class. -The default value is shown next to each variable. -Some variables can also be set in -.Pa /boot/loader.conf . -.Bl -tag -width indent -.It Va kern.geom.eli.version -Version number of the -.Nm ELI -GEOM class. -.It Va kern.geom.eli.debug : No 0 -Debug level of the -.Nm ELI -GEOM class. -This can be set to a number between 0 and 3 inclusive. -If set to 0, minimal debug information is printed. -If set to 3, the -maximum amount of debug information is printed. -.It Va kern.geom.eli.tries : No 3 -Number of times a user is asked for the passphrase. -This is only used for providers which are attached on boot -(before the root file system is mounted). -If set to 0, attaching providers on boot will be disabled. -This variable should be set in -.Pa /boot/loader.conf . -.It Va kern.geom.eli.overwrites : No 5 -Specifies how many times the Master Key will be overwritten -with random values when it is destroyed. -After this operation it is filled with zeros. -.It Va kern.geom.eli.visible_passphrase : No 0 -If set to 1, the passphrase entered on boot (before the root -file system is mounted) will be visible. -This alternative should be used with caution as the entered -passphrase can be logged and exposed via -.Xr dmesg 8 . -This variable should be set in -.Pa /boot/loader.conf . -.It Va kern.geom.eli.threads : No 0 -Specifies how many kernel threads should be used for doing software -cryptography. -Its purpose is to increase performance on SMP systems. -If set to 0, a CPU-pinned thread will be started for every active CPU. -.It Va kern.geom.eli.batch : No 0 -When set to 1, can speed-up crypto operations by using batching. -Batching reduces the number of interrupts by responding to a group of -crypto requests with one interrupt. -The crypto card and the driver has to support this feature. -.It Va kern.geom.eli.key_cache_limit : No 8192 -Specifies how many Data Keys to cache. -The default limit -(8192 keys) will allow caching of all keys for a 4TB provider with 512 byte -sectors and will take around 1MB of memory. -.It Va kern.geom.eli.key_cache_hits -Reports how many times we were looking up a Data Key and it was already in -cache. -This sysctl is not updated for providers that need fewer Data Keys than -the limit specified in -.Va kern.geom.eli.key_cache_limit . -.It Va kern.geom.eli.key_cache_misses -Reports how many times we were looking up a Data Key and it was not in cache. -This sysctl is not updated for providers that need fewer Data Keys than the limit -specified in -.Va kern.geom.eli.key_cache_limit . -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -Initialize a provider which is going to be encrypted with a -passphrase and random data from a file on the user's pen drive. -Use 4kB sector size. -Attach the provider, create a file system, and mount it. -Do the work. -Unmount the provider and detach it: -.Bd -literal -offset indent -# dd if=/dev/random of=/mnt/pendrive/da2.key bs=64 count=1 -# geli init -s 4096 -K /mnt/pendrive/da2.key /dev/da2 -Enter new passphrase: -Reenter new passphrase: -# geli attach -k /mnt/pendrive/da2.key /dev/da2 -Enter passphrase: -# dd if=/dev/random of=/dev/da2.eli bs=1m -# newfs /dev/da2.eli -# mount /dev/da2.eli /mnt/secret -\&... -# umount /mnt/secret -# geli detach da2.eli -.Ed -.Pp -Create an encrypted provider, but use two User Keys: -one for your employee and one for you as the company's security officer -(so it is not a tragedy if the employee -.Qq accidentally -forgets his passphrase): -.Bd -literal -offset indent -# geli init /dev/da2 -Enter new passphrase: (enter security officer's passphrase) -Reenter new passphrase: -# geli setkey -n 1 /dev/da2 -Enter passphrase: (enter security officer's passphrase) -Enter new passphrase: (let your employee enter his passphrase ...) -Reenter new passphrase: (... twice) -.Ed -.Pp -You are the security officer in your company. -Create an encrypted provider for use by the user, but remember that users -forget their passphrases, so backup the Master Key with your own random key: -.Bd -literal -offset indent -# dd if=/dev/random of=/mnt/pendrive/keys/`hostname` bs=64 count=1 -# geli init -P -K /mnt/pendrive/keys/`hostname` /dev/ada0s1e -# geli backup /dev/ada0s1e /mnt/pendrive/backups/`hostname` -(use key number 0, so the encrypted Master Key will be re-encrypted by this) -# geli setkey -n 0 -k /mnt/pendrive/keys/`hostname` /dev/ada0s1e -(allow the user to enter his passphrase) -Enter new passphrase: -Reenter new passphrase: -.Ed -.Pp -Encrypted swap partition setup: -.Bd -literal -offset indent -# dd if=/dev/random of=/dev/ada0s1b bs=1m -# geli onetime -d -e 3des ada0s1b -# swapon /dev/ada0s1b.eli -.Ed -.Pp -The example below shows how to configure two providers which will be attached -on boot (before the root file system is mounted). -One of them is using passphrase and three keyfile parts and the other is -using only a keyfile in one part: -.Bd -literal -offset indent -# dd if=/dev/random of=/dev/da0 bs=1m -# dd if=/dev/random of=/boot/keys/da0.key0 bs=32k count=1 -# dd if=/dev/random of=/boot/keys/da0.key1 bs=32k count=1 -# dd if=/dev/random of=/boot/keys/da0.key2 bs=32k count=1 -# geli init -b -K /boot/keys/da0.key0 -K /boot/keys/da0.key1 -K /boot/keys/da0.key2 da0 -Enter new passphrase: -Reenter new passphrase: -# dd if=/dev/random of=/dev/da1s3a bs=1m -# dd if=/dev/random of=/boot/keys/da1s3a.key bs=128k count=1 -# geli init -b -P -K /boot/keys/da1s3a.key da1s3a -.Ed -.Pp -The providers are initialized, now we have to add these lines to -.Pa /boot/loader.conf : -.Bd -literal -offset indent -geli_da0_keyfile0_load="YES" -geli_da0_keyfile0_type="da0:geli_keyfile0" -geli_da0_keyfile0_name="/boot/keys/da0.key0" -geli_da0_keyfile1_load="YES" -geli_da0_keyfile1_type="da0:geli_keyfile1" -geli_da0_keyfile1_name="/boot/keys/da0.key1" -geli_da0_keyfile2_load="YES" -geli_da0_keyfile2_type="da0:geli_keyfile2" -geli_da0_keyfile2_name="/boot/keys/da0.key2" - -geli_da1s3a_keyfile0_load="YES" -geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0" -geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key" -.Ed -.Pp -If there is only one keyfile, the index might be omitted: -.Bd -literal -offset indent -geli_da1s3a_keyfile_load="YES" -geli_da1s3a_keyfile_type="da1s3a:geli_keyfile" -geli_da1s3a_keyfile_name="/boot/keys/da1s3a.key" -.Ed -.Pp -Not only configure encryption, but also data integrity verification using -.Nm HMAC/SHA256 . -.Bd -literal -offset indent -# geli init -a hmac/sha256 -s 4096 /dev/da0 -Enter new passphrase: -Reenter new passphrase: -# geli attach /dev/da0 -Enter passphrase: -# dd if=/dev/random of=/dev/da0.eli bs=1m -# newfs /dev/da0.eli -# mount /dev/da0.eli /mnt/secret -.Ed -.Pp -.Cm geli -writes the metadata backup by default to the -.Pa /var/backups/.eli -file. -If the metadata is lost in any way (e.g., by accidental overwrite), it can be restored. -Consider the following situation: -.Bd -literal -offset indent -# geli init /dev/da0 -Enter new passphrase: -Reenter new passphrase: - -Metadata backup can be found in /var/backups/da0.eli and -can be restored with the following command: - - # geli restore /var/backups/da0.eli /dev/da0 - -# geli clear /dev/da0 -# geli attach /dev/da0 -geli: Cannot read metadata from /dev/da0: Invalid argument. -# geli restore /var/backups/da0.eli /dev/da0 -# geli attach /dev/da0 -Enter passphrase: -.Ed -.Pp -If an encrypted file system is extended, it is necessary to relocate and -update the metadata: -.Bd -literal -offset indent -# gpart create -s GPT ada0 -# gpart add -s 1g -t freebsd-ufs -i 1 ada0 -# geli init -K keyfile -P ada0p1 -# gpart resize -s 2g -i 1 ada0 -# geli resize -s 1g ada0p1 -# geli attach -k keyfile -p ada0p1 -.Ed -.Pp -Initialize provider with the passphrase split into two files. -The provider can be attached using those two files or by entering -.Dq foobar -as the passphrase at the -.Nm -prompt: -.Bd -literal -offset indent -# echo foo > da0.pass0 -# echo bar > da0.pass1 -# geli init -J da0.pass0 -J da0.pass1 da0 -# geli attach -j da0.pass0 -j da0.pass1 da0 -# geli detach da0 -# geli attach da0 -Enter passphrase: foobar -.Ed -.Pp -Suspend all -.Nm -devices on a laptop, suspend the laptop, then resume devices one by one after -resuming the laptop: -.Bd -literal -offset indent -# geli suspend -a -# zzz - -# geli resume -p -k keyfile gpt/secret -# geli resume gpt/private -Enter passphrase: -.Ed -.Sh ENCRYPTION MODES -.Nm -supports two encryption modes: -.Nm XTS , -which was standardized as -.Nm IEEE P1619 -and -.Nm CBC -with unpredictable IV. -The -.Nm CBC -mode used by -.Nm -is very similar to the mode -.Nm ESSIV . -.Sh DATA AUTHENTICATION -.Nm -can verify data integrity when an authentication algorithm is specified. -When data corruption/modification is detected, -.Nm -will not return any data, but instead will return an error -.Pq Er EINVAL . -The offset and size of the corrupted data will be printed on the console. -It is important to know against which attacks -.Nm -provides protection for your data. -If data is modified in-place or copied from one place on the disk -to another even without modification, -.Nm -should be able to detect such a change. -If an attacker can remember the encrypted data, he can overwrite any future -changes with the data he owns without it being noticed. -In other words -.Nm -will not protect your data against replay attacks. -.Pp -It is recommended to write to the whole provider before first use, -in order to make sure that all sectors and their corresponding -checksums are properly initialized into a consistent state. -One can safely ignore data authentication errors that occur immediately -after the first time a provider is attached and before it is -initialized in this way. -.Sh SEE ALSO -.Xr crypto 4 , -.Xr gbde 4 , -.Xr geom 4 , -.Xr loader.conf 5 , -.Xr gbde 8 , -.Xr geom 8 , -.Xr crypto 9 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 6.0 . -Support for the -.Nm Camellia -block cipher is implemented by Yoshisato Yanagisawa in -.Fx 7.0 . -.Pp -Highest -.Nm GELI -metadata version supported by the given FreeBSD version: -.Bl -column -offset indent ".Sy FreeBSD" ".Sy version" -.It Sy FreeBSD Ta Sy GELI -.It Sy version Ta Sy version -.Pp -.It Li 6.0 Ta 0 -.It Li 6.1 Ta 0 -.It Li 6.2 Ta 3 -.It Li 6.3 Ta 3 -.It Li 6.4 Ta 3 -.Pp -.It Li 7.0 Ta 3 -.It Li 7.1 Ta 3 -.It Li 7.2 Ta 3 -.It Li 7.3 Ta 3 -.It Li 7.4 Ta 3 -.Pp -.It Li 8.0 Ta 3 -.It Li 8.1 Ta 3 -.It Li 8.2 Ta 5 -.Pp -.It Li 9.0 Ta 6 -.Pp -.It Li 10.0 Ta 7 -.El -.Sh AUTHORS -.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org Index: sbin/geom/class/eli/geom_eli.c =================================================================== --- /dev/null +++ sbin/geom/class/eli/geom_eli.c @@ -1,1768 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2010 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_ELI_VERSION; - -#define GELI_BACKUP_DIR "/var/backups/" -#define GELI_ENC_ALGO "aes" - -static void eli_main(struct gctl_req *req, unsigned flags); -static void eli_init(struct gctl_req *req); -static void eli_attach(struct gctl_req *req); -static void eli_configure(struct gctl_req *req); -static void eli_setkey(struct gctl_req *req); -static void eli_delkey(struct gctl_req *req); -static void eli_resume(struct gctl_req *req); -static void eli_kill(struct gctl_req *req); -static void eli_backup(struct gctl_req *req); -static void eli_restore(struct gctl_req *req); -static void eli_resize(struct gctl_req *req); -static void eli_version(struct gctl_req *req); -static void eli_clear(struct gctl_req *req); -static void eli_dump(struct gctl_req *req); - -static int eli_backup_create(struct gctl_req *req, const char *prov, - const char *file); - -/* - * Available commands: - * - * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov - * label - alias for 'init' - * attach [-dprv] [-j passfile] [-k keyfile] prov - * detach [-fl] prov ... - * stop - alias for 'detach' - * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov - * configure [-bBgGtT] prov ... - * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov - * delkey [-afv] [-n keyno] prov - * suspend [-v] -a | prov ... - * resume [-pv] [-j passfile] [-k keyfile] prov - * kill [-av] [prov ...] - * backup [-v] prov file - * restore [-fv] file prov - * resize [-v] -s oldsize prov - * version [prov ...] - * clear [-v] prov ... - * dump [-v] prov ... - */ -struct g_command class_commands[] = { - { "init", G_FLAG_VERBOSE, eli_main, - { - { 'a', "aalgo", "", G_TYPE_STRING }, - { 'b', "boot", NULL, G_TYPE_BOOL }, - { 'B', "backupfile", "", G_TYPE_STRING }, - { 'd', "displaypass", NULL, G_TYPE_BOOL }, - { 'e', "ealgo", "", G_TYPE_STRING }, - { 'g', "geliboot", NULL, G_TYPE_BOOL }, - { 'i', "iterations", "-1", G_TYPE_NUMBER }, - { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'l', "keylen", "0", G_TYPE_NUMBER }, - { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, - { 's', "sectorsize", "0", G_TYPE_NUMBER }, - { 'T', "notrim", NULL, G_TYPE_BOOL }, - { 'V', "mdversion", "-1", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov" - }, - { "label", G_FLAG_VERBOSE, eli_main, - { - { 'a', "aalgo", "", G_TYPE_STRING }, - { 'b', "boot", NULL, G_TYPE_BOOL }, - { 'B', "backupfile", "", G_TYPE_STRING }, - { 'd', "displaypass", NULL, G_TYPE_BOOL }, - { 'e', "ealgo", "", G_TYPE_STRING }, - { 'g', "geliboot", NULL, G_TYPE_BOOL }, - { 'i', "iterations", "-1", G_TYPE_NUMBER }, - { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'l', "keylen", "0", G_TYPE_NUMBER }, - { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, - { 's', "sectorsize", "0", G_TYPE_NUMBER }, - { 'V', "mdversion", "-1", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "- an alias for 'init'" - }, - { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, - { - { 'd', "detach", NULL, G_TYPE_BOOL }, - { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'n', "dryrun", NULL, G_TYPE_BOOL }, - { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, - { 'r', "readonly", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-dnprv] [-j passfile] [-k keyfile] prov" - }, - { "detach", 0, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'l', "last", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fl] prov ..." - }, - { "stop", 0, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'l', "last", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "- an alias for 'detach'" - }, - { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - { 'a', "aalgo", "", G_TYPE_STRING }, - { 'd', "detach", NULL, G_TYPE_BOOL }, - { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, - { 'l', "keylen", "0", G_TYPE_NUMBER }, - { 's', "sectorsize", "0", G_TYPE_NUMBER }, - { 'T', "notrim", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-dT] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" - }, - { "configure", G_FLAG_VERBOSE, eli_main, - { - { 'b', "boot", NULL, G_TYPE_BOOL }, - { 'B', "noboot", NULL, G_TYPE_BOOL }, - { 'd', "displaypass", NULL, G_TYPE_BOOL }, - { 'D', "nodisplaypass", NULL, G_TYPE_BOOL }, - { 'g', "geliboot", NULL, G_TYPE_BOOL }, - { 'G', "nogeliboot", NULL, G_TYPE_BOOL }, - { 't', "trim", NULL, G_TYPE_BOOL }, - { 'T', "notrim", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-bBdDgGtT] prov ..." - }, - { "setkey", G_FLAG_VERBOSE, eli_main, - { - { 'i', "iterations", "-1", G_TYPE_NUMBER }, - { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'n', "keyno", "-1", G_TYPE_NUMBER }, - { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, - { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov" - }, - { "delkey", G_FLAG_VERBOSE, eli_main, - { - { 'a', "all", NULL, G_TYPE_BOOL }, - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'n', "keyno", "-1", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-afv] [-n keyno] prov" - }, - { "suspend", G_FLAG_VERBOSE, NULL, - { - { 'a', "all", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-v] -a | prov ..." - }, - { "resume", G_FLAG_VERBOSE, eli_main, - { - { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, - { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-pv] [-j passfile] [-k keyfile] prov" - }, - { "kill", G_FLAG_VERBOSE, eli_main, - { - { 'a', "all", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-av] [prov ...]" - }, - { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, - "[-v] prov file" - }, - { "restore", G_FLAG_VERBOSE, eli_main, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] file prov" - }, - { "resize", G_FLAG_VERBOSE, eli_main, - { - { 's', "oldsize", NULL, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] -s oldsize prov" - }, - { "version", G_FLAG_LOADKLD, eli_main, G_NULL_OPTS, - "[prov ...]" - }, - { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, - "[-v] prov ..." - }, - G_CMD_SENTINEL -}; - -static int verbose = 0; - -#define BUFSIZE 1024 - -static int -eli_protect(struct gctl_req *req) -{ - struct rlimit rl; - - /* Disable core dumps. */ - rl.rlim_cur = 0; - rl.rlim_max = 0; - if (setrlimit(RLIMIT_CORE, &rl) == -1) { - gctl_error(req, "Cannot disable core dumps: %s.", - strerror(errno)); - return (-1); - } - /* Disable swapping. */ - if (mlockall(MCL_FUTURE) == -1) { - gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); - return (-1); - } - return (0); -} - -static void -eli_main(struct gctl_req *req, unsigned int flags) -{ - const char *name; - - if (eli_protect(req) == -1) - return; - - 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, "init") == 0 || strcmp(name, "label") == 0) - eli_init(req); - else if (strcmp(name, "attach") == 0) - eli_attach(req); - else if (strcmp(name, "configure") == 0) - eli_configure(req); - else if (strcmp(name, "setkey") == 0) - eli_setkey(req); - else if (strcmp(name, "delkey") == 0) - eli_delkey(req); - else if (strcmp(name, "resume") == 0) - eli_resume(req); - else if (strcmp(name, "kill") == 0) - eli_kill(req); - else if (strcmp(name, "backup") == 0) - eli_backup(req); - else if (strcmp(name, "restore") == 0) - eli_restore(req); - else if (strcmp(name, "resize") == 0) - eli_resize(req); - else if (strcmp(name, "version") == 0) - eli_version(req); - else if (strcmp(name, "dump") == 0) - eli_dump(req); - else if (strcmp(name, "clear") == 0) - eli_clear(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static bool -eli_is_attached(const char *prov) -{ - char name[MAXPATHLEN]; - - /* - * Not the best way to do it, but the easiest. - * We try to open provider and check if it is a GEOM provider - * by asking about its sectorsize. - */ - snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); - return (g_get_sectorsize(name) > 0); -} - -static int -eli_genkey_files(struct gctl_req *req, bool new, const char *type, - struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize) -{ - char *p, buf[BUFSIZE], argname[16]; - const char *file; - int error, fd, i; - ssize_t done; - - assert((strcmp(type, "keyfile") == 0 && ctxp != NULL && - passbuf == NULL && passbufsize == 0) || - (strcmp(type, "passfile") == 0 && ctxp == NULL && - passbuf != NULL && passbufsize > 0)); - assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0'); - - for (i = 0; ; i++) { - snprintf(argname, sizeof(argname), "%s%s%d", - new ? "new" : "", type, i); - - /* No more {key,pass}files? */ - if (!gctl_has_param(req, argname)) - return (i); - - file = gctl_get_ascii(req, "%s", argname); - assert(file != NULL); - - if (strcmp(file, "-") == 0) - fd = STDIN_FILENO; - else { - fd = open(file, O_RDONLY); - if (fd == -1) { - gctl_error(req, "Cannot open %s %s: %s.", - type, file, strerror(errno)); - return (-1); - } - } - if (strcmp(type, "keyfile") == 0) { - while ((done = read(fd, buf, sizeof(buf))) > 0) - g_eli_crypto_hmac_update(ctxp, buf, done); - } else /* if (strcmp(type, "passfile") == 0) */ { - assert(strcmp(type, "passfile") == 0); - - while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) { - buf[done] = '\0'; - p = strchr(buf, '\n'); - if (p != NULL) { - *p = '\0'; - done = p - buf; - } - if (strlcat(passbuf, buf, passbufsize) >= - passbufsize) { - gctl_error(req, - "Passphrase in %s too long.", file); - bzero(buf, sizeof(buf)); - return (-1); - } - if (p != NULL) - break; - } - } - error = errno; - if (strcmp(file, "-") != 0) - close(fd); - bzero(buf, sizeof(buf)); - if (done == -1) { - gctl_error(req, "Cannot read %s %s: %s.", - type, file, strerror(error)); - return (-1); - } - } - /* NOTREACHED */ -} - -static int -eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf, - size_t passbufsize) -{ - char *p; - - for (;;) { - p = readpassphrase( - new ? "Enter new passphrase: " : "Enter passphrase: ", - passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY); - if (p == NULL) { - bzero(passbuf, passbufsize); - gctl_error(req, "Cannot read passphrase: %s.", - strerror(errno)); - return (-1); - } - - if (new) { - char tmpbuf[BUFSIZE]; - - p = readpassphrase("Reenter new passphrase: ", - tmpbuf, sizeof(tmpbuf), - RPP_ECHO_OFF | RPP_REQUIRE_TTY); - if (p == NULL) { - bzero(passbuf, passbufsize); - gctl_error(req, - "Cannot read passphrase: %s.", - strerror(errno)); - return (-1); - } - - if (strcmp(passbuf, tmpbuf) != 0) { - bzero(passbuf, passbufsize); - fprintf(stderr, "They didn't match.\n"); - continue; - } - bzero(tmpbuf, sizeof(tmpbuf)); - } - return (0); - } - /* NOTREACHED */ -} - -static int -eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new, - struct hmac_ctx *ctxp) -{ - char passbuf[BUFSIZE]; - bool nopassphrase; - int nfiles; - - nopassphrase = - gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); - if (nopassphrase) { - if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) { - gctl_error(req, - "Options -%c and -%c are mutually exclusive.", - new ? 'J' : 'j', new ? 'P' : 'p'); - return (-1); - } - return (0); - } - - if (!new && md->md_iterations == -1) { - gctl_error(req, "Missing -p flag."); - return (-1); - } - passbuf[0] = '\0'; - nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf, - sizeof(passbuf)); - if (nfiles == -1) - return (-1); - else if (nfiles == 0) { - if (eli_genkey_passphrase_prompt(req, new, passbuf, - sizeof(passbuf)) == -1) { - return (-1); - } - } - /* - * Field md_iterations equal to -1 means "choose some sane - * value for me". - */ - if (md->md_iterations == -1) { - assert(new); - if (verbose) - printf("Calculating number of iterations...\n"); - md->md_iterations = pkcs5v2_calculate(2000000); - assert(md->md_iterations > 0); - if (verbose) { - printf("Done, using %d iterations.\n", - md->md_iterations); - } - } - /* - * If md_iterations is equal to 0, user doesn't want PKCS#5v2. - */ - if (md->md_iterations == 0) { - g_eli_crypto_hmac_update(ctxp, md->md_salt, - sizeof(md->md_salt)); - g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf)); - } else /* if (md->md_iterations > 0) */ { - unsigned char dkey[G_ELI_USERKEYLEN]; - - pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, - sizeof(md->md_salt), passbuf, md->md_iterations); - g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey)); - bzero(dkey, sizeof(dkey)); - } - bzero(passbuf, sizeof(passbuf)); - - return (0); -} - -static unsigned char * -eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, - bool new) -{ - struct hmac_ctx ctx; - bool nopassphrase; - int nfiles; - - nopassphrase = - gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); - - g_eli_crypto_hmac_init(&ctx, NULL, 0); - - nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0); - if (nfiles == -1) - return (NULL); - else if (nfiles == 0 && nopassphrase) { - gctl_error(req, "No key components given."); - return (NULL); - } - - if (eli_genkey_passphrase(req, md, new, &ctx) == -1) - return (NULL); - - g_eli_crypto_hmac_final(&ctx, key, 0); - - return (key); -} - -static int -eli_metadata_read(struct gctl_req *req, const char *prov, - struct g_eli_metadata *md) -{ - unsigned char sector[sizeof(struct g_eli_metadata)]; - int error; - - if (g_get_sectorsize(prov) == 0) { - int fd; - - /* This is a file probably. */ - fd = open(prov, O_RDONLY); - if (fd == -1) { - gctl_error(req, "Cannot open %s: %s.", prov, - strerror(errno)); - return (-1); - } - if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { - gctl_error(req, "Cannot read metadata from %s: %s.", - prov, strerror(errno)); - close(fd); - return (-1); - } - close(fd); - } else { - /* This is a GEOM provider. */ - error = g_metadata_read(prov, sector, sizeof(sector), - G_ELI_MAGIC); - if (error != 0) { - gctl_error(req, "Cannot read metadata from %s: %s.", - prov, strerror(error)); - return (-1); - } - } - error = eli_metadata_decode(sector, md); - switch (error) { - case 0: - break; - case EOPNOTSUPP: - gctl_error(req, - "Provider's %s metadata version %u is too new.\n" - "geli: The highest supported version is %u.", - prov, (unsigned int)md->md_version, G_ELI_VERSION); - return (-1); - case EINVAL: - gctl_error(req, "Inconsistent provider's %s metadata.", prov); - return (-1); - default: - gctl_error(req, - "Unexpected error while decoding provider's %s metadata: %s.", - prov, strerror(error)); - return (-1); - } - return (0); -} - -static int -eli_metadata_store(struct gctl_req *req, const char *prov, - struct g_eli_metadata *md) -{ - unsigned char sector[sizeof(struct g_eli_metadata)]; - int error; - - eli_metadata_encode(md, sector); - if (g_get_sectorsize(prov) == 0) { - int fd; - - /* This is a file probably. */ - fd = open(prov, O_WRONLY | O_TRUNC); - if (fd == -1) { - gctl_error(req, "Cannot open %s: %s.", prov, - strerror(errno)); - bzero(sector, sizeof(sector)); - return (-1); - } - if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { - gctl_error(req, "Cannot write metadata to %s: %s.", - prov, strerror(errno)); - bzero(sector, sizeof(sector)); - close(fd); - return (-1); - } - close(fd); - } else { - /* This is a GEOM provider. */ - error = g_metadata_store(prov, sector, sizeof(sector)); - if (error != 0) { - gctl_error(req, "Cannot write metadata to %s: %s.", - prov, strerror(errno)); - bzero(sector, sizeof(sector)); - return (-1); - } - } - bzero(sector, sizeof(sector)); - return (0); -} - -static void -eli_init(struct gctl_req *req) -{ - struct g_eli_metadata md; - unsigned char sector[sizeof(struct g_eli_metadata)] __aligned(4); - unsigned char key[G_ELI_USERKEYLEN]; - char backfile[MAXPATHLEN]; - const char *str, *prov; - unsigned int secsize, version; - off_t mediasize; - intmax_t val; - int error, nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - mediasize = g_get_mediasize(prov); - secsize = g_get_sectorsize(prov); - if (mediasize == 0 || secsize == 0) { - gctl_error(req, "Cannot get informations about %s: %s.", prov, - strerror(errno)); - return; - } - - bzero(&md, sizeof(md)); - strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); - val = gctl_get_intmax(req, "mdversion"); - if (val == -1) { - version = G_ELI_VERSION; - } else if (val < 0 || val > G_ELI_VERSION) { - gctl_error(req, - "Invalid version specified should be between %u and %u.", - G_ELI_VERSION_00, G_ELI_VERSION); - return; - } else { - version = val; - } - md.md_version = version; - md.md_flags = 0; - if (gctl_get_int(req, "boot")) - md.md_flags |= G_ELI_FLAG_BOOT; - if (gctl_get_int(req, "geliboot")) - md.md_flags |= G_ELI_FLAG_GELIBOOT; - if (gctl_get_int(req, "displaypass")) - md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS; - if (gctl_get_int(req, "notrim")) - md.md_flags |= G_ELI_FLAG_NODELETE; - md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; - str = gctl_get_ascii(req, "aalgo"); - if (*str != '\0') { - if (version < G_ELI_VERSION_01) { - gctl_error(req, - "Data authentication is supported starting from version %u.", - G_ELI_VERSION_01); - return; - } - md.md_aalgo = g_eli_str2aalgo(str); - if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && - md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { - md.md_flags |= G_ELI_FLAG_AUTH; - } else { - /* - * For backward compatibility, check if the -a option - * was used to provide encryption algorithm. - */ - md.md_ealgo = g_eli_str2ealgo(str); - if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || - md.md_ealgo > CRYPTO_ALGORITHM_MAX) { - gctl_error(req, - "Invalid authentication algorithm."); - return; - } else { - fprintf(stderr, "warning: The -e option, not " - "the -a option is now used to specify " - "encryption algorithm to use.\n"); - } - } - } - if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || - md.md_ealgo > CRYPTO_ALGORITHM_MAX) { - str = gctl_get_ascii(req, "ealgo"); - if (*str == '\0') { - if (version < G_ELI_VERSION_05) - str = "aes-cbc"; - else - str = GELI_ENC_ALGO; - } - md.md_ealgo = g_eli_str2ealgo(str); - if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || - md.md_ealgo > CRYPTO_ALGORITHM_MAX) { - gctl_error(req, "Invalid encryption algorithm."); - return; - } - if (md.md_ealgo == CRYPTO_CAMELLIA_CBC && - version < G_ELI_VERSION_04) { - gctl_error(req, - "Camellia-CBC algorithm is supported starting from version %u.", - G_ELI_VERSION_04); - return; - } - if (md.md_ealgo == CRYPTO_AES_XTS && - version < G_ELI_VERSION_05) { - gctl_error(req, - "AES-XTS algorithm is supported starting from version %u.", - G_ELI_VERSION_05); - return; - } - } - val = gctl_get_intmax(req, "keylen"); - md.md_keylen = val; - md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); - if (md.md_keylen == 0) { - gctl_error(req, "Invalid key length."); - return; - } - md.md_provsize = mediasize; - - val = gctl_get_intmax(req, "iterations"); - if (val != -1) { - int nonewpassphrase; - - /* - * Don't allow to set iterations when there will be no - * passphrase. - */ - nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); - if (nonewpassphrase) { - gctl_error(req, - "Options -i and -P are mutually exclusive."); - return; - } - } - md.md_iterations = val; - - val = gctl_get_intmax(req, "sectorsize"); - if (val == 0) - md.md_sectorsize = secsize; - else { - if (val < 0 || (val % secsize) != 0 || !powerof2(val)) { - gctl_error(req, "Invalid sector size."); - return; - } - if (val > sysconf(_SC_PAGE_SIZE)) { - fprintf(stderr, - "warning: Using sectorsize bigger than the page size!\n"); - } - md.md_sectorsize = val; - } - - md.md_keys = 0x01; - arc4random_buf(md.md_salt, sizeof(md.md_salt)); - arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); - - /* Generate user key. */ - if (eli_genkey(req, &md, key, true) == NULL) { - bzero(key, sizeof(key)); - bzero(&md, sizeof(md)); - return; - } - - /* Encrypt the first and the only Master Key. */ - error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); - bzero(key, sizeof(key)); - if (error != 0) { - bzero(&md, sizeof(md)); - gctl_error(req, "Cannot encrypt Master Key: %s.", - strerror(error)); - return; - } - - eli_metadata_encode(&md, sector); - bzero(&md, sizeof(md)); - error = g_metadata_store(prov, sector, sizeof(sector)); - bzero(sector, sizeof(sector)); - if (error != 0) { - gctl_error(req, "Cannot store metadata on %s: %s.", prov, - strerror(error)); - return; - } - if (verbose) - printf("Metadata value stored on %s.\n", prov); - /* Backup metadata to a file. */ - str = gctl_get_ascii(req, "backupfile"); - if (str[0] != '\0') { - /* Backupfile given be the user, just copy it. */ - strlcpy(backfile, str, sizeof(backfile)); - } else { - /* Generate file name automatically. */ - const char *p = prov; - unsigned int i; - - if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - p += sizeof(_PATH_DEV) - 1; - snprintf(backfile, sizeof(backfile), "%s%s.eli", - GELI_BACKUP_DIR, p); - /* Replace all / with _. */ - for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { - if (backfile[i] == '/') - backfile[i] = '_'; - } - } - if (strcmp(backfile, "none") != 0 && - eli_backup_create(req, prov, backfile) == 0) { - printf("\nMetadata backup can be found in %s and\n", backfile); - printf("can be restored with the following command:\n"); - printf("\n\t# geli restore %s %s\n\n", backfile, prov); - } -} - -static void -eli_attach(struct gctl_req *req) -{ - struct g_eli_metadata md; - unsigned char key[G_ELI_USERKEYLEN]; - const char *prov; - off_t mediasize; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - - if (eli_metadata_read(req, prov, &md) == -1) - return; - - mediasize = g_get_mediasize(prov); - if (md.md_provsize != (uint64_t)mediasize) { - gctl_error(req, "Provider size mismatch."); - return; - } - - if (eli_genkey(req, &md, key, false) == NULL) { - bzero(key, sizeof(key)); - return; - } - - gctl_ro_param(req, "key", sizeof(key), key); - if (gctl_issue(req) == NULL) { - if (verbose) - printf("Attached to %s.\n", prov); - } - bzero(key, sizeof(key)); -} - -static void -eli_configure_detached(struct gctl_req *req, const char *prov, int boot, - int geliboot, int displaypass, int trim) -{ - struct g_eli_metadata md; - bool changed = 0; - - if (eli_metadata_read(req, prov, &md) == -1) - return; - - if (boot == 1 && (md.md_flags & G_ELI_FLAG_BOOT)) { - if (verbose) - printf("BOOT flag already configured for %s.\n", prov); - } else if (boot == 0 && !(md.md_flags & G_ELI_FLAG_BOOT)) { - if (verbose) - printf("BOOT flag not configured for %s.\n", prov); - } else if (boot >= 0) { - if (boot) - md.md_flags |= G_ELI_FLAG_BOOT; - else - md.md_flags &= ~G_ELI_FLAG_BOOT; - changed = 1; - } - - if (geliboot == 1 && (md.md_flags & G_ELI_FLAG_GELIBOOT)) { - if (verbose) - printf("GELIBOOT flag already configured for %s.\n", prov); - } else if (geliboot == 0 && !(md.md_flags & G_ELI_FLAG_GELIBOOT)) { - if (verbose) - printf("GELIBOOT flag not configured for %s.\n", prov); - } else if (geliboot >= 0) { - if (geliboot) - md.md_flags |= G_ELI_FLAG_GELIBOOT; - else - md.md_flags &= ~G_ELI_FLAG_GELIBOOT; - changed = 1; - } - - if (displaypass == 1 && (md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) { - if (verbose) - printf("GELIDISPLAYPASS flag already configured for %s.\n", prov); - } else if (displaypass == 0 && - !(md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS)) { - if (verbose) - printf("GELIDISPLAYPASS flag not configured for %s.\n", prov); - } else if (displaypass >= 0) { - if (displaypass) - md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS; - else - md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS; - changed = 1; - } - - if (trim == 0 && (md.md_flags & G_ELI_FLAG_NODELETE)) { - if (verbose) - printf("TRIM disable flag already configured for %s.\n", prov); - } else if (trim == 1 && !(md.md_flags & G_ELI_FLAG_NODELETE)) { - if (verbose) - printf("TRIM disable flag not configured for %s.\n", prov); - } else if (trim >= 0) { - if (trim) - md.md_flags &= ~G_ELI_FLAG_NODELETE; - else - md.md_flags |= G_ELI_FLAG_NODELETE; - changed = 1; - } - - if (changed) - eli_metadata_store(req, prov, &md); - bzero(&md, sizeof(md)); -} - -static void -eli_configure(struct gctl_req *req) -{ - const char *prov; - bool boot, noboot, geliboot, nogeliboot, displaypass, nodisplaypass; - bool trim, notrim; - int doboot, dogeliboot, dodisplaypass, dotrim; - int i, nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs == 0) { - gctl_error(req, "Too few arguments."); - return; - } - - boot = gctl_get_int(req, "boot"); - noboot = gctl_get_int(req, "noboot"); - geliboot = gctl_get_int(req, "geliboot"); - nogeliboot = gctl_get_int(req, "nogeliboot"); - displaypass = gctl_get_int(req, "displaypass"); - nodisplaypass = gctl_get_int(req, "nodisplaypass"); - trim = gctl_get_int(req, "trim"); - notrim = gctl_get_int(req, "notrim"); - - doboot = -1; - if (boot && noboot) { - gctl_error(req, "Options -b and -B are mutually exclusive."); - return; - } - if (boot) - doboot = 1; - else if (noboot) - doboot = 0; - - dogeliboot = -1; - if (geliboot && nogeliboot) { - gctl_error(req, "Options -g and -G are mutually exclusive."); - return; - } - if (geliboot) - dogeliboot = 1; - else if (nogeliboot) - dogeliboot = 0; - - dodisplaypass = -1; - if (displaypass && nodisplaypass) { - gctl_error(req, "Options -d and -D are mutually exclusive."); - return; - } - if (displaypass) - dodisplaypass = 1; - else if (nodisplaypass) - dodisplaypass = 0; - - dotrim = -1; - if (trim && notrim) { - gctl_error(req, "Options -t and -T are mutually exclusive."); - return; - } - if (trim) - dotrim = 1; - else if (notrim) - dotrim = 0; - - if (doboot == -1 && dogeliboot == -1 && dodisplaypass == -1 && - dotrim == -1) { - gctl_error(req, "No option given."); - return; - } - - /* First attached providers. */ - gctl_issue(req); - /* Now the rest. */ - for (i = 0; i < nargs; i++) { - prov = gctl_get_ascii(req, "arg%d", i); - if (!eli_is_attached(prov)) { - eli_configure_detached(req, prov, doboot, dogeliboot, - dodisplaypass, dotrim); - } - } -} - -static void -eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) -{ - unsigned char key[G_ELI_USERKEYLEN]; - intmax_t val, old = 0; - int error; - - val = gctl_get_intmax(req, "iterations"); - /* Check if iterations number should be changed. */ - if (val != -1) - md->md_iterations = val; - else - old = md->md_iterations; - - /* Generate key for Master Key encryption. */ - if (eli_genkey(req, md, key, true) == NULL) { - bzero(key, sizeof(key)); - return; - } - /* - * If number of iterations has changed, but wasn't given as a - * command-line argument, update the request. - */ - if (val == -1 && md->md_iterations != old) { - error = gctl_change_param(req, "iterations", sizeof(intmax_t), - &md->md_iterations); - assert(error == 0); - } - - gctl_ro_param(req, "key", sizeof(key), key); - gctl_issue(req); - bzero(key, sizeof(key)); -} - -static void -eli_setkey_detached(struct gctl_req *req, const char *prov, - struct g_eli_metadata *md) -{ - unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; - unsigned char *mkeydst; - unsigned int nkey; - intmax_t val; - int error; - - if (md->md_keys == 0) { - gctl_error(req, "No valid keys on %s.", prov); - return; - } - - /* Generate key for Master Key decryption. */ - if (eli_genkey(req, md, key, false) == NULL) { - bzero(key, sizeof(key)); - return; - } - - /* Decrypt Master Key. */ - error = g_eli_mkey_decrypt(md, key, mkey, &nkey); - bzero(key, sizeof(key)); - if (error != 0) { - bzero(md, sizeof(*md)); - if (error == -1) - gctl_error(req, "Wrong key for %s.", prov); - else /* if (error > 0) */ { - gctl_error(req, "Cannot decrypt Master Key: %s.", - strerror(error)); - } - return; - } - if (verbose) - printf("Decrypted Master Key %u.\n", nkey); - - val = gctl_get_intmax(req, "keyno"); - if (val != -1) - nkey = val; -#if 0 - else - ; /* Use the key number which was found during decryption. */ -#endif - if (nkey >= G_ELI_MAXMKEYS) { - gctl_error(req, "Invalid '%s' argument.", "keyno"); - return; - } - - val = gctl_get_intmax(req, "iterations"); - /* Check if iterations number should and can be changed. */ - if (val != -1 && md->md_iterations == -1) { - md->md_iterations = val; - } else if (val != -1 && val != md->md_iterations) { - if (bitcount32(md->md_keys) != 1) { - gctl_error(req, "To be able to use '-i' option, only " - "one key can be defined."); - return; - } - if (md->md_keys != (1 << nkey)) { - gctl_error(req, "Only already defined key can be " - "changed when '-i' option is used."); - return; - } - md->md_iterations = val; - } - - mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; - md->md_keys |= (1 << nkey); - - bcopy(mkey, mkeydst, sizeof(mkey)); - bzero(mkey, sizeof(mkey)); - - /* Generate key for Master Key encryption. */ - if (eli_genkey(req, md, key, true) == NULL) { - bzero(key, sizeof(key)); - bzero(md, sizeof(*md)); - return; - } - - /* Encrypt the Master-Key with the new key. */ - error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); - bzero(key, sizeof(key)); - if (error != 0) { - bzero(md, sizeof(*md)); - gctl_error(req, "Cannot encrypt Master Key: %s.", - strerror(error)); - return; - } - - /* Store metadata with fresh key. */ - eli_metadata_store(req, prov, md); - bzero(md, sizeof(*md)); -} - -static void -eli_setkey(struct gctl_req *req) -{ - struct g_eli_metadata md; - const char *prov; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - - if (eli_metadata_read(req, prov, &md) == -1) - return; - - if (eli_is_attached(prov)) - eli_setkey_attached(req, &md); - else - eli_setkey_detached(req, prov, &md); - - if (req->error == NULL || req->error[0] == '\0') { - printf("Note, that the master key encrypted with old keys " - "and/or passphrase may still exists in a metadata backup " - "file.\n"); - } -} - -static void -eli_delkey_attached(struct gctl_req *req, const char *prov __unused) -{ - - gctl_issue(req); -} - -static void -eli_delkey_detached(struct gctl_req *req, const char *prov) -{ - struct g_eli_metadata md; - unsigned char *mkeydst; - unsigned int nkey; - intmax_t val; - bool all, force; - - if (eli_metadata_read(req, prov, &md) == -1) - return; - - all = gctl_get_int(req, "all"); - if (all) - arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); - else { - force = gctl_get_int(req, "force"); - val = gctl_get_intmax(req, "keyno"); - if (val == -1) { - gctl_error(req, "Key number has to be specified."); - return; - } - nkey = val; - if (nkey >= G_ELI_MAXMKEYS) { - gctl_error(req, "Invalid '%s' argument.", "keyno"); - return; - } - if (!(md.md_keys & (1 << nkey)) && !force) { - gctl_error(req, "Master Key %u is not set.", nkey); - return; - } - md.md_keys &= ~(1 << nkey); - if (md.md_keys == 0 && !force) { - gctl_error(req, "This is the last Master Key. Use '-f' " - "option if you really want to remove it."); - return; - } - mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; - arc4random_buf(mkeydst, G_ELI_MKEYLEN); - } - - eli_metadata_store(req, prov, &md); - bzero(&md, sizeof(md)); -} - -static void -eli_delkey(struct gctl_req *req) -{ - const char *prov; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - - if (eli_is_attached(prov)) - eli_delkey_attached(req, prov); - else - eli_delkey_detached(req, prov); -} - -static void -eli_resume(struct gctl_req *req) -{ - struct g_eli_metadata md; - unsigned char key[G_ELI_USERKEYLEN]; - const char *prov; - off_t mediasize; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - - if (eli_metadata_read(req, prov, &md) == -1) - return; - - mediasize = g_get_mediasize(prov); - if (md.md_provsize != (uint64_t)mediasize) { - gctl_error(req, "Provider size mismatch."); - return; - } - - if (eli_genkey(req, &md, key, false) == NULL) { - bzero(key, sizeof(key)); - return; - } - - gctl_ro_param(req, "key", sizeof(key), key); - if (gctl_issue(req) == NULL) { - if (verbose) - printf("Resumed %s.\n", prov); - } - bzero(key, sizeof(key)); -} - -static int -eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset) -{ - unsigned int overwrites; - unsigned char *sector; - ssize_t size; - int error; - - size = sizeof(overwrites); - if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size, - NULL, 0) == -1 || overwrites == 0) { - overwrites = G_ELI_OVERWRITES; - } - - size = g_sectorsize(fd); - if (size <= 0) { - gctl_error(req, "Cannot obtain provider sector size %s: %s.", - prov, strerror(errno)); - return (-1); - } - sector = malloc(size); - if (sector == NULL) { - gctl_error(req, "Cannot allocate %zd bytes of memory.", size); - return (-1); - } - - error = 0; - do { - arc4random_buf(sector, size); - if (pwrite(fd, sector, size, offset) != size) { - if (error == 0) - error = errno; - } - (void)g_flush(fd); - } while (--overwrites > 0); - free(sector); - if (error != 0) { - gctl_error(req, "Cannot trash metadata on provider %s: %s.", - prov, strerror(error)); - return (-1); - } - return (0); -} - -static void -eli_kill_detached(struct gctl_req *req, const char *prov) -{ - off_t offset; - int fd; - - /* - * NOTE: Maybe we should verify if this is geli provider first, - * but 'kill' command is quite critical so better don't waste - * the time. - */ -#if 0 - error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), - G_ELI_MAGIC); - if (error != 0) { - gctl_error(req, "Cannot read metadata from %s: %s.", prov, - strerror(error)); - return; - } -#endif - - fd = g_open(prov, 1); - if (fd == -1) { - gctl_error(req, "Cannot open provider %s: %s.", prov, - strerror(errno)); - return; - } - offset = g_mediasize(fd) - g_sectorsize(fd); - if (offset <= 0) { - gctl_error(req, - "Cannot obtain media size or sector size for provider %s: %s.", - prov, strerror(errno)); - (void)g_close(fd); - return; - } - (void)eli_trash_metadata(req, prov, fd, offset); - (void)g_close(fd); -} - -static void -eli_kill(struct gctl_req *req) -{ - const char *prov; - int i, nargs, all; - - nargs = gctl_get_int(req, "nargs"); - all = gctl_get_int(req, "all"); - if (!all && nargs == 0) { - gctl_error(req, "Too few arguments."); - return; - } - /* - * How '-a' option combine with a list of providers: - * Delete Master Keys from all attached providers: - * geli kill -a - * Delete Master Keys from all attached providers and from - * detached da0 and da1: - * geli kill -a da0 da1 - * Delete Master Keys from (attached or detached) da0 and da1: - * geli kill da0 da1 - */ - - /* First detached providers. */ - for (i = 0; i < nargs; i++) { - prov = gctl_get_ascii(req, "arg%d", i); - if (!eli_is_attached(prov)) - eli_kill_detached(req, prov); - } - /* Now attached providers. */ - gctl_issue(req); -} - -static int -eli_backup_create(struct gctl_req *req, const char *prov, const char *file) -{ - unsigned char *sector; - ssize_t secsize; - int error, filefd, ret; - - ret = -1; - filefd = -1; - sector = NULL; - secsize = 0; - - secsize = g_get_sectorsize(prov); - if (secsize == 0) { - gctl_error(req, "Cannot get informations about %s: %s.", prov, - strerror(errno)); - goto out; - } - sector = malloc(secsize); - if (sector == NULL) { - gctl_error(req, "Cannot allocate memory."); - goto out; - } - /* Read metadata from the provider. */ - error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC); - if (error != 0) { - gctl_error(req, "Unable to read metadata from %s: %s.", prov, - strerror(error)); - goto out; - } - - filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); - if (filefd == -1) { - gctl_error(req, "Unable to open %s: %s.", file, - strerror(errno)); - goto out; - } - /* Write metadata to the destination file. */ - if (write(filefd, sector, secsize) != secsize) { - gctl_error(req, "Unable to write to %s: %s.", file, - strerror(errno)); - (void)close(filefd); - (void)unlink(file); - goto out; - } - (void)fsync(filefd); - (void)close(filefd); - /* Success. */ - ret = 0; -out: - if (sector != NULL) { - bzero(sector, secsize); - free(sector); - } - return (ret); -} - -static void -eli_backup(struct gctl_req *req) -{ - const char *file, *prov; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - file = gctl_get_ascii(req, "arg1"); - - eli_backup_create(req, prov, file); -} - -static void -eli_restore(struct gctl_req *req) -{ - struct g_eli_metadata md; - const char *file, *prov; - off_t mediasize; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - file = gctl_get_ascii(req, "arg0"); - prov = gctl_get_ascii(req, "arg1"); - - /* Read metadata from the backup file. */ - if (eli_metadata_read(req, file, &md) == -1) - return; - /* Obtain provider's mediasize. */ - mediasize = g_get_mediasize(prov); - if (mediasize == 0) { - gctl_error(req, "Cannot get informations about %s: %s.", prov, - strerror(errno)); - return; - } - /* Check if the provider size has changed since we did the backup. */ - if (md.md_provsize != (uint64_t)mediasize) { - if (gctl_get_int(req, "force")) { - md.md_provsize = mediasize; - } else { - gctl_error(req, "Provider size mismatch: " - "wrong backup file?"); - return; - } - } - /* Write metadata to the provider. */ - (void)eli_metadata_store(req, prov, &md); -} - -static void -eli_resize(struct gctl_req *req) -{ - struct g_eli_metadata md; - const char *prov; - unsigned char *sector; - ssize_t secsize; - off_t mediasize, oldsize; - int error, nargs, provfd; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 1) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - - provfd = -1; - sector = NULL; - secsize = 0; - - provfd = g_open(prov, 1); - if (provfd == -1) { - gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); - goto out; - } - - mediasize = g_mediasize(provfd); - secsize = g_sectorsize(provfd); - if (mediasize == -1 || secsize == -1) { - gctl_error(req, "Cannot get information about %s: %s.", prov, - strerror(errno)); - goto out; - } - - sector = malloc(secsize); - if (sector == NULL) { - gctl_error(req, "Cannot allocate memory."); - goto out; - } - - oldsize = gctl_get_intmax(req, "oldsize"); - if (oldsize < 0 || oldsize > mediasize) { - gctl_error(req, "Invalid oldsize: Out of range."); - goto out; - } - if (oldsize == mediasize) { - gctl_error(req, "Size hasn't changed."); - goto out; - } - - /* Read metadata from the 'oldsize' offset. */ - if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { - gctl_error(req, "Cannot read old metadata: %s.", - strerror(errno)); - goto out; - } - - /* Check if this sector contains geli metadata. */ - error = eli_metadata_decode(sector, &md); - switch (error) { - case 0: - break; - case EOPNOTSUPP: - gctl_error(req, - "Provider's %s metadata version %u is too new.\n" - "geli: The highest supported version is %u.", - prov, (unsigned int)md.md_version, G_ELI_VERSION); - goto out; - case EINVAL: - gctl_error(req, "Inconsistent provider's %s metadata.", prov); - goto out; - default: - gctl_error(req, - "Unexpected error while decoding provider's %s metadata: %s.", - prov, strerror(error)); - goto out; - } - - /* - * If the old metadata doesn't have a correct provider size, refuse - * to resize. - */ - if (md.md_provsize != (uint64_t)oldsize) { - gctl_error(req, "Provider size mismatch at oldsize."); - goto out; - } - - /* - * Update the old metadata with the current provider size and write - * it back to the correct place on the provider. - */ - md.md_provsize = mediasize; - /* Write metadata to the provider. */ - (void)eli_metadata_store(req, prov, &md); - /* Now trash the old metadata. */ - (void)eli_trash_metadata(req, prov, provfd, oldsize - secsize); -out: - if (provfd != -1) - (void)g_close(provfd); - if (sector != NULL) { - bzero(sector, secsize); - free(sector); - } -} - -static void -eli_version(struct gctl_req *req) -{ - struct g_eli_metadata md; - const char *name; - unsigned int version; - int error, i, nargs; - - nargs = gctl_get_int(req, "nargs"); - - if (nargs == 0) { - unsigned int kernver; - ssize_t size; - - size = sizeof(kernver); - if (sysctlbyname("kern.geom.eli.version", &kernver, &size, - NULL, 0) == -1) { - warn("Unable to obtain GELI kernel version"); - } else { - printf("kernel: %u\n", kernver); - } - printf("userland: %u\n", G_ELI_VERSION); - return; - } - - for (i = 0; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - error = g_metadata_read(name, (unsigned char *)&md, - sizeof(md), G_ELI_MAGIC); - if (error != 0) { - warn("%s: Unable to read metadata: %s.", name, - strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - version = le32dec(&md.md_version); - printf("%s: %u\n", name, version); - } -} - -static void -eli_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_ELI_MAGIC); - if (error != 0) { - fprintf(stderr, "Cannot 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 -eli_dump(struct gctl_req *req) -{ - struct g_eli_metadata md; - const char *name; - int 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); - if (eli_metadata_read(NULL, name, &md) == -1) { - gctl_error(req, "Not fully done."); - continue; - } - printf("Metadata on %s:\n", name); - eli_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/journal/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/journal/Makefile @@ -1,13 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= journal -SRCS+= geom_journal_ufs.c - -LIBADD= ufs md - -CFLAGS+=-I${SRCTOP}/sys - -.include Index: sbin/geom/class/journal/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/journal/Makefile.depend @@ -1,21 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libmd \ - lib/libufs \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/journal/geom_journal.h =================================================================== --- /dev/null +++ sbin/geom/class/journal/geom_journal.h @@ -1,35 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2006 Pawel Jakub Dawidek - * 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. - * - * $FreeBSD$ - */ - -#ifndef _GEOM_JOURNAL_H_ -#define _GEOM_JOURNAL_H_ -int g_journal_ufs_exists(const char *prov); -int g_journal_ufs_using_last_sector(const char *prov); -#endif /* !_GEOM_JOURNAL_H_ */ Index: sbin/geom/class/journal/geom_journal.c =================================================================== --- /dev/null +++ sbin/geom/class/journal/geom_journal.c @@ -1,351 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2005-2006 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "geom_journal.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_JOURNAL_VERSION; - -static void journal_main(struct gctl_req *req, unsigned flags); -static void journal_clear(struct gctl_req *req); -static void journal_dump(struct gctl_req *req); -static void journal_label(struct gctl_req *req); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, journal_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "dump", 0, journal_main, G_NULL_OPTS, - "prov ..." - }, - { "label", G_FLAG_VERBOSE, journal_main, - { - { 'c', "checksum", NULL, G_TYPE_BOOL }, - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'h', "hardcode", NULL, G_TYPE_BOOL }, - { 's', "jsize", "-1", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-cfhv] [-s jsize] dataprov [jprov]" - }, - { "stop", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name ..." - }, - { "sync", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v]" - }, - G_CMD_SENTINEL -}; - -static int verbose = 0; - -static void -journal_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) - journal_label(req); - else if (strcmp(name, "clear") == 0) - journal_clear(req); - else if (strcmp(name, "dump") == 0) - journal_dump(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static int -g_journal_fs_exists(const char *prov) -{ - - if (g_journal_ufs_exists(prov)) - return (1); -#if 0 - if (g_journal_otherfs_exists(prov)) - return (1); -#endif - return (0); -} - -static int -g_journal_fs_using_last_sector(const char *prov) -{ - - if (g_journal_ufs_using_last_sector(prov)) - return (1); -#if 0 - if (g_journal_otherfs_using_last_sector(prov)) - return (1); -#endif - return (0); -} - -static void -journal_label(struct gctl_req *req) -{ - struct g_journal_metadata md; - const char *data, *journal, *str; - u_char sector[512]; - intmax_t jsize, msize, ssize; - int error, force, i, nargs, checksum, hardcode; - - bzero(sector, sizeof(sector)); - nargs = gctl_get_int(req, "nargs"); - str = NULL; /* gcc */ - - strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); - md.md_version = G_JOURNAL_VERSION; - md.md_id = arc4random(); - md.md_joffset = 0; - md.md_jid = 0; - md.md_flags = GJ_FLAG_CLEAN; - checksum = gctl_get_int(req, "checksum"); - if (checksum) - md.md_flags |= GJ_FLAG_CHECKSUM; - force = gctl_get_int(req, "force"); - hardcode = gctl_get_int(req, "hardcode"); - - if (nargs != 1 && nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - - /* Verify the given providers. */ - for (i = 0; i < nargs; i++) { - str = gctl_get_ascii(req, "arg%d", i); - if (g_get_mediasize(str) == 0) { - gctl_error(req, "Invalid provider %s.", str); - return; - } - } - - data = gctl_get_ascii(req, "arg0"); - jsize = gctl_get_intmax(req, "jsize"); - journal = NULL; - switch (nargs) { - case 1: - if (!force && g_journal_fs_exists(data)) { - gctl_error(req, "File system exists on %s and this " - "operation would destroy it.\nUse -f if you " - "really want to do it.", data); - return; - } - journal = data; - msize = g_get_mediasize(data); - ssize = g_get_sectorsize(data); - if (jsize == -1) { - /* - * No journal size specified. 1GB should be safe - * default. - */ - jsize = 1073741824ULL; - } else { - if (jsize < 104857600) { - gctl_error(req, "Journal too small."); - return; - } - if ((jsize % ssize) != 0) { - gctl_error(req, "Invalid journal size."); - return; - } - } - if (jsize + ssize >= msize) { - gctl_error(req, "Provider too small for journalling. " - "You can try smaller jsize (default is %jd).", - jsize); - return; - } - md.md_jstart = msize - ssize - jsize; - md.md_jend = msize - ssize; - break; - case 2: - if (!force && g_journal_fs_using_last_sector(data)) { - gctl_error(req, "File system on %s is using the last " - "sector and this operation is going to overwrite " - "it. Use -f if you really want to do it.", data); - return; - } - journal = gctl_get_ascii(req, "arg1"); - if (jsize != -1) { - gctl_error(req, "jsize argument is valid only for " - "all-in-one configuration."); - return; - } - msize = g_get_mediasize(journal); - ssize = g_get_sectorsize(journal); - md.md_jstart = 0; - md.md_jend = msize - ssize; - break; - } - - if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { - gctl_error(req, "Not equal sector sizes."); - return; - } - - /* - * Clear last sector first, to spoil all components if device exists. - */ - for (i = 0; i < nargs; i++) { - str = gctl_get_ascii(req, "arg%d", i); - error = g_metadata_clear(str, NULL); - if (error != 0) { - gctl_error(req, "Cannot clear metadata on %s: %s.", str, - strerror(error)); - return; - } - } - - /* - * Ok, store metadata. - */ - for (i = 0; i < nargs; i++) { - switch (i) { - case 0: - str = data; - md.md_type = GJ_TYPE_DATA; - if (nargs == 1) - md.md_type |= GJ_TYPE_JOURNAL; - break; - case 1: - str = journal; - md.md_type = GJ_TYPE_JOURNAL; - break; - } - 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)); - } - journal_metadata_encode(&md, sector); - error = g_metadata_store(str, sector, sizeof(sector)); - if (error != 0) { - fprintf(stderr, "Cannot 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 -journal_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_JOURNAL_MAGIC); - if (error != 0) { - fprintf(stderr, "Cannot 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 -journal_dump(struct gctl_req *req) -{ - struct g_journal_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_JOURNAL_MAGIC); - if (error != 0) { - fprintf(stderr, "Cannot read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - if (journal_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); - journal_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/journal/geom_journal_ufs.c =================================================================== --- /dev/null +++ sbin/geom/class/journal/geom_journal_ufs.c @@ -1,80 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2006 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "geom_journal.h" - -static struct fs * -read_superblock(const char *prov) -{ - static struct uufsd disk; - struct fs *fs; - - if (ufs_disk_fillout(&disk, prov) == -1) - return (NULL); - fs = &disk.d_fs; - ufs_disk_close(&disk); - return (fs); -} - -int -g_journal_ufs_exists(const char *prov) -{ - - return (read_superblock(prov) != NULL); -} - -int -g_journal_ufs_using_last_sector(const char *prov) -{ - struct fs *fs; - off_t psize, fssize; - - fs = read_superblock(prov); - if (fs == NULL) - return (0); - /* Provider size in 512 bytes blocks. */ - psize = g_get_mediasize(prov) / DEV_BSIZE; - /* File system size in 512 bytes blocks. */ - fssize = fsbtodb(fs, fs->fs_size); - return (psize <= fssize); -} Index: sbin/geom/class/journal/gjournal.8 =================================================================== --- /dev/null +++ sbin/geom/class/journal/gjournal.8 @@ -1,346 +0,0 @@ -.\" Copyright (c) 2006-2009 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd February 17, 2009 -.Dt GJOURNAL 8 -.Os -.Sh NAME -.Nm gjournal -.Nd "control utility for journaled devices" -.Sh SYNOPSIS -.Nm -.Cm label -.Op Fl cfhv -.Op Fl s Ar jsize -.Ar dataprov -.Op Ar jprov -.Nm -.Cm stop -.Op Fl fv -.Ar name ... -.Nm -.Cm sync -.Op Fl v -.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 journal configuration on the given GEOM provider. -The Journal and data may be stored on the same provider or on two separate -providers. -This is block level journaling, not file system level journaling, which means -everything gets logged, e.g.\& for file systems, it journals both data and -metadata. -The -.Nm -GEOM class can talk to file systems, which allows the use of -.Nm -for file system journaling and to keep file systems in a consistent state. -At this time, only UFS file system is supported. -.Pp -To configure journaling on the UFS file system using -.Nm , -one should first create a -.Nm -provider using the -.Nm -utility, then run -.Xr newfs 8 -or -.Xr tunefs 8 -on it with the -.Fl J -flag which instructs UFS to cooperate with the -.Nm -provider below. -There are important differences in how journaled UFS works. -The most important one is that -.Xr sync 2 -and -.Xr fsync 2 -system calls do not work as expected anymore. -To ensure that data is stored on the data provider, the -.Nm Cm sync -command should be used after calling -.Xr sync 2 . -For the best performance possible, soft-updates should be disabled when -.Nm -is used. -It is also safe and recommended to use the -.Cm async -.Xr mount 8 -option. -.Pp -When -.Nm -is configured on top of -.Xr gmirror 8 -or -.Xr graid3 8 -providers, it also keeps them in a consistent state, thus -automatic synchronization on power failure or system crash may be disabled -on those providers. -.Pp -The -.Nm -utility uses on-disk metadata, stored in the provider's last sector, -to store all needed information. -This could be a problem when an existing file system is converted to use -.Nm . -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm status" -.It Cm label -Configures -.Nm -on the given provider(s). -If only one provider is given, both data and journal are stored on the same -provider. -If two providers are given, the first one will be used as data provider and the -second will be used as the journal provider. -.Pp -Additional options include: -.Bl -tag -width ".Fl s Ar jsize" -.It Fl c -Checksum journal records. -.It Fl f -May be used to convert an existing file system to use -.Nm , -but only if the journal will be configured on a separate provider and if the -last sector in the data provider is not used by the existing file system. -If -.Nm -detects that the last sector is used, it will refuse to overwrite it -and return an error. -This behavior may be forced by using the -.Fl f -flag, which will force -.Nm -to overwrite the last sector. -.It Fl h -Hardcode provider names in metadata. -.It Fl s Ar jsize -Specifies size of the journal if only one provider is used for both data and -journal. -The default is one gigabyte. -Size should be chosen based on provider's load, and not on its size; -recommended minimum is twice the size of the physical memory installed. -It is not recommended to use -.Nm -for small file systems (e.g.: only few gigabytes big). -.El -.It Cm clear -Clear metadata on the given providers. -.It Cm stop -Stop the given provider. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Stop the given provider even if it is opened. -.El -.It Cm sync -Trigger journal switch and enforce sending data to the data provider. -.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 -Create a -.Nm -based UFS file system and mount it: -.Bd -literal -offset indent -gjournal load -gjournal label da0 -newfs -J /dev/da0.journal -mount -o async /dev/da0.journal /mnt -.Ed -.Pp -Configure journaling on an existing file system, but only if -.Nm -allows this (i.e., if the last sector is not already used by the file system): -.Bd -literal -offset indent -umount /dev/da0s1d -gjournal label da0s1d da0s1e && \e - tunefs -J enable -n disable da0s1d.journal && \e - mount -o async /dev/da0s1d.journal /mnt || \e - mount /dev/da0s1d /mnt -.Ed -.Sh SYSCTLS -Gjournal adds the sysctl level kern.geom.journal. -The string and integer information available is detailed below. -The changeable column shows whether a process with appropriate privilege may -change the value. -.Bl -column "accept_immediatelyXXXXXX" integerXXX -offset indent -.It Sy "sysctl name Type Changeable" -.It "debug integer yes" -.It "switch_time integer yes" -.It "force_switch integer yes" -.It "parallel_flushes integer yes" -.It "accept_immediately integer yes" -.It "parallel_copies integer yes" -.It "record_entries integer yes" -.It "optimize integer yes" -.El -.Bl -tag -width 6n -.It Li debug -Setting a non-zero value enables debugging at various levels. -Debug level 1 will record actions at a journal level, relating to journal -switches, metadata updates, etc. -Debug level 2 will record actions at a higher level, relating to the numbers of -entries in journals, access requests, etc. -Debug level 3 will record verbose detail, including insertion of I/Os to the -journal. -.It Li switch_time -The maximum number of seconds a journal is allowed to remain open before -switching to a new journal. -.It Li force_switch -Force a journal switch when the journal uses more than N% of the free journal -space. -.It Li parallel_flushes -The number of flush I/O requests to be sent in parallel when flushing the -journal to the data provider. -.It Li accept_immediately -The maximum number of I/O requests accepted at the same time. -.It Li parallel_copies -The number of copy I/O requests to send in parallel. -.It Li record_entries -The maximum number of record entries to allow in a single journal. -.It Li optimize -Controls whether entries in a journal will be optimized by combining overlapping -I/Os into a single I/O and reordering the entries in a journal. -This can be disabled by setting the sysctl to 0. -.El -.Ss cache -The string and integer information available for the cache level -is detailed below. -The changeable column shows whether a process with appropriate -privilege may change the value. -.Bl -column "alloc_failuresXXXXXX" integerXXX -offset indent -.It Sy "sysctl name Type Changeable" -.It "used integer no" -.It "limit integer yes" -.It "divisor integer no" -.It "switch integer yes" -.It "misses integer yes" -.It "alloc_failures integer yes" -.El -.Bl -tag -width 6n -.It Li used -The number of bytes currently allocated to the cache. -.It Li limit -The maximum number of bytes to be allocated to the cache. -.It Li divisor -Sets the cache size to be used as a proportion of kmem_size. -A value of 2 (the default) will cause the cache size to be set to 1/2 of the -kmem_size. -.It Li switch -Force a journal switch when this percentage of cache has been used. -.It Li misses -The number of cache misses, when data has been read, but was not found in the -cache. -.It Li alloc_failures -The number of times memory failed to be allocated to the cache because the cache -limit was hit. -.El -.Ss stats -The string and integer information available for the statistics level -is detailed below. -The changeable column shows whether a process with appropriate -privilege may change the value. -.Bl -column "skipped_bytesXXXXXX" integerXXX -offset indent -.It Sy "sysctl name Type Changeable" -.It "skipped_bytes integer yes" -.It "combined_ios integer yes" -.It "switches integer yes" -.It "wait_for_copy integer yes" -.It "journal_full integer yes" -.It "low_mem integer yes" -.El -.Bl -tag -width 6n -.It Li skipped_bytes -The number of bytes skipped. -.It Li combined_ios -The number of I/Os which were combined by journal optimization. -.It Li switches -The number of journal switches. -.It Li wait_for_copy -The number of times the journal switch process had to wait for the previous -journal copy to complete. -.It Li journal_full -The number of times the journal was almost full, forcing a journal switch. -.It Li low_mem -The number of times the low_mem hook was called. -.El -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 , -.Xr mount 8 , -.Xr newfs 8 , -.Xr tunefs 8 , -.Xr umount 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 7.0 . -.Sh AUTHORS -.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org Index: sbin/geom/class/label/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/label/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= label - -.include Index: sbin/geom/class/label/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/label/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/label/geom_label.c =================================================================== --- /dev/null +++ sbin/geom/class/label/geom_label.c @@ -1,260 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2005 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - -#ifdef STATIC_GEOM_CLASSES -#define PUBSYM(x) glabel_##x -#else -#define PUBSYM(x) x -#endif - -uint32_t PUBSYM(lib_version) = G_LIB_VERSION; -uint32_t PUBSYM(version) = G_LABEL_VERSION; - -static void label_main(struct gctl_req *req, unsigned flags); -static void label_clear(struct gctl_req *req); -static void label_dump(struct gctl_req *req); -static void label_label(struct gctl_req *req); -static void label_refresh(struct gctl_req *req); - -struct g_command PUBSYM(class_commands)[] = { - { "clear", G_FLAG_VERBOSE, label_main, G_NULL_OPTS, - "[-v] dev ..." - }, - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, G_NULL_OPTS, - "[-v] name dev" - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name ..." - }, - { "dump", 0, label_main, G_NULL_OPTS, - "dev ..." - }, - { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, label_main, G_NULL_OPTS, - "[-v] name dev" - }, - { "refresh", 0, label_main, G_NULL_OPTS, - "dev ..." - }, - { "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 -label_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) - label_label(req); - else if (strcmp(name, "clear") == 0) - label_clear(req); - else if (strcmp(name, "dump") == 0) - label_dump(req); - else if (strcmp(name, "refresh") == 0) - label_refresh(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static void -label_label(struct gctl_req *req) -{ - struct g_label_metadata md; - const char *name, *label; - u_char sector[512]; - int error, nargs; - - bzero(sector, sizeof(sector)); - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - - /* - * Clear last sector first to spoil all components if device exists. - */ - name = gctl_get_ascii(req, "arg1"); - 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_LABEL_MAGIC, sizeof(md.md_magic)); - md.md_version = G_LABEL_VERSION; - label = gctl_get_ascii(req, "arg0"); - bzero(md.md_label, sizeof(md.md_label)); - strlcpy(md.md_label, label, sizeof(md.md_label)); - md.md_provsize = g_get_mediasize(name); - if (md.md_provsize == 0) { - gctl_error(req, "Can't get mediasize of %s: %s.", name, - strerror(errno)); - return; - } - - /* - * Ok, store metadata. - */ - label_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 done."); - } - if (verbose) - printf("Metadata value stored on %s.\n", name); -} - -static void -label_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_LABEL_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 -label_metadata_dump(const struct g_label_metadata *md) -{ - - printf(" Magic string: %s\n", md->md_magic); - printf("Metadata version: %u\n", (u_int)md->md_version); - printf(" Label: %s\n", md->md_label); -} - -static void -label_dump(struct gctl_req *req) -{ - struct g_label_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_LABEL_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - label_metadata_decode((u_char *)&tmpmd, &md); - printf("Metadata on %s:\n", name); - label_metadata_dump(&md); - printf("\n"); - } -} - -static void -label_refresh(struct gctl_req *req) -{ - const char *name; - int i, nargs, fd; - - 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); - fd = g_open(name, 1); - if (fd == -1) { - printf("Can't refresh metadata from %s: %s.\n", - name, strerror(errno)); - } else { - printf("Metadata from %s refreshed.\n", name); - (void)g_close(fd); - } - } -} Index: sbin/geom/class/label/glabel.8 =================================================================== --- /dev/null +++ sbin/geom/class/label/glabel.8 @@ -1,280 +0,0 @@ -.\" Copyright (c) 2004-2005 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd March 12, 2017 -.Dt GLABEL 8 -.Os -.Sh NAME -.Nm glabel -.Nd "disk labelization control utility" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Ar name -.Ar dev -.Nm -.Cm destroy -.Op Fl fv -.Ar name ... -.Nm -.Cm label -.Op Fl v -.Ar name -.Ar dev -.Nm -.Cm stop -.Op Fl fv -.Ar name ... -.Nm -.Cm clear -.Op Fl v -.Ar dev ... -.Nm -.Cm dump -.Ar dev ... -.Nm -.Cm refresh -.Ar dev ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used for GEOM provider labelization. -A label can be set up on a GEOM provider in two ways: -.Dq manual -or -.Dq automatic . -When using the -.Dq manual -method, no metadata are stored on the devices, so a label has to be configured -by hand every time it is needed. -The -.Dq automatic -method uses on-disk metadata to store the label and detect it automatically in -the future. -.Pp -This GEOM class also provides volume label detection for file systems. -Those labels cannot be set with -.Nm , -but must be set with the appropriate file system utility, e.g.\& for UFS -the file system label is set with -.Xr tunefs 8 . -Currently supported file systems are: -.Pp -.Bl -bullet -offset indent -compact -.It -UFS1 volume names (directory -.Pa /dev/ufs/ ) . -.It -UFS2 volume names (directory -.Pa /dev/ufs/ ) . -.It -UFS1 file system IDs (directory -.Pa /dev/ufsid/ ) . -.It -UFS2 file system IDs (directory -.Pa /dev/ufsid/ ) . -.It -MSDOSFS (FAT12, FAT16, FAT32) (directory -.Pa /dev/msdosfs/ ) . -.It -CD ISO9660 (directory -.Pa /dev/iso9660/ ) . -.It -EXT2FS (directory -.Pa /dev/ext2fs/ ) . -.It -REISERFS (directory -.Pa /dev/reiserfs/ ) . -.It -NTFS (directory -.Pa /dev/ntfs/ ) . -.El -.Pp -Support for partition metadata is implemented for: -.Pp -.Bl -bullet -offset indent -compact -.It -GPT labels (directory -.Pa /dev/gpt/ ) . -.It -GPT UUIDs (directory -.Pa /dev/gptid/ ) . -.El -.Pp -Generic disk ID strings are exported as labels in the format -.Pa /dev/diskid/GEOM_CLASS-ident -e.g. -.Pa /dev/diskid/DISK-6QG3Z026 . -.Pp -Generic labels created and managed solely by -.Xr glabel 8 -are created in the -.Pa /dev/label/ -directory. -.Pp -Note that for all label types, nested GEOM classes will cause additional -device nodes to be created, with context-specific data appended to their -names. E.g. for every node like -.Pa /dev/label/bigdisk -there will be additional entries for any partitions which the device -contains, like -.Pa /dev/label/bigdiskp1 -and -.Pa /dev/label/bigdiskp1a . -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm destroy" -.It Cm create -Create temporary label -.Ar name -for the given provider. -This is the -.Dq manual -method. -The kernel module -.Pa geom_label.ko -will be loaded if it is not loaded already. -.It Cm label -Set up a label -.Ar name -for the given provider. -This is the -.Dq automatic -method, where metadata is stored in a provider's last sector. -The kernel module -.Pa geom_label.ko -will be loaded if it is not loaded already. -.It Cm stop -Turn off the given label by its -.Ar name . -This command does not touch on-disk metadata! -.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 refresh -Refresh / rediscover metadata from 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 f -Force the removal of the specified labels. -.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 LABEL -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.label.debug : No 0 -Debug level of the -.Nm LABEL -GEOM class. -This can be set to a number between 0 and 2 inclusive. -If set to 0 minimal debug information is printed, and if set to 2 the -maximum amount of debug information is printed. -.El -.Bl -tag -width indent -.It Va kern.geom.label.*.enable : No 1 -Most -.Nm LABEL -providers implement a -.Xr sysctl 8 -flag and a tunable variable named in the above format. This flag -controls if the label provider will be active, tasting devices -and creating label nodes in the -.Xr devfs 5 -tree. It is sometimes desirable to disable certain label types if -they conflict with other classes in complex GEOM topologies. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -The following example shows how to set up a label for disk -.Dq Li da2 , -create a file system on it, and mount it: -.Bd -literal -offset indent -glabel label -v usr /dev/da2 -newfs /dev/label/usr -mount /dev/label/usr /usr -[...] -umount /usr -glabel stop usr -glabel unload -.Ed -.Pp -The next example shows how to set up a label for a UFS file system: -.Bd -literal -offset indent -tunefs -L data /dev/da4s1a -mount /dev/ufs/data /mnt/data -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr loader.conf 5 , -.Xr geom 8 , -.Xr mount 8 , -.Xr newfs 8 , -.Xr sysctl 8 , -.Xr tunefs 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 Index: sbin/geom/class/mirror/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/mirror/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= mirror - -LIBADD= md - -.include Index: sbin/geom/class/mirror/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/mirror/Makefile.depend @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libmd \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/mirror/geom_mirror.c =================================================================== --- /dev/null +++ sbin/geom/class/mirror/geom_mirror.c @@ -1,500 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2009 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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; - 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); -} Index: sbin/geom/class/mirror/gmirror.8 =================================================================== --- /dev/null +++ sbin/geom/class/mirror/gmirror.8 @@ -1,436 +0,0 @@ -.\" Copyright (c) 2004-2009 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd November 30, 2017 -.Dt GMIRROR 8 -.Os -.Sh NAME -.Nm gmirror -.Nd "control utility for mirrored devices" -.Sh SYNOPSIS -.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 add: -.Bd -literal -offset indent -gmirror configure -b prefer data -.Ed -.Pp -to the -.Pa /etc/rc.early -script and: -.Bd -literal -offset indent -gmirror configure -b round-robin data -.Ed -.Pp -to the -.Pa /etc/rc.local -script. -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 gvinum 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. Index: sbin/geom/class/mountver/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/mountver/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= mountver - -.include Index: sbin/geom/class/mountver/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/mountver/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/mountver/geom_mountver.c =================================================================== --- /dev/null +++ sbin/geom/class/mountver/geom_mountver.c @@ -1,58 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010 Edward Tomasz Napierala - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include "core/geom.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_MOUNTVER_VERSION; - -struct g_command class_commands[] = { - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - G_OPT_SENTINEL - }, - "[-v] prov ..." - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name" - }, - G_CMD_SENTINEL -}; Index: sbin/geom/class/mountver/gmountver.8 =================================================================== --- /dev/null +++ sbin/geom/class/mountver/gmountver.8 @@ -1,133 +0,0 @@ -.\"- -.\" Copyright (c) 2010 Edward Tomasz Napierala -.\" 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 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 THE 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. -.\" -.\" $FreeBSD$ -.\" -.Dd May 18, 2015 -.Dt GMOUNTVER 8 -.Os -.Sh NAME -.Nm gmountver -.Nd "control utility for disk mount verification GEOM class" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Ar prov ... -.Nm -.Cm destroy -.Op Fl fv -.Ar name -.Nm -.Cm list -.Nm -.Cm status -.Op Fl s Ar name -.Nm -.Cm load -.Op Fl v -.Nm -.Cm unload -.Op Fl v -.Sh DESCRIPTION -The -.Nm -utility is used to control the mount verification GEOM class. -When configured, it passes all the I/O requests to the underlying provider. -When the underlying provider disappears - for example because the disk device -got disconnected - it queues all the I/O requests and waits for the provider -to reappear. -When that happens, it attaches to it and sends the queued requests. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm destroy" -.It Cm create -Enable mount verification for the given provider. -If the operation succeeds, a new GEOM provider will be created using the -given provider's name with a -.Ql .mountver -suffix. -The kernel module -.Pa geom_mountver.ko -will be loaded if it is not loaded already. -.It Cm destroy -Destroy -.Ar name . -.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 f -Force the removal of the specified mountver device. -.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 MOUNTVER -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.mountver.debug : No 0 -Debug level of the -.Nm MOUNTVER -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. -.It Va kern.geom.mountver.check_ident : No 1 -This can be set to 0 or 1. -If set to 0, -.Nm -will reattach to the device even if the device reports a different disk ID. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 9.0 . -.Sh AUTHORS -.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org Index: sbin/geom/class/multipath/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/multipath/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= multipath - -CFLAGS+= -I${SRCTOP}/sys - -.include Index: sbin/geom/class/multipath/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/multipath/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/multipath/geom_multipath.c =================================================================== --- /dev/null +++ sbin/geom/class/multipath/geom_multipath.c @@ -1,325 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2006 Mathew Jacob - * 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 -__FBSDID("$FreeBSD$"); -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_MULTIPATH_VERSION; - -static void mp_main(struct gctl_req *, unsigned int); -static void mp_label(struct gctl_req *); -static void mp_clear(struct gctl_req *); -static void mp_prefer(struct gctl_req *); - -struct g_command class_commands[] = { - { - "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - { 'A', "active_active", NULL, G_TYPE_BOOL }, - { 'R', "active_read", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-vAR] name prov ..." - }, - { - "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main, - { - { 'A', "active_active", NULL, G_TYPE_BOOL }, - { 'R', "active_read", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-vAR] name prov ..." - }, - { "configure", G_FLAG_VERBOSE, NULL, - { - { 'A', "active_active", NULL, G_TYPE_BOOL }, - { 'P', "active_passive", NULL, G_TYPE_BOOL }, - { 'R', "active_read", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-vAPR] name" - }, - { - "add", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" - }, - { - "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" - }, - { - "prefer", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { - "fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" - }, - { - "restore", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" - }, - { - "rotate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name" - }, - { - "getactive", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name" - }, - { - "destroy", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name" - }, - { - "stop", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name" - }, - { - "clear", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS, - "[-v] prov ..." - }, - G_CMD_SENTINEL -}; - -static void -mp_main(struct gctl_req *req, unsigned int flags __unused) -{ - const char *name; - - name = gctl_get_ascii(req, "verb"); - if (name == NULL) { - gctl_error(req, "No '%s' argument.", "verb"); - return; - } - if (strcmp(name, "label") == 0) { - mp_label(req); - } else if (strcmp(name, "clear") == 0) { - mp_clear(req); - } else if (strcmp(name, "prefer") == 0) { - mp_prefer(req); - } else { - gctl_error(req, "Unknown command: %s.", name); - } -} - -static void -mp_label(struct gctl_req *req) -{ - struct g_multipath_metadata md; - off_t disksize = 0, msize; - uint8_t *sector, *rsector; - char *ptr; - uuid_t uuid; - ssize_t secsize = 0, ssize; - uint32_t status; - const char *name, *name2, *mpname; - int error, i, nargs, fd; - - nargs = gctl_get_int(req, "nargs"); - if (nargs < 2) { - gctl_error(req, "wrong number of arguments."); - return; - } - - /* - * First, check each provider to make sure it's the same size. - * This also gets us our size and sectorsize for the metadata. - */ - for (i = 1; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (msize == 0 || ssize == 0) { - gctl_error(req, "cannot get information about %s: %s.", - name, strerror(errno)); - return; - } - if (i == 1) { - secsize = ssize; - disksize = msize; - } else { - if (secsize != ssize) { - gctl_error(req, "%s sector size %ju different.", - name, (intmax_t)ssize); - return; - } - if (disksize != msize) { - gctl_error(req, "%s media size %ju different.", - name, (intmax_t)msize); - return; - } - } - - } - - /* - * Generate metadata. - */ - strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic)); - md.md_version = G_MULTIPATH_VERSION; - mpname = gctl_get_ascii(req, "arg0"); - strlcpy(md.md_name, mpname, sizeof(md.md_name)); - md.md_size = disksize; - md.md_sectorsize = secsize; - uuid_create(&uuid, &status); - if (status != uuid_s_ok) { - gctl_error(req, "cannot create a UUID."); - return; - } - uuid_to_string(&uuid, &ptr, &status); - if (status != uuid_s_ok) { - gctl_error(req, "cannot stringify a UUID."); - return; - } - strlcpy(md.md_uuid, ptr, sizeof (md.md_uuid)); - md.md_active_active = gctl_get_int(req, "active_active"); - if (gctl_get_int(req, "active_read")) - md.md_active_active = 2; - free(ptr); - - /* - * Allocate a sector to write as metadata. - */ - sector = calloc(1, secsize); - if (sector == NULL) { - gctl_error(req, "unable to allocate metadata buffer"); - return; - } - rsector = malloc(secsize); - if (rsector == NULL) { - gctl_error(req, "unable to allocate metadata buffer"); - goto done; - } - - /* - * encode the metadata - */ - multipath_metadata_encode(&md, sector); - - /* - * Store metadata on the initial provider. - */ - name = gctl_get_ascii(req, "arg1"); - error = g_metadata_store(name, sector, secsize); - if (error != 0) { - gctl_error(req, "cannot store metadata on %s: %s.", name, strerror(error)); - goto done; - } - - /* - * Now touch the rest of the providers to hint retaste. - */ - for (i = 2; i < nargs; i++) { - name2 = gctl_get_ascii(req, "arg%d", i); - fd = g_open(name2, 1); - if (fd < 0) { - fprintf(stderr, "Unable to open %s: %s.\n", - name2, strerror(errno)); - continue; - } - if (pread(fd, rsector, secsize, disksize - secsize) != - (ssize_t)secsize) { - fprintf(stderr, "Unable to read metadata from %s: %s.\n", - name2, strerror(errno)); - g_close(fd); - continue; - } - g_close(fd); - if (memcmp(sector, rsector, secsize)) { - fprintf(stderr, "No metadata found on %s." - " It is not a path of %s.\n", - name2, name); - } - } -done: - free(rsector); - free(sector); -} - - -static void -mp_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_MULTIPATH_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't clear metadata on %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - } -} - -static void -mp_prefer(struct gctl_req *req) -{ - const char *name, *comp, *errstr; - int nargs; - - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Usage: prefer GEOM PROVIDER"); - return; - } - name = gctl_get_ascii(req, "arg0"); - comp = gctl_get_ascii(req, "arg1"); - errstr = gctl_issue (req); - if (errstr != NULL) { - fprintf(stderr, "Can't set %s preferred provider to %s: %s.\n", - name, comp, errstr); - } -} Index: sbin/geom/class/multipath/gmultipath.8 =================================================================== --- /dev/null +++ sbin/geom/class/multipath/gmultipath.8 @@ -1,377 +0,0 @@ -.\" Copyright (c) 2007 Matthew Jacob -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd September 8, 2016 -.Dt GMULTIPATH 8 -.Os -.Sh NAME -.Nm gmultipath -.Nd "disk multipath control utility" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl ARv -.Ar name -.Ar prov ... -.Nm -.Cm label -.Op Fl ARv -.Ar name -.Ar prov ... -.Nm -.Cm configure -.Op Fl APRv -.Ar name -.Nm -.Cm add -.Op Fl v -.Ar name prov -.Nm -.Cm remove -.Op Fl v -.Ar name prov -.Nm -.Cm fail -.Op Fl v -.Ar name prov -.Nm -.Cm restore -.Op Fl v -.Ar name prov -.Nm -.Cm rotate -.Op Fl v -.Ar name -.Nm -.Cm prefer -.Op Fl v -.Ar name -.Ar prov -.Nm -.Cm getactive -.Op Fl v -.Ar name -.Nm -.Cm destroy -.Op Fl v -.Ar name -.Nm -.Cm stop -.Op Fl v -.Ar name -.Nm -.Cm clear -.Op Fl v -.Ar prov ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used for device multipath configuration. -.Pp -The multipath device 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 multipath -device has to be configured by hand every time it is needed. -Additional device paths also will not be detected automatically. -The -.Dq automatic -method uses on-disk metadata to detect device and all its paths. -Metadata use the last sector of the underlying disk device and -include device name and UUID. -The UUID guarantees uniqueness in a shared storage environment -but is in general too cumbersome to use. -The name is what is exported via the device interface. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm destroy" -.It Cm create -Create multipath device with -.Dq manual -method without writing any on-disk metadata. -It is up to administrator, how to properly identify device paths. -Kernel will only check that all given providers have same media and -sector sizes. -.Pp -.Fl A -option enables Active/Active mode, -.Fl R -option enables Active/Read mode, otherwise Active/Passive mode is used -by default. -.It Cm label -Create multipath device with -.Dq automatic -method. -Label the first given provider with on-disk metadata using the specified -.Ar name . -The rest of given providers will be retasted to detect these metadata. -It reliably protects against specifying unrelated providers. -Providers with no matching metadata detected will not be added to the device. -.Pp -.Fl A -option enables Active/Active mode, -.Fl R -option enables Active/Read mode, otherwise Active/Passive mode is used -by default. -.It Cm configure -Configure the given multipath device. -.Pp -.Fl A -option enables Active/Active mode, -.Fl P -option enables Active/Passive mode, -.Fl R -option enables Active/Read mode. -.It Cm add -Add the given provider as a path to the given multipath device. -Should normally be used only for devices created with -.Dq manual -method, unless you know what you are doing (you are sure that it is another -device path, but tasting its metadata in regular -.Dq automatic -way is not possible). -.It Cm remove -Remove the given provider as a path from the given multipath device. -If the last path removed, the multipath device will be destroyed. -.It Cm fail -Mark specified provider as a path of the specified multipath device as failed. -If there are other paths present, new requests will be forwarded there. -.It Cm restore -Mark specified provider as a path of the specified multipath device as -operational, allowing it to handle requests. -.It Cm rotate -Change the active provider/path to the next available provider in Active/Passive mode. -.It Cm prefer -Change the active provider/path to the specified provider in Active/Passive mode. -.It Cm getactive -Get the currently active provider(s)/path(s). -.It Cm destroy -Destroy the given multipath device clearing metadata. -.It Cm stop -Stop the given multipath device without clearing metadata. -.It Cm clear -Clear metadata on the given provider. -.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 -.Sh SYSCTL VARIABLES -The following -.Xr sysctl 8 -variable can be used to control the behavior of the -.Nm MULTIPATH -GEOM class. -.Bl -tag -width indent -.It Va kern.geom.multipath.debug : No 0 -Debug level of the -.Nm MULTIPATH -GEOM class. -This can be set to 0 (default) or 1 to disable or enable various -forms of chattiness. -.It Va kern.geom.multipath.exclusive : No 1 -Open underlying providers exclusively, preventing individual paths access. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh MULTIPATH ARCHITECTURE -This is a multiple path architecture with no device knowledge or -presumptions other than size matching built in. -Therefore the user must exercise some care -in selecting providers that do indeed represent multiple paths to the -same underlying disk device. -The reason for this is that there are several -criteria across multiple underlying transport types that can -.Ar indicate -identity, but in all respects such identity can rarely be considered -.Ar definitive . -.Pp -For example, if you use the World Word Port Name of a Fibre Channel -disk object you might believe that two disks that have the same WWPN -on different paths (or even disjoint fabrics) might be considered -the same disk. -Nearly always this would be a safe assumption, until -you realize that a WWPN, like an Ethernet MAC address, is a soft -programmable entity, and that a misconfigured Director Class switch -could lead you to believe incorrectly that you have found multiple -paths to the same device. -This is an extreme and theoretical case, but -it is possible enough to indicate that the policy for deciding which -of multiple pathnames refer to the same device should be left to the -system operator who will use tools and knowledge of their own storage -subsystem to make the correct configuration selection. -.Pp -There are Active/Passive, Active/Read and Active/Active operation modes -supported. -In Active/Passive mode only one path has I/O moving on it -at any point in time. -This I/O continues until an I/O is returned with -a generic I/O error or a "Nonexistent Device" error. -When this occurs, that path is marked FAIL, the next path -in a list is selected as active and the failed I/O reissued. -In Active/Active mode all paths not marked FAIL may handle I/O at the same time. -Requests are distributed between paths to equalize load. -For capable devices it allows the utilisation of the bandwidth available on all paths. -In Active/Read mode all paths not marked FAIL may handle reads at the same time, -but unlike in Active/Active mode only one path handles write requests at any -point in time; closely following the original write request order if the layer -above needs it for data consistency (not waiting for requisite write completion -before sending dependent write). -.Pp -When new devices are added to the system the -.Nm MULTIPATH -GEOM class is given an opportunity to taste these new devices. -If a new -device has a -.Nm MULTIPATH -on-disk metadata label, the device is either used to create a new -.Nm MULTIPATH -GEOM, or added to the list of paths for an existing -.Nm MULTIPATH -GEOM. -.Pp -It is this mechanism that works reasonably with -.Xr isp 4 -and -.Xr mpt 4 -based Fibre Channel disk devices. -For these devices, when a device disappears -(due to e.g., a cable pull or power failure to a switch), the device is -proactively marked as gone and I/O to it failed. -This causes the -.Nm MULTIPATH -failure event just described. -.Pp -When Fibre Channel events inform either -.Xr isp 4 -or -.Xr mpt 4 -host bus adapters that new devices may have arrived (e.g., the arrival -of an RSCN event from the Fabric Domain Controller), they can cause -a rescan to occur and cause the attachment and configuration of any -(now) new devices to occur, causing the taste event described above. -.Pp -This means that this multipath architecture is not a one-shot path -failover, but can be considered to be steady state as long as failed -paths are repaired (automatically or otherwise). -.Pp -Automatic rescanning is not a requirement. -Nor is Fibre Channel. -The -same failover mechanisms work equally well for traditional "Parallel" -SCSI but may require manual intervention with -.Xr camcontrol 8 -to cause the reattachment of repaired device links. -.Sh EXAMPLES -The following example shows how to use -.Xr camcontrol 8 -to find possible multiple path devices and to create a -.Nm MULTIPATH -GEOM class for them. -.Bd -literal -offset indent -mysys# camcontrol devlist - at scbus0 target 0 lun 0 (da0,pass0) - at scbus0 target 0 lun 1 (da1,pass1) - at scbus1 target 0 lun 0 (da2,pass2) - at scbus1 target 0 lun 1 (da3,pass3) -mysys# camcontrol inquiry da0 -S -ECNTX0LUN000000SER10ac0d01 -mysys# camcontrol inquiry da2 -S -ECNTX0LUN000000SER10ac0d01 -.Ed -.Pp -Now that you have used the Serial Number to compare two disk paths -it is not entirely unreasonable to conclude that these are multiple -paths to the same device. -However, only the user who is familiar -with their storage is qualified to make this judgement. -.Pp -You can then use the -.Nm -command to label and create a -.Nm MULTIPATH -GEOM provider named -.Ar FRED . -.Bd -literal -offset indent -gmultipath label -v FRED /dev/da0 /dev/da2 -disklabel -Brw /dev/multipath/FRED auto -newfs /dev/multipath/FREDa -mount /dev/multipath/FREDa /mnt.... -.Ed -.Pp -The resultant console output looks something like: -.Bd -literal -offset indent -GEOM_MULTIPATH: da0 added to FRED -GEOM_MULTIPATH: da0 is now active path in FRED -GEOM_MULTIPATH: da2 added to FRED -.Ed -.Pp -To load the -.Nm -module at boot time, add this entry to -.Pa /boot/loader.conf : -.Bd -literal -offset ident -geom_multipath_load="YES" -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr isp 4 , -.Xr mpt 4 , -.Xr loader.conf 5 , -.Xr camcontrol 8 , -.Xr geom 8 , -.Xr mount 8 , -.Xr newfs 8 , -.Xr sysctl 8 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 7.0 -.Sh AUTHORS -.An Matthew Jacob Aq Mt mjacob@FreeBSD.org -.An Alexander Motin Aq Mt mav@FreeBSD.org Index: sbin/geom/class/nop/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/nop/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= nop - -.include Index: sbin/geom/class/nop/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/nop/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/nop/geom_nop.c =================================================================== --- /dev/null +++ sbin/geom/class/nop/geom_nop.c @@ -1,81 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2006 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include "core/geom.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_NOP_VERSION; - -struct g_command class_commands[] = { - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - { 'e', "error", "-1", G_TYPE_NUMBER }, - { 'o', "offset", "0", G_TYPE_NUMBER }, - { 'p', "stripesize", "0", G_TYPE_NUMBER }, - { 'P', "stripeoffset", "0", G_TYPE_NUMBER }, - { 'r', "rfailprob", "-1", G_TYPE_NUMBER }, - { 's', "size", "0", G_TYPE_NUMBER }, - { 'S', "secsize", "0", G_TYPE_NUMBER }, - { 'w', "wfailprob", "-1", G_TYPE_NUMBER }, - { 'z', "physpath", G_NOP_PHYSPATH_PASSTHROUGH, G_TYPE_STRING }, - G_OPT_SENTINEL - }, - "[-v] [-e error] [-o offset] [-p stripesize] [-P stripeoffset] " - "[-r rfailprob] [-s size] [-S secsize] [-w wfailprob] " - "[-z physpath] dev ..." - }, - { "configure", G_FLAG_VERBOSE, NULL, - { - { 'e', "error", "-1", G_TYPE_NUMBER }, - { 'r', "rfailprob", "-1", G_TYPE_NUMBER }, - { 'w', "wfailprob", "-1", G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] [-e error] [-r rfailprob] [-w wfailprob] prov ..." - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] prov ..." - }, - { "reset", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] prov ..." - }, - G_CMD_SENTINEL -}; Index: sbin/geom/class/nop/gnop.8 =================================================================== --- /dev/null +++ sbin/geom/class/nop/gnop.8 @@ -1,189 +0,0 @@ -.\" Copyright (c) 2004-2006 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd January 17, 2018 -.Dt GNOP 8 -.Os -.Sh NAME -.Nm gnop -.Nd "control utility for NOP GEOM class" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Op Fl e Ar error -.Op Fl o Ar offset -.Op Fl p Ar stripesize -.Op Fl P Ar stripeoffset -.Op Fl r Ar rfailprob -.Op Fl s Ar size -.Op Fl S Ar secsize -.Op Fl w Ar wfailprob -.Op Fl z Ar physpath -.Ar dev ... -.Nm -.Cm configure -.Op Fl v -.Op Fl e Ar error -.Op Fl r Ar rfailprob -.Op Fl w Ar wfailprob -.Ar prov ... -.Nm -.Cm destroy -.Op Fl fv -.Ar prov ... -.Nm -.Cm reset -.Op Fl v -.Ar prov ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used for setting up transparent providers on existing ones. -Its main purpose is testing other GEOM classes, as it allows forced provider -removal and I/O error simulation with a given probability. -It also gathers statistics on the number of read, write, delete, -getattr, flush, and other requests, and the number of bytes read and written. -.Nm -can also be used as a good starting point for implementing new GEOM -classes. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm configure" -.It Cm create -Set up a transparent provider on the given devices. -If the operation succeeds, the new provider should appear with name -.Pa /dev/ Ns Ao Ar dev Ac Ns Pa .nop . -The kernel module -.Pa geom_nop.ko -will be loaded if it is not loaded already. -.It Cm configure -Configure existing transparent provider. -At the moment it is only used for changing failure probability. -.It Cm destroy -Turn off the given transparent providers. -.It Cm reset -Reset statistics for the given transparent 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: -.Bl -tag -width ".Fl r Ar rfailprob" -.It Fl e Ar error -Specifies the error number to return on failure. -.It Fl f -Force the removal of the specified provider. -.It Fl o Ar offset -Where to begin on the original provider. -.It Fl p Ar stripesize -Value of the stripesize property of the transparent provider. -.It Fl P Ar stripeoffset -Value of the stripeoffset property of the transparent provider. -.It Fl r Ar rfailprob -Specifies read failure probability in percent. -.It Fl s Ar size -Size of the transparent provider. -.It Fl S Ar secsize -Sector size of the transparent provider. -.It Fl w Ar wfailprob -Specifies write failure probability in percent. -.It Fl v -Be more verbose. -.It Fl z Ar physpath -Physical path of the transparent provider. -.El -.Sh SYSCTL VARIABLES -The following -.Xr sysctl 8 -variables can be used to control the behavior of the -.Nm NOP -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.nop.debug : No 0 -Debug level of the -.Nm NOP -GEOM class. -This can be set to a number between 0 and 2 inclusive. -If set to 0, minimal debug information is printed. -If set to 1, basic debug information is logged along with the I/O requests -that were returned as errors. -If set to 2, the maximum amount of debug information is printed including -all I/O requests. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -The following example shows how to create a transparent provider for disk -.Pa /dev/da0 -with 50% write failure probability, and how to destroy it. -.Bd -literal -offset indent -gnop create -v -w 50 da0 -gnop destroy -v da0.nop -.Ed -.Pp -The traffic statistics for the given transparent providers can be obtained -with the -.Cm list -command. -The example below shows the number of bytes written with -.Xr newfs 8 : -.Bd -literal -offset indent -gnop create da0 -newfs /dev/da0.nop -gnop list -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 5.3 . -.Sh AUTHORS -.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org Index: sbin/geom/class/part/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/part/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= part - -LIBADD= util - -.include Index: sbin/geom/class/part/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/part/Makefile.depend @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libutil \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/part/geom_part.c =================================================================== --- /dev/null +++ sbin/geom/class/part/geom_part.c @@ -1,1344 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2007, 2008 Marcel Moolenaar - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - -#ifdef STATIC_GEOM_CLASSES -#define PUBSYM(x) gpart_##x -#else -#define PUBSYM(x) x -#endif - -uint32_t PUBSYM(lib_version) = G_LIB_VERSION; -uint32_t PUBSYM(version) = 0; - -static char sstart[32]; -static char ssize[32]; -volatile sig_atomic_t undo_restore; - -#define GPART_AUTOFILL "*" -#define GPART_FLAGS "C" - -#define GPART_PARAM_BOOTCODE "bootcode" -#define GPART_PARAM_INDEX "index" -#define GPART_PARAM_PARTCODE "partcode" - -static struct gclass *find_class(struct gmesh *, const char *); -static struct ggeom * find_geom(struct gclass *, const char *); -static int geom_is_withered(struct ggeom *); -static const char *find_geomcfg(struct ggeom *, const char *); -static const char *find_provcfg(struct gprovider *, const char *); -static struct gprovider *find_provider(struct ggeom *, off_t); -static const char *fmtsize(int64_t); -static int gpart_autofill(struct gctl_req *); -static int gpart_autofill_resize(struct gctl_req *); -static void gpart_bootcode(struct gctl_req *, unsigned int); -static void *gpart_bootfile_read(const char *, ssize_t *); -static _Noreturn void gpart_issue(struct gctl_req *, unsigned int); -static void gpart_show(struct gctl_req *, unsigned int); -static void gpart_show_geom(struct ggeom *, const char *, int); -static int gpart_show_hasopt(struct gctl_req *, const char *, const char *); -static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t); -static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *); -static void gpart_print_error(const char *); -static void gpart_backup(struct gctl_req *, unsigned int); -static void gpart_restore(struct gctl_req *, unsigned int); - -struct g_command PUBSYM(class_commands)[] = { - { "add", 0, gpart_issue, { - { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, - { 'b', "start", GPART_AUTOFILL, G_TYPE_STRING }, - { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, - { 't', "type", NULL, G_TYPE_STRING }, - { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-t type [-a alignment] [-b start] [-s size] [-i index] " - "[-l label] [-f flags] geom" - }, - { "backup", 0, gpart_backup, G_NULL_OPTS, - "geom" - }, - { "bootcode", 0, gpart_bootcode, { - { 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, - { 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING }, - { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "[-b bootcode] [-p partcode -i index] [-f flags] geom" - }, - { "commit", 0, gpart_issue, G_NULL_OPTS, - "geom" - }, - { "create", 0, gpart_issue, { - { 's', "scheme", NULL, G_TYPE_STRING }, - { 'n', "entries", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-s scheme [-n entries] [-f flags] provider" - }, - { "delete", 0, gpart_issue, { - { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-i index [-f flags] geom" - }, - { "destroy", 0, gpart_issue, { - { 'F', "force", NULL, G_TYPE_BOOL }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "[-F] [-f flags] geom" - }, - { "modify", 0, gpart_issue, { - { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, - { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, - { 't', "type", G_VAL_OPTIONAL, G_TYPE_STRING }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-i index [-l label] [-t type] [-f flags] geom" - }, - { "set", 0, gpart_issue, { - { 'a', "attrib", NULL, G_TYPE_STRING }, - { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-a attrib [-i index] [-f flags] geom" - }, - { "show", 0, gpart_show, { - { 'l', "show_label", NULL, G_TYPE_BOOL }, - { 'r', "show_rawtype", NULL, G_TYPE_BOOL }, - { 'p', "show_providers", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL }, - "[-l | -r] [-p] [geom ...]" - }, - { "undo", 0, gpart_issue, G_NULL_OPTS, - "geom" - }, - { "unset", 0, gpart_issue, { - { 'a', "attrib", NULL, G_TYPE_STRING }, - { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-a attrib [-i index] [-f flags] geom" - }, - { "resize", 0, gpart_issue, { - { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, - { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, - { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "-i index [-a alignment] [-s size] [-f flags] geom" - }, - { "restore", 0, gpart_restore, { - { 'F', "force", NULL, G_TYPE_BOOL }, - { 'l', "restore_labels", NULL, G_TYPE_BOOL }, - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "[-lF] [-f flags] provider [...]" - }, - { "recover", 0, gpart_issue, { - { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, - G_OPT_SENTINEL }, - "[-f flags] geom" - }, - G_CMD_SENTINEL -}; - -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, *wgp; - - if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - name += sizeof(_PATH_DEV) - 1; - wgp = NULL; - LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { - if (strcmp(gp->lg_name, name) != 0) - continue; - if (!geom_is_withered(gp)) - return (gp); - else - wgp = gp; - } - return (wgp); -} - -static int -geom_is_withered(struct ggeom *gp) -{ - struct gconfig *gc; - - LIST_FOREACH(gc, &gp->lg_config, lg_config) { - if (!strcmp(gc->lg_name, "wither")) - return (1); - } - return (0); -} - -static const char * -find_geomcfg(struct ggeom *gp, const char *cfg) -{ - struct gconfig *gc; - - LIST_FOREACH(gc, &gp->lg_config, lg_config) { - if (!strcmp(gc->lg_name, cfg)) - return (gc->lg_val); - } - return (NULL); -} - -static const char * -find_provcfg(struct gprovider *pp, const char *cfg) -{ - struct gconfig *gc; - - LIST_FOREACH(gc, &pp->lg_config, lg_config) { - if (!strcmp(gc->lg_name, cfg)) - return (gc->lg_val); - } - return (NULL); -} - -static struct gprovider * -find_provider(struct ggeom *gp, off_t minsector) -{ - struct gprovider *pp, *bestpp; - const char *s; - off_t sector, bestsector; - - bestpp = NULL; - bestsector = 0; - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "start"); - sector = (off_t)strtoimax(s, NULL, 0); - if (sector < minsector) - continue; - if (bestpp != NULL && sector >= bestsector) - continue; - - bestpp = pp; - bestsector = sector; - } - return (bestpp); -} - -static const char * -fmtsize(int64_t rawsz) -{ - static char buf[5]; - - humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE, - HN_B | HN_NOSPACE | HN_DECIMAL); - return (buf); -} - -static const char * -fmtattrib(struct gprovider *pp) -{ - static char buf[128]; - struct gconfig *gc; - u_int idx; - - buf[0] = '\0'; - idx = 0; - LIST_FOREACH(gc, &pp->lg_config, lg_config) { - if (strcmp(gc->lg_name, "attrib") != 0) - continue; - idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s", - (idx == 0) ? " [" : ",", gc->lg_val); - } - if (idx > 0) - snprintf(buf + idx, sizeof(buf) - idx, "] "); - return (buf); -} - -#define ALIGNDOWN(d, a) ((d) - (d) % (a)) -#define ALIGNUP(d, a) ((d) % (a) ? (d) - (d) % (a) + (a): (d)) - -static int -gpart_autofill_resize(struct gctl_req *req) -{ - struct gmesh mesh; - struct gclass *cp; - struct ggeom *gp; - struct gprovider *pp; - off_t last, size, start, new_size; - off_t lba, new_lba, alignment, offset; - const char *s; - int error, idx, has_alignment; - - idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); - if (idx < 1) - errx(EXIT_FAILURE, "invalid partition index"); - - error = geom_gettree(&mesh); - if (error) - return (error); - s = gctl_get_ascii(req, "class"); - if (s == NULL) - abort(); - cp = find_class(&mesh, s); - if (cp == NULL) - errx(EXIT_FAILURE, "Class %s not found.", s); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(cp, s); - if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); - pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; - if (pp == NULL) - errx(EXIT_FAILURE, "Provider for geom %s not found.", s); - - s = gctl_get_ascii(req, "alignment"); - has_alignment = (*s == '*') ? 0 : 1; - alignment = 1; - if (has_alignment) { - error = g_parse_lba(s, pp->lg_sectorsize, &alignment); - if (error) - errc(EXIT_FAILURE, error, "Invalid alignment param"); - if (alignment == 0) - errx(EXIT_FAILURE, "Invalid alignment param"); - } else { - lba = pp->lg_stripesize / pp->lg_sectorsize; - if (lba > 0) - alignment = lba; - } - error = gctl_delete_param(req, "alignment"); - if (error) - errc(EXIT_FAILURE, error, "internal error"); - - s = gctl_get_ascii(req, "size"); - if (*s == '*') - new_size = 0; - else { - error = g_parse_lba(s, pp->lg_sectorsize, &new_size); - if (error) - errc(EXIT_FAILURE, error, "Invalid size param"); - /* no autofill necessary. */ - if (has_alignment == 0) - goto done; - } - - offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; - s = find_geomcfg(gp, "last"); - if (s == NULL) - errx(EXIT_FAILURE, "Final block not found for geom %s", - gp->lg_name); - last = (off_t)strtoimax(s, NULL, 0); - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "index"); - if (s == NULL) - continue; - if (atoi(s) == idx) - break; - } - if (pp == NULL) - errx(EXIT_FAILURE, "invalid partition index"); - - s = find_provcfg(pp, "start"); - start = (off_t)strtoimax(s, NULL, 0); - s = find_provcfg(pp, "end"); - lba = (off_t)strtoimax(s, NULL, 0); - size = lba - start + 1; - - pp = find_provider(gp, lba + 1); - if (new_size > 0 && (new_size <= size || pp == NULL)) { - /* The start offset may be not aligned, so we align the end - * offset and then calculate the size. - */ - new_size = ALIGNDOWN(start + offset + new_size, - alignment) - start - offset; - goto done; - } - if (pp == NULL) { - new_size = ALIGNDOWN(last + offset + 1, alignment) - - start - offset; - if (new_size < size) - return (ENOSPC); - } else { - s = find_provcfg(pp, "start"); - new_lba = (off_t)strtoimax(s, NULL, 0); - /* - * Is there any free space between current and - * next providers? - */ - new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset; - if (new_lba > lba) - new_size = new_lba - start; - else { - geom_deletetree(&mesh); - return (ENOSPC); - } - } -done: - snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size); - gctl_change_param(req, "size", -1, ssize); - geom_deletetree(&mesh); - return (0); -} - -static int -gpart_autofill(struct gctl_req *req) -{ - struct gmesh mesh; - struct gclass *cp; - struct ggeom *gp; - struct gprovider *pp; - off_t first, last, a_first; - off_t size, start, a_lba; - off_t lba, len, alignment, offset; - uintmax_t grade; - const char *s; - int error, has_size, has_start, has_alignment; - - s = gctl_get_ascii(req, "verb"); - if (strcmp(s, "resize") == 0) - return gpart_autofill_resize(req); - if (strcmp(s, "add") != 0) - return (0); - - error = geom_gettree(&mesh); - if (error) - return (error); - s = gctl_get_ascii(req, "class"); - if (s == NULL) - abort(); - cp = find_class(&mesh, s); - if (cp == NULL) - errx(EXIT_FAILURE, "Class %s not found.", s); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(cp, s); - if (gp == NULL) { - if (g_device_path(s) == NULL) { - errx(EXIT_FAILURE, "No such geom %s.", s); - } else { - /* - * We don't free memory allocated by g_device_path() as - * we are about to exit. - */ - errx(EXIT_FAILURE, - "No partitioning scheme found on geom %s. Create one first using 'gpart create'.", - s); - } - } - pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; - if (pp == NULL) - errx(EXIT_FAILURE, "Provider for geom %s not found.", s); - - s = gctl_get_ascii(req, "alignment"); - has_alignment = (*s == '*') ? 0 : 1; - alignment = 1; - if (has_alignment) { - error = g_parse_lba(s, pp->lg_sectorsize, &alignment); - if (error) - errc(EXIT_FAILURE, error, "Invalid alignment param"); - if (alignment == 0) - errx(EXIT_FAILURE, "Invalid alignment param"); - } - error = gctl_delete_param(req, "alignment"); - if (error) - errc(EXIT_FAILURE, error, "internal error"); - - s = gctl_get_ascii(req, "size"); - has_size = (*s == '*') ? 0 : 1; - size = 0; - if (has_size) { - error = g_parse_lba(s, pp->lg_sectorsize, &size); - if (error) - errc(EXIT_FAILURE, error, "Invalid size param"); - } - - s = gctl_get_ascii(req, "start"); - has_start = (*s == '*') ? 0 : 1; - start = 0ULL; - if (has_start) { - error = g_parse_lba(s, pp->lg_sectorsize, &start); - if (error) - errc(EXIT_FAILURE, error, "Invalid start param"); - } - - /* No autofill necessary. */ - if (has_size && has_start && !has_alignment) - goto done; - - len = pp->lg_stripesize / pp->lg_sectorsize; - if (len > 0 && !has_alignment) - alignment = len; - - /* Adjust parameters to stripeoffset */ - offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; - start = ALIGNUP(start + offset, alignment); - if (size > alignment) - size = ALIGNDOWN(size, alignment); - - s = find_geomcfg(gp, "first"); - if (s == NULL) - errx(EXIT_FAILURE, "Starting block not found for geom %s", - gp->lg_name); - first = (off_t)strtoimax(s, NULL, 0); - s = find_geomcfg(gp, "last"); - if (s == NULL) - errx(EXIT_FAILURE, "Final block not found for geom %s", - gp->lg_name); - last = (off_t)strtoimax(s, NULL, 0); - grade = ~0ULL; - a_first = ALIGNUP(first + offset, alignment); - last = ALIGNDOWN(last + offset + 1, alignment) - 1; - if (a_first < start) - a_first = start; - while ((pp = find_provider(gp, first)) != NULL) { - s = find_provcfg(pp, "start"); - lba = (off_t)strtoimax(s, NULL, 0); - a_lba = ALIGNDOWN(lba + offset, alignment); - if (first < a_lba && a_first < a_lba) { - /* Free space [first, lba> */ - len = a_lba - a_first; - if (has_size) { - if (len >= size && - (uintmax_t)(len - size) < grade) { - start = a_first; - grade = len - size; - } - } else if (has_start) { - if (start >= a_first && start < a_lba) { - size = a_lba - start; - grade = start - a_first; - } - } else { - if (grade == ~0ULL || len > size) { - start = a_first; - size = len; - grade = 0; - } - } - } - - s = find_provcfg(pp, "end"); - first = (off_t)strtoimax(s, NULL, 0) + 1; - if (first + offset > a_first) - a_first = ALIGNUP(first + offset, alignment); - } - if (a_first <= last) { - /* Free space [first-last] */ - len = ALIGNDOWN(last - a_first + 1, alignment); - if (has_size) { - if (len >= size && - (uintmax_t)(len - size) < grade) { - start = a_first; - grade = len - size; - } - } else if (has_start) { - if (start >= a_first && start <= last) { - size = ALIGNDOWN(last - start + 1, alignment); - grade = start - a_first; - } - } else { - if (grade == ~0ULL || len > size) { - start = a_first; - size = len; - grade = 0; - } - } - } - if (grade == ~0ULL) { - geom_deletetree(&mesh); - return (ENOSPC); - } - start -= offset; /* Return back to real offset */ -done: - snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size); - gctl_change_param(req, "size", -1, ssize); - snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start); - gctl_change_param(req, "start", -1, sstart); - geom_deletetree(&mesh); - return (0); -} - -static void -gpart_show_geom(struct ggeom *gp, const char *element, int show_providers) -{ - struct gprovider *pp; - const char *s, *scheme; - off_t first, last, sector, end; - off_t length, secsz; - int idx, wblocks, wname, wmax; - - if (geom_is_withered(gp)) - return; - scheme = find_geomcfg(gp, "scheme"); - if (scheme == NULL) - errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); - s = find_geomcfg(gp, "first"); - if (s == NULL) - errx(EXIT_FAILURE, "Starting block not found for geom %s", - gp->lg_name); - first = (off_t)strtoimax(s, NULL, 0); - s = find_geomcfg(gp, "last"); - if (s == NULL) - errx(EXIT_FAILURE, "Final block not found for geom %s", - gp->lg_name); - last = (off_t)strtoimax(s, NULL, 0); - wblocks = strlen(s); - s = find_geomcfg(gp, "state"); - if (s == NULL) - errx(EXIT_FAILURE, "State not found for geom %s", gp->lg_name); - if (s != NULL && *s != 'C') - s = NULL; - wmax = strlen(gp->lg_name); - if (show_providers) { - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - wname = strlen(pp->lg_name); - if (wname > wmax) - wmax = wname; - } - } - wname = wmax; - pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; - secsz = pp->lg_sectorsize; - printf("=>%*jd %*jd %*s %s (%s)%s\n", - wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1), - wname, gp->lg_name, - scheme, fmtsize(pp->lg_mediasize), - s ? " [CORRUPT]": ""); - - while ((pp = find_provider(gp, first)) != NULL) { - s = find_provcfg(pp, "start"); - sector = (off_t)strtoimax(s, NULL, 0); - - s = find_provcfg(pp, "end"); - end = (off_t)strtoimax(s, NULL, 0); - length = end - sector + 1; - - s = find_provcfg(pp, "index"); - idx = atoi(s); - if (first < sector) { - printf(" %*jd %*jd %*s - free - (%s)\n", - wblocks, (intmax_t)first, wblocks, - (intmax_t)(sector - first), wname, "", - fmtsize((sector - first) * secsz)); - } - if (show_providers) { - printf(" %*jd %*jd %*s %s %s (%s)\n", - wblocks, (intmax_t)sector, wblocks, - (intmax_t)length, wname, pp->lg_name, - find_provcfg(pp, element), fmtattrib(pp), - fmtsize(pp->lg_mediasize)); - } else - printf(" %*jd %*jd %*d %s %s (%s)\n", - wblocks, (intmax_t)sector, wblocks, - (intmax_t)length, wname, idx, - find_provcfg(pp, element), fmtattrib(pp), - fmtsize(pp->lg_mediasize)); - first = end + 1; - } - if (first <= last) { - length = last - first + 1; - printf(" %*jd %*jd %*s - free - (%s)\n", - wblocks, (intmax_t)first, wblocks, (intmax_t)length, - wname, "", - fmtsize(length * secsz)); - } - printf("\n"); -} - -static int -gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt) -{ - - if (!gctl_get_int(req, "%s", opt)) - return (0); - - if (elt != NULL) - errx(EXIT_FAILURE, "-l and -r are mutually exclusive"); - - return (1); -} - -static void -gpart_show(struct gctl_req *req, unsigned int fl __unused) -{ - struct gmesh mesh; - struct gclass *classp; - struct ggeom *gp; - const char *element, *name; - int error, i, nargs, show_providers; - - element = NULL; - if (gpart_show_hasopt(req, "show_label", element)) - element = "label"; - if (gpart_show_hasopt(req, "show_rawtype", element)) - element = "rawtype"; - if (element == NULL) - element = "type"; - - name = gctl_get_ascii(req, "class"); - if (name == NULL) - abort(); - error = geom_gettree(&mesh); - if (error != 0) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); - classp = find_class(&mesh, name); - if (classp == NULL) { - geom_deletetree(&mesh); - errx(EXIT_FAILURE, "Class %s not found.", name); - } - show_providers = gctl_get_int(req, "show_providers"); - nargs = gctl_get_int(req, "nargs"); - if (nargs > 0) { - for (i = 0; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - gp = find_geom(classp, name); - if (gp != NULL) - gpart_show_geom(gp, element, show_providers); - else - errx(EXIT_FAILURE, "No such geom: %s.", name); - } - } else { - LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { - gpart_show_geom(gp, element, show_providers); - } - } - geom_deletetree(&mesh); -} - -static void -gpart_backup(struct gctl_req *req, unsigned int fl __unused) -{ - struct gmesh mesh; - struct gclass *classp; - struct gprovider *pp; - struct ggeom *gp; - const char *s, *scheme; - off_t sector, end; - off_t length; - int error, i, windex, wblocks, wtype; - - if (gctl_get_int(req, "nargs") != 1) - errx(EXIT_FAILURE, "Invalid number of arguments."); - error = geom_gettree(&mesh); - if (error != 0) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); - s = gctl_get_ascii(req, "class"); - if (s == NULL) - abort(); - classp = find_class(&mesh, s); - if (classp == NULL) { - geom_deletetree(&mesh); - errx(EXIT_FAILURE, "Class %s not found.", s); - } - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(classp, s); - if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); - scheme = find_geomcfg(gp, "scheme"); - if (scheme == NULL) - abort(); - pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; - s = find_geomcfg(gp, "last"); - if (s == NULL) - abort(); - wblocks = strlen(s); - wtype = 0; - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "type"); - i = strlen(s); - if (i > wtype) - wtype = i; - } - s = find_geomcfg(gp, "entries"); - if (s == NULL) - abort(); - windex = strlen(s); - printf("%s %s\n", scheme, s); - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "start"); - sector = (off_t)strtoimax(s, NULL, 0); - - s = find_provcfg(pp, "end"); - end = (off_t)strtoimax(s, NULL, 0); - length = end - sector + 1; - - s = find_provcfg(pp, "label"); - printf("%-*s %*s %*jd %*jd %s %s\n", - windex, find_provcfg(pp, "index"), - wtype, find_provcfg(pp, "type"), - wblocks, (intmax_t)sector, - wblocks, (intmax_t)length, - (s != NULL) ? s: "", fmtattrib(pp)); - } - geom_deletetree(&mesh); -} - -static int -skip_line(const char *p) -{ - - while (*p != '\0') { - if (*p == '#') - return (1); - if (isspace(*p) == 0) - return (0); - p++; - } - return (1); -} - -static void -gpart_sighndl(int sig __unused) -{ - undo_restore = 1; -} - -static void -gpart_restore(struct gctl_req *req, unsigned int fl __unused) -{ - struct gmesh mesh; - struct gclass *classp; - struct gctl_req *r; - struct ggeom *gp; - struct sigaction si_sa; - const char *s, *flags, *errstr, *label; - char **ap, *argv[6], line[BUFSIZ], *pline; - int error, forced, i, l, nargs, created, rl; - intmax_t n; - - nargs = gctl_get_int(req, "nargs"); - if (nargs < 1) - errx(EXIT_FAILURE, "Invalid number of arguments."); - - forced = gctl_get_int(req, "force"); - flags = gctl_get_ascii(req, "flags"); - rl = gctl_get_int(req, "restore_labels"); - s = gctl_get_ascii(req, "class"); - if (s == NULL) - abort(); - error = geom_gettree(&mesh); - if (error != 0) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); - classp = find_class(&mesh, s); - if (classp == NULL) { - geom_deletetree(&mesh); - errx(EXIT_FAILURE, "Class %s not found.", s); - } - - sigemptyset(&si_sa.sa_mask); - si_sa.sa_flags = 0; - si_sa.sa_handler = gpart_sighndl; - if (sigaction(SIGINT, &si_sa, 0) == -1) - err(EXIT_FAILURE, "sigaction SIGINT"); - - if (forced) { - /* destroy existent partition table before restore */ - for (i = 0; i < nargs; i++) { - s = gctl_get_ascii(req, "arg%d", i); - gp = find_geom(classp, s); - if (gp != NULL) { - r = gctl_get_handle(); - gctl_ro_param(r, "class", -1, - classp->lg_name); - gctl_ro_param(r, "verb", -1, "destroy"); - gctl_ro_param(r, "flags", -1, "restore"); - gctl_ro_param(r, "force", sizeof(forced), - &forced); - gctl_ro_param(r, "arg0", -1, s); - errstr = gctl_issue(r); - if (errstr != NULL && errstr[0] != '\0') { - gpart_print_error(errstr); - gctl_free(r); - goto backout; - } - gctl_free(r); - } - } - } - created = 0; - while (undo_restore == 0 && - fgets(line, sizeof(line) - 1, stdin) != NULL) { - /* Format of backup entries: - * - * [label] ['['attrib[,attrib]']'] - */ - pline = (char *)line; - pline[strlen(line) - 1] = 0; - if (skip_line(pline)) - continue; - for (ap = argv; - (*ap = strsep(&pline, " \t")) != NULL;) - if (**ap != '\0' && ++ap >= &argv[6]) - break; - l = ap - &argv[0]; - label = pline = NULL; - if (l == 1 || l == 2) { /* create table */ - if (created) - errx(EXIT_FAILURE, "Incorrect backup format."); - if (l == 2) - n = strtoimax(argv[1], NULL, 0); - for (i = 0; i < nargs; i++) { - s = gctl_get_ascii(req, "arg%d", i); - r = gctl_get_handle(); - gctl_ro_param(r, "class", -1, - classp->lg_name); - gctl_ro_param(r, "verb", -1, "create"); - gctl_ro_param(r, "scheme", -1, argv[0]); - if (l == 2) - gctl_ro_param(r, "entries", - sizeof(n), &n); - gctl_ro_param(r, "flags", -1, "restore"); - gctl_ro_param(r, "arg0", -1, s); - errstr = gctl_issue(r); - if (errstr != NULL && errstr[0] != '\0') { - gpart_print_error(errstr); - gctl_free(r); - goto backout; - } - gctl_free(r); - } - created = 1; - continue; - } else if (l < 4 || created == 0) - errx(EXIT_FAILURE, "Incorrect backup format."); - else if (l == 5) { - if (strchr(argv[4], '[') == NULL) - label = argv[4]; - else - pline = argv[4]; - } else if (l == 6) { - label = argv[4]; - pline = argv[5]; - } - /* Add partitions to each table */ - for (i = 0; i < nargs; i++) { - s = gctl_get_ascii(req, "arg%d", i); - r = gctl_get_handle(); - n = strtoimax(argv[0], NULL, 0); - gctl_ro_param(r, "class", -1, classp->lg_name); - gctl_ro_param(r, "verb", -1, "add"); - gctl_ro_param(r, "flags", -1, "restore"); - gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n); - gctl_ro_param(r, "type", -1, argv[1]); - gctl_ro_param(r, "start", -1, argv[2]); - gctl_ro_param(r, "size", -1, argv[3]); - if (rl != 0 && label != NULL) - gctl_ro_param(r, "label", -1, argv[4]); - gctl_ro_param(r, "alignment", -1, GPART_AUTOFILL); - gctl_ro_param(r, "arg0", -1, s); - error = gpart_autofill(r); - if (error != 0) - errc(EXIT_FAILURE, error, "autofill"); - errstr = gctl_issue(r); - if (errstr != NULL && errstr[0] != '\0') { - gpart_print_error(errstr); - gctl_free(r); - goto backout; - } - gctl_free(r); - } - if (pline == NULL || *pline != '[') - continue; - /* set attributes */ - pline++; - for (ap = argv; - (*ap = strsep(&pline, ",]")) != NULL;) - if (**ap != '\0' && ++ap >= &argv[6]) - break; - for (i = 0; i < nargs; i++) { - l = ap - &argv[0]; - s = gctl_get_ascii(req, "arg%d", i); - while (l > 0) { - r = gctl_get_handle(); - gctl_ro_param(r, "class", -1, classp->lg_name); - gctl_ro_param(r, "verb", -1, "set"); - gctl_ro_param(r, "flags", -1, "restore"); - gctl_ro_param(r, GPART_PARAM_INDEX, - sizeof(n), &n); - gctl_ro_param(r, "attrib", -1, argv[--l]); - gctl_ro_param(r, "arg0", -1, s); - errstr = gctl_issue(r); - if (errstr != NULL && errstr[0] != '\0') { - gpart_print_error(errstr); - gctl_free(r); - goto backout; - } - gctl_free(r); - } - } - } - if (undo_restore) - goto backout; - /* commit changes if needed */ - if (strchr(flags, 'C') != NULL) { - for (i = 0; i < nargs; i++) { - s = gctl_get_ascii(req, "arg%d", i); - r = gctl_get_handle(); - gctl_ro_param(r, "class", -1, classp->lg_name); - gctl_ro_param(r, "verb", -1, "commit"); - gctl_ro_param(r, "arg0", -1, s); - errstr = gctl_issue(r); - if (errstr != NULL && errstr[0] != '\0') { - gpart_print_error(errstr); - gctl_free(r); - goto backout; - } - gctl_free(r); - } - } - gctl_free(req); - geom_deletetree(&mesh); - exit(EXIT_SUCCESS); - -backout: - for (i = 0; i < nargs; i++) { - s = gctl_get_ascii(req, "arg%d", i); - r = gctl_get_handle(); - gctl_ro_param(r, "class", -1, classp->lg_name); - gctl_ro_param(r, "verb", -1, "undo"); - gctl_ro_param(r, "arg0", -1, s); - gctl_issue(r); - gctl_free(r); - } - gctl_free(req); - geom_deletetree(&mesh); - exit(EXIT_FAILURE); -} - -static void * -gpart_bootfile_read(const char *bootfile, ssize_t *size) -{ - struct stat sb; - void *code; - int fd; - - if (stat(bootfile, &sb) == -1) - err(EXIT_FAILURE, "%s", bootfile); - if (!S_ISREG(sb.st_mode)) - errx(EXIT_FAILURE, "%s: not a regular file", bootfile); - if (sb.st_size == 0) - errx(EXIT_FAILURE, "%s: empty file", bootfile); - if (*size > 0 && sb.st_size > *size) - errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile, - *size); - - *size = sb.st_size; - - fd = open(bootfile, O_RDONLY); - if (fd == -1) - err(EXIT_FAILURE, "%s", bootfile); - code = malloc(*size); - if (code == NULL) - err(EXIT_FAILURE, NULL); - if (read(fd, code, *size) != *size) - err(EXIT_FAILURE, "%s", bootfile); - close(fd); - - return (code); -} - -static void -gpart_write_partcode(struct ggeom *gp, int idx, void *code, ssize_t size) -{ - char dsf[128]; - struct gprovider *pp; - const char *s; - char *buf; - off_t bsize; - int fd; - - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "index"); - if (s == NULL) - continue; - if (atoi(s) == idx) - break; - } - - if (pp != NULL) { - snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); - if (pp->lg_mediasize < size) - errx(EXIT_FAILURE, "%s: not enough space", dsf); - fd = open(dsf, O_WRONLY); - if (fd == -1) - err(EXIT_FAILURE, "%s", dsf); - /* - * When writing to a disk device, the write must be - * sector aligned and not write to any partial sectors, - * so round up the buffer size to the next sector and zero it. - */ - bsize = (size + pp->lg_sectorsize - 1) / - pp->lg_sectorsize * pp->lg_sectorsize; - buf = calloc(1, bsize); - if (buf == NULL) - err(EXIT_FAILURE, "%s", dsf); - bcopy(code, buf, size); - if (write(fd, buf, bsize) != bsize) - err(EXIT_FAILURE, "%s", dsf); - free(buf); - close(fd); - printf("partcode written to %s\n", pp->lg_name); - } else - errx(EXIT_FAILURE, "invalid partition index"); -} - -static void -gpart_write_partcode_vtoc8(struct ggeom *gp, int idx, void *code) -{ - char dsf[128]; - struct gprovider *pp; - const char *s; - int installed, fd; - - installed = 0; - LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { - s = find_provcfg(pp, "index"); - if (s == NULL) - continue; - if (idx != 0 && atoi(s) != idx) - continue; - snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name); - if (pp->lg_sectorsize != sizeof(struct vtoc8)) - errx(EXIT_FAILURE, "%s: unexpected sector " - "size (%d)\n", dsf, pp->lg_sectorsize); - if (pp->lg_mediasize < VTOC_BOOTSIZE) - continue; - fd = open(dsf, O_WRONLY); - if (fd == -1) - err(EXIT_FAILURE, "%s", dsf); - /* - * We ignore the first VTOC_BOOTSIZE bytes of boot code in - * order to avoid overwriting the label. - */ - if (lseek(fd, sizeof(struct vtoc8), SEEK_SET) != - sizeof(struct vtoc8)) - err(EXIT_FAILURE, "%s", dsf); - if (write(fd, (caddr_t)code + sizeof(struct vtoc8), - VTOC_BOOTSIZE - sizeof(struct vtoc8)) != VTOC_BOOTSIZE - - sizeof(struct vtoc8)) - err(EXIT_FAILURE, "%s", dsf); - installed++; - close(fd); - if (idx != 0 && atoi(s) == idx) - break; - } - if (installed == 0) - errx(EXIT_FAILURE, "%s: no partitions", gp->lg_name); - else - printf("partcode written to %s\n", - idx != 0 ? pp->lg_name: gp->lg_name); -} - -static void -gpart_bootcode(struct gctl_req *req, unsigned int fl) -{ - struct gmesh mesh; - struct gclass *classp; - struct ggeom *gp; - const char *s; - void *bootcode, *partcode; - size_t bootsize, partsize; - int error, idx, vtoc8; - - if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { - s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); - bootsize = 800 * 1024; /* Arbitrary limit. */ - bootcode = gpart_bootfile_read(s, &bootsize); - error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize, - bootcode); - if (error) - errc(EXIT_FAILURE, error, "internal error"); - } else - bootcode = NULL; - - s = gctl_get_ascii(req, "class"); - if (s == NULL) - abort(); - error = geom_gettree(&mesh); - if (error != 0) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); - classp = find_class(&mesh, s); - if (classp == NULL) { - geom_deletetree(&mesh); - errx(EXIT_FAILURE, "Class %s not found.", s); - } - if (gctl_get_int(req, "nargs") != 1) - errx(EXIT_FAILURE, "Invalid number of arguments."); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(classp, s); - if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); - s = find_geomcfg(gp, "scheme"); - if (s == NULL) - errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); - if (strcmp(s, "VTOC8") == 0) - vtoc8 = 1; - else - vtoc8 = 0; - - if (gctl_has_param(req, GPART_PARAM_PARTCODE)) { - s = gctl_get_ascii(req, GPART_PARAM_PARTCODE); - if (vtoc8 != 0) - partsize = VTOC_BOOTSIZE; - else - partsize = 1024 * 1024; /* Arbitrary limit. */ - partcode = gpart_bootfile_read(s, &partsize); - error = gctl_delete_param(req, GPART_PARAM_PARTCODE); - if (error) - errc(EXIT_FAILURE, error, "internal error"); - } else - partcode = NULL; - - if (gctl_has_param(req, GPART_PARAM_INDEX)) { - if (partcode == NULL) - errx(EXIT_FAILURE, "-i is only valid with -p"); - idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); - if (idx < 1) - errx(EXIT_FAILURE, "invalid partition index"); - error = gctl_delete_param(req, GPART_PARAM_INDEX); - if (error) - errc(EXIT_FAILURE, error, "internal error"); - } else - idx = 0; - - if (partcode != NULL) { - if (vtoc8 == 0) { - if (idx == 0) - errx(EXIT_FAILURE, "missing -i option"); - gpart_write_partcode(gp, idx, partcode, partsize); - } else { - if (partsize != VTOC_BOOTSIZE) - errx(EXIT_FAILURE, "invalid bootcode"); - gpart_write_partcode_vtoc8(gp, idx, partcode); - } - } else - if (bootcode == NULL) - errx(EXIT_FAILURE, "no -b nor -p"); - - if (bootcode != NULL) - gpart_issue(req, fl); - - geom_deletetree(&mesh); - free(partcode); -} - -static void -gpart_print_error(const char *errstr) -{ - char *errmsg; - int error; - - error = strtol(errstr, &errmsg, 0); - if (errmsg != errstr) { - while (errmsg[0] == ' ') - errmsg++; - if (errmsg[0] != '\0') - warnc(error, "%s", errmsg); - else - warnc(error, NULL); - } else - warnx("%s", errmsg); -} - -static _Noreturn void -gpart_issue(struct gctl_req *req, unsigned int fl __unused) -{ - char buf[4096]; - const char *errstr; - int error, status; - - if (gctl_get_int(req, "nargs") != 1) - errx(EXIT_FAILURE, "Invalid number of arguments."); - (void)gctl_delete_param(req, "nargs"); - - /* autofill parameters (if applicable). */ - error = gpart_autofill(req); - if (error) { - warnc(error, "autofill"); - status = EXIT_FAILURE; - goto done; - } - - bzero(buf, sizeof(buf)); - gctl_rw_param(req, "output", sizeof(buf), buf); - errstr = gctl_issue(req); - if (errstr == NULL || errstr[0] == '\0') { - if (buf[0] != '\0') - printf("%s", buf); - status = EXIT_SUCCESS; - goto done; - } - - gpart_print_error(errstr); - status = EXIT_FAILURE; - - done: - gctl_free(req); - exit(status); -} Index: sbin/geom/class/part/gpart.8 =================================================================== --- /dev/null +++ sbin/geom/class/part/gpart.8 @@ -1,1391 +0,0 @@ -.\" Copyright (c) 2007, 2008 Marcel Moolenaar -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd March 2, 2018 -.Dt GPART 8 -.Os -.Sh NAME -.Nm gpart -.Nd "control utility for the disk partitioning GEOM class" -.Sh SYNOPSIS -.\" ==== ADD ==== -.Nm -.Cm add -.Fl t Ar type -.Op Fl a Ar alignment -.Op Fl b Ar start -.Op Fl s Ar size -.Op Fl i Ar index -.Op Fl l Ar label -.Op Fl f Ar flags -.Ar geom -.\" ==== BACKUP ==== -.Nm -.Cm backup -.Ar geom -.\" ==== BOOTCODE ==== -.Nm -.Cm bootcode -.Op Fl b Ar bootcode -.Op Fl p Ar partcode Fl i Ar index -.Op Fl f Ar flags -.Ar geom -.\" ==== COMMIT ==== -.Nm -.Cm commit -.Ar geom -.\" ==== CREATE ==== -.Nm -.Cm create -.Fl s Ar scheme -.Op Fl n Ar entries -.Op Fl f Ar flags -.Ar provider -.\" ==== DELETE ==== -.Nm -.Cm delete -.Fl i Ar index -.Op Fl f Ar flags -.Ar geom -.\" ==== DESTROY ==== -.Nm -.Cm destroy -.Op Fl F -.Op Fl f Ar flags -.Ar geom -.\" ==== MODIFY ==== -.Nm -.Cm modify -.Fl i Ar index -.Op Fl l Ar label -.Op Fl t Ar type -.Op Fl f Ar flags -.Ar geom -.\" ==== RECOVER ==== -.Nm -.Cm recover -.Op Fl f Ar flags -.Ar geom -.\" ==== RESIZE ==== -.Nm -.Cm resize -.Fl i Ar index -.Op Fl a Ar alignment -.Op Fl s Ar size -.Op Fl f Ar flags -.Ar geom -.\" ==== RESTORE ==== -.Nm -.Cm restore -.Op Fl lF -.Op Fl f Ar flags -.Ar provider -.Op Ar ... -.\" ==== SET ==== -.Nm -.Cm set -.Fl a Ar attrib -.Fl i Ar index -.Op Fl f Ar flags -.Ar geom -.\" ==== SHOW ==== -.Nm -.Cm show -.Op Fl l | r -.Op Fl p -.Op Ar geom ... -.\" ==== UNDO ==== -.Nm -.Cm undo -.Ar geom -.\" ==== UNSET ==== -.Nm -.Cm unset -.Fl a Ar attrib -.Fl i Ar index -.Op Fl f Ar flags -.Ar geom -.\" -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used to partition GEOM providers, normally disks. -The first argument is the action to be taken: -.Bl -tag -width ".Cm bootcode" -.\" ==== ADD ==== -.It Cm add -Add a new partition to the partitioning scheme given by -.Ar geom . -The partition begins on the logical block address given by the -.Fl b Ar start -option. -Its size is given by the -.Fl s Ar size -option. -SI unit suffixes are allowed. -One or both -.Fl b -and -.Fl s -options can be omitted. -If so they are automatically calculated. -The type of the partition is given by the -.Fl t Ar type -option. -Partition types are discussed below in the section entitled -.Sx "PARTITION TYPES" . -.Pp -Additional options include: -.Bl -tag -width 12n -.It Fl a Ar alignment -If specified, then -.Nm -utility tries to align -.Ar start -offset and partition -.Ar size -to be multiple of -.Ar alignment -value. -.It Fl i Ar index -The index in the partition table at which the new partition is to be -placed. -The index determines the name of the device special file used -to represent the partition. -.It Fl l Ar label -The label attached to the partition. -This option is only valid when used on partitioning schemes that support -partition labels. -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== BACKUP ==== -.It Cm backup -Dump a partition table to standard output in a special format used by the -.Cm restore -action. -.\" ==== BOOTCODE ==== -.It Cm bootcode -Embed bootstrap code into the partitioning scheme's metadata on the -.Ar geom -(using -.Fl b Ar bootcode ) -or write bootstrap code into a partition (using -.Fl p Ar partcode -and -.Fl i Ar index ) . -Not all partitioning schemes have embedded bootstrap code, so the -.Fl b Ar bootcode -option is scheme-specific in nature (see the section entitled -.Sx BOOTSTRAPPING -below). -The -.Fl b Ar bootcode -option specifies a file that contains the bootstrap code. -The contents and size of the file are determined by the partitioning -scheme. -The -.Fl p Ar partcode -option specifies a file that contains the bootstrap code intended to be -written to a partition. -The partition is specified by the -.Fl i Ar index -option. -The size of the file must be smaller than the size of the partition. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== COMMIT ==== -.It Cm commit -Commit any pending changes for geom -.Ar geom . -All actions are committed by default and will not result in -pending changes. -Actions can be modified with the -.Fl f Ar flags -option so that they are not committed, but become pending. -Pending changes are reflected by the geom and the -.Nm -utility, but they are not actually written to disk. -The -.Cm commit -action will write all pending changes to disk. -.\" ==== CREATE ==== -.It Cm create -Create a new partitioning scheme on a provider given by -.Ar provider . -The -.Fl s Ar scheme -option determines the scheme to use. -The kernel must have support for a particular scheme before -that scheme can be used to partition a disk. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl n Ar entries -The number of entries in the partition table. -Every partitioning scheme has a minimum and maximum number of entries. -This option allows tables to be created with a number of entries -that is within the limits. -Some schemes have a maximum equal to the minimum and some schemes have -a maximum large enough to be considered unlimited. -By default, partition tables are created with the minimum number of -entries. -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== DELETE ==== -.It Cm delete -Delete a partition from geom -.Ar geom -and further identified by the -.Fl i Ar index -option. -The partition cannot be actively used by the kernel. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== DESTROY ==== -.It Cm destroy -Destroy the partitioning scheme as implemented by geom -.Ar geom . -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl F -Forced destroying of the partition table even if it is not empty. -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== MODIFY ==== -.It Cm modify -Modify a partition from geom -.Ar geom -and further identified by the -.Fl i Ar index -option. -Only the type and/or label of the partition can be modified. -To change the type of a partition, specify the new type with the -.Fl t Ar type -option. -To change the label of a partition, specify the new label with the -.Fl l Ar label -option. -Not all partitioning schemes support labels and it is invalid to -try to change a partition label in such cases. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== RECOVER ==== -.It Cm recover -Recover a corrupt partition's scheme metadata on the geom -.Ar geom . -See the section entitled -.Sx RECOVERING -below for the additional information. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== RESIZE ==== -.It Cm resize -Resize a partition from geom -.Ar geom -and further identified by the -.Fl i Ar index -option. -New partition size is expressed in logical block -numbers and can be given by the -.Fl s Ar size -option. -If -.Fl s -option is omitted then new size is automatically calculated -to maximum available from given geom -.Ar geom . -.Pp -Additional options include: -.Bl -tag -width 12n -.It Fl a Ar alignment -If specified, then -.Nm -utility tries to align partition -.Ar size -to be multiple of -.Ar alignment -value. -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== RESTORE ==== -.It Cm restore -Restore the partition table from a backup previously created by the -.Cm backup -action and read from standard input. -Only the partition table is restored. -This action does not affect the content of partitions. -After restoring the partition table and writing bootcode if needed, -user data must be restored from backup. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl F -Destroy partition table on the given -.Ar provider -before doing restore. -.It Fl l -Restore partition labels for partitioning schemes that support them. -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== SET ==== -.It Cm set -Set the named attribute on the partition entry. -See the section entitled -.Sx ATTRIBUTES -below for a list of available attributes. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.\" ==== SHOW ==== -.It Cm show -Show current partition information for the specified geoms, or all -geoms if none are specified. -The default output includes the logical starting block of each -partition, the partition size in blocks, the partition index number, -the partition type, and a human readable partition size. -Block sizes and locations are based on the device's Sectorsize -as shown by -.Cm gpart list . -Additional options include: -.Bl -tag -width 10n -.It Fl l -For partitioning schemes that support partition labels, print them -instead of partition type. -.It Fl p -Show provider names instead of partition indexes. -.It Fl r -Show raw partition type instead of symbolic name. -.El -.\" ==== UNDO ==== -.It Cm undo -Revert any pending changes for geom -.Ar geom . -This action is the opposite of the -.Cm commit -action and can be used to undo any changes that have not been committed. -.\" ==== UNSET ==== -.It Cm unset -Clear the named attribute on the partition entry. -See the section entitled -.Sx ATTRIBUTES -below for a list of available attributes. -.Pp -Additional options include: -.Bl -tag -width 10n -.It Fl f Ar flags -Additional operational flags. -See the section entitled -.Sx "OPERATIONAL FLAGS" -below for a discussion -about its use. -.El -.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 -.Sh PARTITIONING SCHEMES -Several partitioning schemes are supported by the -.Nm -utility: -.Bl -tag -width ".Cm VTOC8" -.It Cm APM -Apple Partition Map, used by PowerPC(R) Macintosh(R) computers. -Requires the -.Cd GEOM_PART_APM -kernel option. -.It Cm BSD -Traditional BSD disklabel, usually used to subdivide MBR partitions. -.Po -This scheme can also be used as the sole partitioning method, without -an MBR. -Partition editing tools from other operating systems often do not -understand the bare disklabel partition layout, so this is sometimes -called -.Dq dangerously dedicated . -.Pc -Requires the -.Cm GEOM_PART_BSD -kernel option. -.It Cm BSD64 -64-bit implementation of BSD disklabel used in DragonFlyBSD to subdivide MBR -or GPT partitions. -Requires the -.Cm GEOM_PART_BSD64 -kernel option. -.It Cm LDM -The Logical Disk Manager is an implementation of volume manager for -Microsoft Windows NT. -Requires the -.Cd GEOM_PART_LDM -kernel option. -.It Cm GPT -GUID Partition Table is used on Intel-based Macintosh computers and -gradually replacing MBR on most PCs and other systems. -Requires the -.Cm GEOM_PART_GPT -kernel option. -.It Cm MBR -Master Boot Record is used on PCs and removable media. -Requires the -.Cm GEOM_PART_MBR -kernel option. -The -.Cm GEOM_PART_EBR -option adds support for the Extended Boot Record (EBR), -which is used to define a logical partition. -The -.Cm GEOM_PART_EBR_COMPAT -option enables backward compatibility for partition names -in the EBR scheme. -It also prevents any type of actions on such partitions. -.It Cm VTOC8 -Sun's SMI Volume Table Of Contents, used by -.Tn SPARC64 -and -.Tn UltraSPARC -computers. -Requires the -.Cm GEOM_PART_VTOC8 -kernel option. -.El -.Sh PARTITION TYPES -Partition types are identified on disk by particular strings or magic -values. -The -.Nm -utility uses symbolic names for common partition types so the user -does not need to know these values or other details of the partitioning -scheme in question. -The -.Nm -utility also allows the user to specify scheme-specific partition types -for partition types that do not have symbolic names. -Symbolic names currently understood and used by -.Fx -are: -.Bl -tag -width ".Cm dragonfly-disklabel64" -.It Cm apple-boot -The system partition dedicated to storing boot loaders on some Apple -systems. -The scheme-specific types are -.Qq Li "!171" -for MBR, -.Qq Li "!Apple_Bootstrap" -for APM, and -.Qq Li "!426f6f74-0000-11aa-aa11-00306543ecac" -for GPT. -.It Cm bios-boot -The system partition dedicated to second stage of the boot loader program. -Usually it is used by the GRUB 2 loader for GPT partitioning schemes. -The scheme-specific type is -.Qq Li "!21686148-6449-6E6F-744E-656564454649" . -.It Cm efi -The system partition for computers that use the Extensible Firmware -Interface (EFI). -In such cases, the GPT partitioning scheme is used and the -actual partition type for the system partition can also be specified as -.Qq Li "!c12a7328-f81f-11d2-ba4b-00a0c93ec93b" . -.It Cm freebsd -A -.Fx -partition subdivided into filesystems with a -.Bx -disklabel. -This is a legacy partition type and should not be used for the APM -or GPT schemes. -The scheme-specific types are -.Qq Li "!165" -for MBR, -.Qq Li "!FreeBSD" -for APM, and -.Qq Li "!516e7cb4-6ecf-11d6-8ff8-00022d09712b" -for GPT. -.It Cm freebsd-boot -A -.Fx -partition dedicated to bootstrap code. -The scheme-specific type is -.Qq Li "!83bd6b9d-7f41-11dc-be0b-001560b84f0f" -for GPT. -.It Cm freebsd-swap -A -.Fx -partition dedicated to swap space. -The scheme-specific types are -.Qq Li "!FreeBSD-swap" -for APM, -.Qq Li "!516e7cb5-6ecf-11d6-8ff8-00022d09712b" -for GPT, and tag 0x0901 for VTOC8. -.It Cm freebsd-ufs -A -.Fx -partition that contains a UFS or UFS2 filesystem. -The scheme-specific types are -.Qq Li "!FreeBSD-UFS" -for APM, -.Qq Li "!516e7cb6-6ecf-11d6-8ff8-00022d09712b" -for GPT, and tag 0x0902 for VTOC8. -.It Cm freebsd-vinum -A -.Fx -partition that contains a Vinum volume. -The scheme-specific types are -.Qq Li "!FreeBSD-Vinum" -for APM, -.Qq Li "!516e7cb8-6ecf-11d6-8ff8-00022d09712b" -for GPT, and tag 0x0903 for VTOC8. -.It Cm freebsd-zfs -A -.Fx -partition that contains a ZFS volume. -The scheme-specific types are -.Qq Li "!FreeBSD-ZFS" -for APM, -.Qq Li "!516e7cba-6ecf-11d6-8ff8-00022d09712b" -for GPT, and 0x0904 for VTOC8. -.El -.Pp -Another symbolic names that can be used with -.Cm gpart -utility are: -.Bl -tag -width ".Cm dragonfly-disklabel64" -.It Cm apple-apfs -An Apple macOS partition used for the Apple file system, APFS. -.It Cm apple-core-storage -An Apple Mac OS X partition used by logical volume manager known as -Core Storage. -The scheme-specific type is -.Qq Li "!53746f72-6167-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-hfs -An Apple Mac OS X partition that contains a HFS or HFS+ filesystem. -The scheme-specific types are -.Qq Li "!175" -for MBR, -.Qq Li "!Apple_HFS" -for APM and -.Qq Li "!48465300-0000-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-label -An Apple Mac OS X partition dedicated to partition metadata that descibes -disk device. -The scheme-specific type is -.Qq Li "!4c616265-6c00-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-raid -An Apple Mac OS X partition used in a software RAID configuration. -The scheme-specific type is -.Qq Li "!52414944-0000-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-raid-offline -An Apple Mac OS X partition used in a software RAID configuration. -The scheme-specific type is -.Qq Li "!52414944-5f4f-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-tv-recovery -An Apple Mac OS X partition used by Apple TV. -The scheme-specific type is -.Qq Li "!5265636f-7665-11aa-aa11-00306543ecac" -for GPT. -.It Cm apple-ufs -An Apple Mac OS X partition that contains a UFS filesystem. -The scheme-specific types are -.Qq Li "!168" -for MBR, -.Qq Li "!Apple_UNIX_SVR2" -for APM and -.Qq Li "!55465300-0000-11aa-aa11-00306543ecac" -for GPT. -.It Cm dragonfly-label32 -A DragonFlyBSD partition subdivided into filesystems with a -.Bx -disklabel. -The scheme-specific type is -.Qq Li "!9d087404-1ca5-11dc-8817-01301bb8a9f5" -for GPT. -.It Cm dragonfly-label64 -A DragonFlyBSD partition subdivided into filesystems with a -disklabel64. -The scheme-specific type is -.Qq Li "!3d48ce54-1d16-11dc-8696-01301bb8a9f5" -for GPT. -.It Cm dragonfly-legacy -A legacy partition type used in DragonFlyBSD. -The scheme-specific type is -.Qq Li "!bd215ab2-1d16-11dc-8696-01301bb8a9f5" -for GPT. -.It Cm dragonfly-ccd -A DragonFlyBSD partition used with Concatenated Disk driver. -The scheme-specific type is -.Qq Li "!dbd5211b-1ca5-11dc-8817-01301bb8a9f5" -for GPT. -.It Cm dragonfly-hammer -A DragonFlyBSD partition that contains a Hammer filesystem. -The scheme-specific type is -.Qq Li "!61dc63ac-6e38-11dc-8513-01301bb8a9f5" -for GPT. -.It Cm dragonfly-hammer2 -A DragonFlyBSD partition that contains a Hammer2 filesystem. -The scheme-specific type is -.Qq Li "!5cbb9ad1-862d-11dc-a94d-01301bb8a9f5" -for GPT. -.It Cm dragonfly-swap -A DragonFlyBSD partition dedicated to swap space. -The scheme-specific type is -.Qq Li "!9d58fdbd-1ca5-11dc-8817-01301bb8a9f5" -for GPT. -.It Cm dragonfly-ufs -A DragonFlyBSD partition that contains an UFS1 filesystem. -The scheme-specific type is -.Qq Li "!9d94ce7c-1ca5-11dc-8817-01301bb8a9f5" -for GPT. -.It Cm dragonfly-vinum -A DragonFlyBSD partition used with Logical Volume Manager. -The scheme-specific type is -.Qq Li "!9dd4478f-1ca5-11dc-8817-01301bb8a9f5" -for GPT. -.It Cm ebr -A partition subdivided into filesystems with a EBR. -The scheme-specific type is -.Qq Li "!5" -for MBR. -.It Cm fat16 -A partition that contains a FAT16 filesystem. -The scheme-specific type is -.Qq Li "!6" -for MBR. -.It Cm fat32 -A partition that contains a FAT32 filesystem. -The scheme-specific type is -.Qq Li "!11" -for MBR. -.It Cm linux-data -A Linux partition that contains some filesystem with data. -The scheme-specific types are -.Qq Li "!131" -for MBR and -.Qq Li "!0fc63daf-8483-4772-8e79-3d69d8477de4" -for GPT. -.It Cm linux-lvm -A Linux partition dedicated to Logical Volume Manager. -The scheme-specific types are -.Qq Li "!142" -for MBR and -.Qq Li "!e6d6d379-f507-44c2-a23c-238f2a3df928" -for GPT. -.It Cm linux-raid -A Linux partition used in a software RAID configuration. -The scheme-specific types are -.Qq Li "!253" -for MBR and -.Qq Li "!a19d880f-05fc-4d3b-a006-743f0f84911e" -for GPT. -.It Cm linux-swap -A Linux partition dedicated to swap space. -The scheme-specific types are -.Qq Li "!130" -for MBR and -.Qq Li "!0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" -for GPT. -.It Cm mbr -A partition that is sub-partitioned by a Master Boot Record (MBR). -This type is known as -.Qq Li "!024dee41-33e7-11d3-9d69-0008c781f39f" -by GPT. -.It Cm ms-basic-data -A basic data partition (BDP) for Microsoft operating systems. -In the GPT this type is the equivalent to partition types -.Cm fat16 , fat32 -and -.Cm ntfs -in MBR. -The scheme-specific type is -.Qq Li "!ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" -for GPT. -.It Cm ms-ldm-data -A partition that contains Logical Disk Manager (LDM) volumes. -The scheme-specific types are -.Qq Li "!66" -for MBR, -.Qq Li "!af9b60a0-1431-4f62-bc68-3311714a69ad" -for GPT. -.It Cm ms-ldm-metadata -A partition that contains Logical Disk Manager (LDM) database. -The scheme-specific type is -.Qq Li "!5808c8aa-7e8f-42e0-85d2-e1e90434cfb3" -for GPT. -.It Cm netbsd-ccd -A NetBSD partition used with Concatenated Disk driver. -The scheme-specific type is -.Qq Li "!2db519c4-b10f-11dc-b99b-0019d1879648" -for GPT. -.It Cm netbsd-cgd -An encrypted NetBSD partition. -The scheme-specific type is -.Qq Li "!2db519ec-b10f-11dc-b99b-0019d1879648" -for GPT. -.It Cm netbsd-ffs -A NetBSD partition that contains an UFS filesystem. -The scheme-specific type is -.Qq Li "!49f48d5a-b10e-11dc-b99b-0019d1879648" -for GPT. -.It Cm netbsd-lfs -A NetBSD partition that contains an LFS filesystem. -The scheme-specific type is -.Qq Li "!49f48d82-b10e-11dc-b99b-0019d1879648" -for GPT. -.It Cm netbsd-raid -A NetBSD partition used in a software RAID configuration. -The scheme-specific type is -.Qq Li "!49f48daa-b10e-11dc-b99b-0019d1879648" -for GPT. -.It Cm netbsd-swap -A NetBSD partition dedicated to swap space. -The scheme-specific type is -.Qq Li "!49f48d32-b10e-11dc-b99b-0019d1879648" -for GPT. -.It Cm ntfs -A partition that contains a NTFS or exFAT filesystem. -The scheme-specific type is -.Qq Li "!7" -for MBR. -.It Cm prep-boot -The system partition dedicated to storing boot loaders on some PowerPC systems, -notably those made by IBM. -The scheme-specific types are -.Qq Li "!65" -for MBR and -.Qq Li "!0x9e1a2d38-c612-4316-aa26-8b49521e5a8b" -for GPT. -.It Cm vmware-vmfs -A partition that contains a VMware File System (VMFS). -The scheme-specific types are -.Qq Li "!251" -for MBR and -.Qq Li "!aa31e02a-400f-11db-9590-000c2911d1b8" -for GPT. -.It Cm vmware-vmkdiag -A partition that contains a VMware diagostic filesystem. -The scheme-specific types are -.Qq Li "!252" -for MBR and -.Qq Li "!9d275380-40ad-11db-bf97-000c2911d1b8" -for GPT. -.It Cm vmware-reserved -A VMware reserved partition. -The scheme-specific type is -.Qq Li "!9198effc-31c0-11db-8f-78-000c2911d1b8" -for GPT. -.It Cm vmware-vsanhdr -A partition claimed by VMware VSAN. -The scheme-specific type is -.Qq Li "!381cfccc-7288-11e0-92ee-000c2911d0b2" -for GPT. -.El -.Sh ATTRIBUTES -The scheme-specific attributes for EBR: -.Bl -tag -width ".Cm active" -.It Cm active -.El -.Pp -The scheme-specific attributes for GPT: -.Bl -tag -width ".Cm bootfailed" -.It Cm bootme -When set, the -.Nm gptboot -stage 1 boot loader will try to boot the system from this partition. -Multiple partitions can be marked with the -.Cm bootme -attribute. -See -.Xr gptboot 8 -for more details. -.It Cm bootonce -Setting this attribute automatically sets the -.Cm bootme -attribute. -When set, the -.Nm gptboot -stage 1 boot loader will try to boot the system from this partition only once. -Multiple partitions can be marked with the -.Cm bootonce -and -.Cm bootme -attribute pairs. -See -.Xr gptboot 8 -for more details. -.It Cm bootfailed -This attribute should not be manually managed. -It is managed by the -.Nm gptboot -stage 1 boot loader and the -.Pa /etc/rc.d/gptboot -start-up script. -See -.Xr gptboot 8 -for more details. -.It Cm lenovofix -Setting this attribute overwrites the Protective MBR with a new one where -the 0xee partition is the second, rather than the first record. -This resolves a BIOS compatibility issue with some Lenovo models including the -X220, T420, and T520, allowing them to boot from GPT partitioned disks -without using EFI. -.El -.Pp -The scheme-specific attributes for MBR: -.Bl -tag -width ".Cm active" -.It Cm active -.El -.Sh BOOTSTRAPPING -.Fx -supports several partitioning schemes and each scheme uses different -bootstrap code. -The bootstrap code is located in a specific disk area for each partitioning -scheme, and may vary in size for different schemes. -.Pp -Bootstrap code can be separated into two types. -The first type is embedded in the partitioning scheme's metadata, while the -second type is located on a specific partition. -Embedding bootstrap code should only be done with the -.Cm gpart bootcode -command with the -.Fl b Ar bootcode -option. -The GEOM PART class knows how to safely embed bootstrap code into -specific partitioning scheme metadata without causing any damage. -.Pp -The Master Boot Record (MBR) uses a 512-byte bootstrap code image, embedded -into the partition table's metadata area. -There are two variants of this bootstrap code: -.Pa /boot/mbr -and -.Pa /boot/boot0 . -.Pa /boot/mbr -searches for a partition with the -.Cm active -attribute (see the -.Sx ATTRIBUTES -section) in the partition table. -Then it runs next bootstrap stage. -The -.Pa /boot/boot0 -image contains a boot manager with some additional interactive functions -for multi-booting from a user-selected partition. -.Pp -A BSD disklabel is usually created inside an MBR partition (slice) -with type -.Cm freebsd -(see the -.Sx "PARTITION TYPES" -section). -It uses 8 KB size bootstrap code image -.Pa /boot/boot , -embedded into the partition table's metadata area. -.Pp -Both types of bootstrap code are used to boot from the GUID Partition Table. -First, a protective MBR is embedded into the first disk sector from the -.Pa /boot/pmbr -image. -It searches through the GPT for a -.Cm freebsd-boot -partition (see the -.Sx "PARTITION TYPES" -section) and runs the next bootstrap stage from it. -The -.Cm freebsd-boot -partition should be smaller than 545 KB. -It can be located either before or after other -.Fx -partitions on the disk. -There are two variants of bootstrap code to write to this partition: -.Pa /boot/gptboot -and -.Pa /boot/gptzfsboot . -.Pp -.Pa /boot/gptboot -is used to boot from UFS partitions. -.Cm gptboot -searches through -.Cm freebsd-ufs -partitions in the GPT and selects one to boot based on the -.Cm bootonce -and -.Cm bootme -attributes. -If neither attribute is found, -.Pa /boot/gptboot -boots from the first -.Cm freebsd-ufs -partition. -.Pa /boot/loader -.Pq the third bootstrap stage -is loaded from the first partition that matches these conditions. -See -.Xr gptboot 8 -for more information. -.Pp -.Pa /boot/gptzfsboot -is used to boot from ZFS. -It searches through the GPT for -.Cm freebsd-zfs -partitions, trying to detect ZFS pools. -After all pools are detected, -.Pa /boot/zfsloader -is started from the first one found. -.Pp -The VTOC8 scheme does not support embedding bootstrap code. -Instead, the 8 KBytes bootstrap code image -.Pa /boot/boot1 -should be written with the -.Cm gpart bootcode -command with the -.Fl p Ar bootcode -option to all sufficiently large VTOC8 partitions. -To do this the -.Fl i Ar index -option could be omitted. -.Pp -The APM scheme also does not support embedding bootstrap code. -Instead, the 800 KBytes bootstrap code image -.Pa /boot/boot1.hfs -should be written with the -.Cm gpart bootcode -command to a partition of type -.Cm apple-boot , -which should also be 800 KB in size. -.Sh OPERATIONAL FLAGS -Actions other than the -.Cm commit -and -.Cm undo -actions take an optional -.Fl f Ar flags -option. -This option is used to specify action-specific operational flags. -By default, the -.Nm -utility defines the -.Ql C -flag so that the action is immediately -committed. -The user can specify -.Dq Fl f Cm x -to have the action result in a pending change that can later, with -other pending changes, be committed as a single compound change with -the -.Cm commit -action or reverted with the -.Cm undo -action. -.Sh RECOVERING -The GEOM PART class supports recovering of partition tables only for GPT. -The GPT primary metadata is stored at the beginning of the device. -For redundancy, a secondary -.Pq backup -copy of the metadata is stored at the end of the device. -As a result of having two copies, some corruption of metadata is not -fatal to the working of GPT. -When the kernel detects corrupt metadata, it marks this table as corrupt -and reports the problem. -.Cm destroy -and -.Cm recover -are the only operations allowed on corrupt tables. -.Pp -If one GPT header appears to be corrupt but the other copy remains intact, -the kernel will log the following: -.Bd -literal -offset indent -GEOM: provider: the primary GPT table is corrupt or invalid. -GEOM: provider: using the secondary instead -- recovery strongly advised. -.Ed -.Pp -or -.Bd -literal -offset indent -GEOM: provider: the secondary GPT table is corrupt or invalid. -GEOM: provider: using the primary only -- recovery suggested. -.Ed -.Pp -Also -.Nm -commands such as -.Cm show , status -and -.Cm list -will report about corrupt tables. -.Pp -If the size of the device has changed (e.g.,\& volume expansion) the -secondary GPT header will no longer be located in the last sector. -This is not a metadata corruption, but it is dangerous because any -corruption of the primary GPT will lead to loss of the partition table. -This problem is reported by the kernel with the message: -.Bd -literal -offset indent -GEOM: provider: the secondary GPT header is not in the last LBA. -.Ed -.Pp -This situation can be recovered with the -.Cm recover -command. -This command reconstructs the corrupt metadata using known valid -metadata and relocates the secondary GPT to the end of the device. -.Pp -.Em NOTE : -The GEOM PART class can detect the same partition table visible through -different GEOM providers, and some of them will be marked as corrupt. -Be careful when choosing a provider for recovery. -If you choose incorrectly you can destroy the metadata of another GEOM class, -e.g.,\& GEOM MIRROR or GEOM LABEL. -.Sh SYSCTL VARIABLES -The following -.Xr sysctl 8 -variables can be used to control the behavior of the -.Nm PART -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.part.auto_resize: No 1 -This variable controls automatic resize behavior of -.Nm -GEOM class. -When this variable is enable and new size of provider is detected, the schema -metadata is resized but all changes are not saved to disk, until -.Cm gpart commit -is run to confirm changes. -This behavior is also reported with diagnostic message: -.Sy "GEOM_PART: (provider) was automatically resized." -.Sy "Use `gpart commit (provider)` to save changes or `gpart undo (provider)`" -.Sy "to revert them." -.It Va kern.geom.part.check_integrity : No 1 -This variable controls the behaviour of metadata integrity checks. -When integrity checks are enabled, the -.Nm PART -GEOM class verifies all generic partition parameters obtained from the -disk metadata. -If some inconsistency is detected, the partition table will be -rejected with a diagnostic message: -.Sy "GEOM_PART: Integrity check failed (provider, scheme)" . -.It Va kern.geom.part.ldm.debug : No 0 -Debug level of the Logical Disk Manager (LDM) module. -This can be set to a number between 0 and 2 inclusive. -If set to 0 minimal debug information is printed, -and if set to 2 the maximum amount of debug information is printed. -.It Va kern.geom.part.ldm.show_mirrors : No 0 -This variable controls how the Logical Disk Manager (LDM) module handles -mirrored volumes. -By default mirrored volumes are shown as partitions with type -.Cm ms-ldm-data -(see the -.Sx "PARTITION TYPES" -section). -If this variable set to 1 each component of the mirrored volume will be -present as independent partition. -.Em NOTE : -This may break a mirrored volume and lead to data damage. -.It Va kern.geom.part.mbr.enforce_chs : No 0 -Specify how the Master Boot Record (MBR) module does alignment. -If this variable is set to a non-zero value, the module will automatically -recalculate the user-specified offset and size for alignment with the CHS -geometry. -Otherwise the values will be left unchanged. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -The examples below assume that the disk's logical block size is 512 -bytes, regardless of its physical block size. -.Ss GPT -In this example, we will format -.Pa ada0 -with the GPT scheme and create boot, swap and root partitions. -First, we need to create the partition table: -.Bd -literal -offset indent -/sbin/gpart create -s GPT ada0 -.Ed -.Pp -Next, we install a protective MBR with the first-stage bootstrap code. -The protective MBR lists a single, bootable partition spanning the -entire disk, thus allowing non-GPT-aware BIOSes to boot from the disk -and preventing tools which do not understand the GPT scheme from -considering the disk to be unformatted. -.Bd -literal -offset indent -/sbin/gpart bootcode -b /boot/pmbr ada0 -.Ed -.Pp -We then create a dedicated -.Cm freebsd-boot -partition to hold the second-stage boot loader, which will load the -.Fx -kernel and modules from a UFS or ZFS filesystem. -This partition must be larger than the bootstrap code -.Po -either -.Pa /boot/gptboot -for UFS or -.Pa /boot/gptzfsboot -for ZFS -.Pc , -but smaller than 545 kB since the first-stage loader will load the -entire partition into memory during boot, regardless of how much data -it actually contains. -We create a 472-block (236 kB) boot partition at offset 40, which is -the size of the partition table (34 blocks or 17 kB) rounded up to the -nearest 4 kB boundary. -.Bd -literal -offset indent -/sbin/gpart add -b 40 -s 472 -t freebsd-boot ada0 -/sbin/gpart bootcode -p /boot/gptboot -i 1 ada0 -.Ed -.Pp -We now create a 4 GB swap partition at the first available offset, -which is 40 + 472 = 512 blocks (256 kB). -.Bd -literal -offset indent -/sbin/gpart add -s 4G -t freebsd-swap ada0 -.Ed -.Pp -Aligning the swap partition and all subsequent partitions on a 256 kB -boundary ensures optimal performance on a wide range of media, from -plain old disks with 512-byte blocks, through modern -.Dq advanced format -disks with 4096-byte physical blocks, to RAID volumes with stripe -sizes of up to 256 kB. -.Pp -Finally, we create and format an 8 GB -.Cm freebsd-ufs -partition for the root filesystem, leaving the rest of the slice free -for additional filesystems: -.Bd -literal -offset indent -/sbin/gpart add -s 8G -t freebsd-ufs ada0 -/sbin/newfs -Uj /dev/ada0p3 -.Ed -.Ss MBR -In this example, we will format -.Pa ada0 -with the MBR scheme and create a single partition which we subdivide -using a traditional -.Bx -disklabel. -.Pp -First, we create the partition table and a single 64 GB partition, -then we mark that partition active (bootable) and install the -first-stage boot loader: -.Bd -literal -offset indent -/sbin/gpart create -s MBR ada0 -/sbin/gpart add -t freebsd -s 64G ada0 -/sbin/gpart set -a active -i 1 ada0 -/sbin/gpart bootcode -b /boot/boot0 ada0 -.Ed -.Pp -Next, we create a disklabel in that partition -.Po -.Dq slice -in disklabel terminology -.Pc -with room for up to 20 partitions: -.Bd -literal -offset indent -/sbin/gpart create -s BSD -n 20 ada0s1 -.Ed -.Pp -We then create an 8 GB root partition and a 4 GB swap partition: -.Bd -literal -offset indent -/sbin/gpart add -t freebsd-ufs -s 8G ada0s1 -/sbin/gpart add -t freebsd-swap -s 4G ada0s1 -.Ed -.Pp -Finally, we install the appropriate boot loader for the -.Bx -label: -.Bd -literal -offset indent -/sbin/gpart bootcode -b /boot/boot ada0s1 -.Ed -.Ss VTOC8 -.Pp -Create a VTOC8 scheme on -.Pa da0 : -.Bd -literal -offset indent -/sbin/gpart create -s VTOC8 da0 -.Ed -.Pp -Create a 512MB-sized -.Cm freebsd-ufs -partition to contain a UFS filesystem from which the system can boot. -.Bd -literal -offset indent -/sbin/gpart add -s 512M -t freebsd-ufs da0 -.Ed -.Pp -Create a 15GB-sized -.Cm freebsd-ufs -partition to contain a UFS filesystem and aligned on 4KB boundaries: -.Bd -literal -offset indent -/sbin/gpart add -s 15G -t freebsd-ufs -a 4k da0 -.Ed -.Pp -After creating all required partitions, embed bootstrap code into them: -.Bd -literal -offset indent -/sbin/gpart bootcode -p /boot/boot1 da0 -.Ed -.Ss Deleting Partitions and Destroying the Partitioning Scheme -If a -.Em "Device busy" -error is shown when trying to destroy a partition table, remember that -all of the partitions must be deleted first with the -.Cm delete -action. -In this example, -.Pa da0 -has three partitions: -.Bd -literal -offset indent -/sbin/gpart delete -i 3 da0 -/sbin/gpart delete -i 2 da0 -/sbin/gpart delete -i 1 da0 -/sbin/gpart destroy da0 -.Ed -.Pp -Rather than deleting each partition and then destroying the partitioning -scheme, the -.Fl F -option can be given with -.Cm destroy -to delete all of the partitions before destroying the partitioning scheme. -This is equivalent to the previous example: -.Bd -literal -offset indent -/sbin/gpart destroy -F da0 -.Ed -.Ss Backup and Restore -.Pp -Create a backup of the partition table from -.Pa da0 : -.Bd -literal -offset indent -/sbin/gpart backup da0 > da0.backup -.Ed -.Pp -Restore the partition table from the backup to -.Pa da0 : -.Bd -literal -offset indent -/sbin/gpart restore -l da0 < /mnt/da0.backup -.Ed -.Pp -Clone the partition table from -.Pa ada0 -to -.Pa ada1 -and -.Pa ada2 : -.Bd -literal -offset indent -/sbin/gpart backup ada0 | /sbin/gpart restore -F ada1 ada2 -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr boot0cfg 8 , -.Xr geom 8 , -.Xr gptboot 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 7.0 . -.Sh AUTHORS -.An Marcel Moolenaar Aq Mt marcel@FreeBSD.org Index: sbin/geom/class/raid/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/raid/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= raid - -LIBADD= md - -.include Index: sbin/geom/class/raid/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/raid/Makefile.depend @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libmd \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/raid/geom_raid.c =================================================================== --- /dev/null +++ sbin/geom/class/raid/geom_raid.c @@ -1,94 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2010 Alexander Motin - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_RAID_VERSION; - -struct g_command class_commands[] = { - { "label", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'o', "fmtopt", G_VAL_OPTIONAL, G_TYPE_STRING }, - { 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-fv] [-o fmtopt] [-S size] [-s stripsize] format label level prov ..." - }, - { "add", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - { 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - { 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-fv] [-S size] [-s stripsize] name label level" - }, - { "delete", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name [label|num]" - }, - { "insert", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov ..." - }, - { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov ..." - }, - { "fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov ..." - }, - { "stop", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name" - }, - G_CMD_SENTINEL -}; - Index: sbin/geom/class/raid/graid.8 =================================================================== --- /dev/null +++ sbin/geom/class/raid/graid.8 @@ -1,321 +0,0 @@ -.\" Copyright (c) 2010 Alexander Motin -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd April 4, 2013 -.Dt GRAID 8 -.Os -.Sh NAME -.Nm graid -.Nd "control utility for software RAID devices" -.Sh SYNOPSIS -.Nm -.Cm label -.Op Fl f -.Op Fl o Ar fmtopt -.Op Fl S Ar size -.Op Fl s Ar strip -.Ar format -.Ar label -.Ar level -.Ar prov ... -.Nm -.Cm add -.Op Fl f -.Op Fl S Ar size -.Op Fl s Ar strip -.Ar name -.Ar label -.Ar level -.Nm -.Cm delete -.Op Fl f -.Ar name -.Op Ar label | Ar num -.Nm -.Cm insert -.Ar name -.Ar prov ... -.Nm -.Cm remove -.Ar name -.Ar prov ... -.Nm -.Cm fail -.Ar name -.Ar prov ... -.Nm -.Cm stop -.Op Fl fv -.Ar name ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used to manage software RAID configurations, supported by the -GEOM RAID class. -GEOM RAID class uses on-disk metadata to provide access to software-RAID -volumes defined by different RAID BIOSes. -Depending on RAID BIOS type and its metadata format, different subsets of -configurations and features are supported. -To allow booting from RAID volume, the metadata format should match the -RAID BIOS type and its capabilities. -To guarantee that these match, it is recommended to create volumes via the -RAID BIOS interface, while experienced users are free to do it using this -utility. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm destroy" -.It Cm label -Create an array with single volume. -The -.Ar format -argument specifies the on-disk metadata format to use for this array, -such as "Intel". -The -.Ar label -argument specifies the label of the created volume. -The -.Ar level -argument specifies the RAID level of the created volume, such as: -"RAID0", "RAID1", etc. -The subsequent list enumerates providers to use as array components. -The special name "NONE" can be used to reserve space for absent disks. -The order of components can be important, depending on specific RAID level -and metadata format. -.Pp -Additional options include: -.Bl -tag -width ".Fl s Ar strip" -.It Fl f -Enforce specified configuration creation if it is officially unsupported, -but technically can be created. -.It Fl o Ar fmtopt -Specifies metadata format options. -.It Fl S Ar size -Use -.Ar size -bytes on each component for this volume. -Should be used if several volumes per array are planned, or if smaller -components going to be inserted later. -Defaults to size of the smallest component. -.It Fl s Ar strip -Specifies strip size in bytes. -Defaults to 131072. -.El -.It Cm add -Create another volume on the existing array. -The -.Ar name -argument is the name of the existing array, reported by label command. -The rest of arguments are the same as for the label command. -.It Cm delete -Delete volume(s) from the existing array. -When the last volume is deleted, the array is also deleted and its metadata -erased. -The -.Ar name -argument is the name of existing array. -Optional -.Ar label -or -.Ar num -arguments allow specifying volume for deletion. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Delete volume(s) even if it is still open. -.El -.It Cm insert -Insert specified provider(s) into specified array instead of the first missing -or failed components. -If there are no such components, mark disk(s) as spare. -.It Cm remove -Remove the specified provider(s) from the specified array and erase metadata. -If there are spare disks present, the removed disk(s) will be replaced by -spares. -.It Cm fail -Mark the given disks(s) as failed, removing from active use unless absolutely -necessary due to exhausted redundancy. -If there are spare disks present - failed disk(s) will be replaced with one -of them. -.It Cm stop -Stop the given array. -The metadata will not be erased. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Stop the given array even if some of its volumes are opened. -.El -.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 SUPPORTED METADATA FORMATS -The GEOM RAID class follows a modular design, allowing different metadata -formats to be used. -Support is currently implemented for the following formats: -.Bl -tag -width "Intel" -.It DDF -The format defined by the SNIA Common RAID Disk Data Format v2.0 specification. -Used by some Adaptec RAID BIOSes and some hardware RAID controllers. -Because of high format flexibility different implementations support -different set of features and have different on-disk metadata layouts. -To provide compatibility, the GEOM RAID class mimics capabilities -of the first detected DDF array. -Respecting that, it may support different number of disks per volume, -volumes per array, partitions per disk, etc. -The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks), -RAID1E (3+ disks), RAID3 (3+ disks), RAID4 (3+ disks), RAID5 (3+ disks), -RAID5E (4+ disks), RAID5EE (4+ disks), RAID5R (3+ disks), RAID6 (4+ disks), -RAIDMDF (4+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks). -.Pp -Format supports two options "BE" and "LE", that mean big-endian byte order -defined by specification (default) and little-endian used by some Adaptec -controllers. -.It Intel -The format used by Intel RAID BIOS. -Supports up to two volumes per array. -Supports configurations: RAID0 (2+ disks), RAID1 (2 disks), -RAID5 (3+ disks), RAID10 (4 disks). -Configurations not supported by Intel RAID BIOS, but enforceable on your own -risk: RAID1 (3+ disks), RAID1E (3+ disks), RAID10 (6+ disks). -.It JMicron -The format used by JMicron RAID BIOS. -Supports one volume per array. -Supports configurations: RAID0 (2+ disks), RAID1 (2 disks), -RAID10 (4 disks), CONCAT (2+ disks). -Configurations not supported by JMicron RAID BIOS, but enforceable on your own -risk: RAID1 (3+ disks), RAID1E (3+ disks), RAID10 (6+ disks), RAID5 (3+ disks). -.It NVIDIA -The format used by NVIDIA MediaShield RAID BIOS. -Supports one volume per array. -Supports configurations: RAID0 (2+ disks), RAID1 (2 disks), -RAID5 (3+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks). -Configurations not supported by NVIDIA MediaShield RAID BIOS, but enforceable -on your own risk: RAID1 (3+ disks). -.It Promise -The format used by Promise and AMD/ATI RAID BIOSes. -Supports multiple volumes per array. -Each disk can be split to be used by up to two arbitrary volumes. -Supports configurations: RAID0 (2+ disks), RAID1 (2 disks), -RAID5 (3+ disks), RAID10 (4 disks), SINGLE (1 disk), CONCAT (2+ disks). -Configurations not supported by RAID BIOSes, but enforceable on your -own risk: RAID1 (3+ disks), RAID10 (6+ disks). -.It SiI -The format used by SiliconImage RAID BIOS. -Supports one volume per array. -Supports configurations: RAID0 (2+ disks), RAID1 (2 disks), -RAID5 (3+ disks), RAID10 (4 disks), SINGLE (1 disk), CONCAT (2+ disks). -Configurations not supported by SiliconImage RAID BIOS, but enforceable on your -own risk: RAID1 (3+ disks), RAID10 (6+ disks). -.El -.Sh SUPPORTED RAID LEVELS -The GEOM RAID class follows a modular design, allowing different RAID levels -to be used. -Full support for the following RAID levels is currently implemented: -RAID0, RAID1, RAID1E, RAID10, SINGLE, CONCAT. -The following RAID levels supported as read-only for volumes in optimal -state (without using redundancy): RAID4, RAID5, RAID5E, RAID5EE, RAID5R, -RAID6, RAIDMDF. -.Sh RAID LEVEL MIGRATION -The GEOM RAID class has no support for RAID level migration, allowed by some -metadata formats. -If you started migration using BIOS or in some other way, make sure to -complete it there. -Do not run GEOM RAID class on migrating volumes under pain of possible data -corruption! -.Sh 2TiB BARRIERS -NVIDIA metadata format does not support volumes above 2TiB. -.Sh SYSCTL VARIABLES -The following -.Xr sysctl 8 -variable can be used to control the behavior of the -.Nm RAID -GEOM class. -.Bl -tag -width indent -.It Va kern.geom.raid.aggressive_spare : No 0 -Use any disks without metadata connected to controllers of the vendor -matching to volume metadata format as spare. -Use it with much care to not lose data if connecting unrelated disk! -.It Va kern.geom.raid.clean_time : No 5 -Mark volume as clean when idle for the specified number of seconds. -.It Va kern.geom.raid.debug : No 0 -Debug level of the -.Nm RAID -GEOM class. -.It Va kern.geom.raid.enable : No 1 -Enable on-disk metadata taste. -.It Va kern.geom.raid.idle_threshold : No 1000000 -Time in microseconds to consider a volume idle for rebuild purposes. -.It Va kern.geom.raid.name_format : No 0 -Providers name format: 0 -- raid/r{num}, 1 -- raid/{label}. -.It Va kern.geom.raid.read_err_thresh : No 10 -Number of read errors equated to disk failure. -Write errors are always considered as disk failures. -.It Va kern.geom.raid.start_timeout : No 30 -Time to wait for missing array components on startup. -.It Va kern.geom.raid. Ns Ar X Ns Va .enable : No 1 -Enable taste for specific metadata or transformation module. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and non-zero if the command fails. -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 , -.Xr gvinum 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 9.0 . -.Sh AUTHORS -.An Alexander Motin Aq Mt mav@FreeBSD.org -.An M. Warner Losh Aq Mt imp@FreeBSD.org Index: sbin/geom/class/raid3/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/raid3/Makefile @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= raid3 - -LIBADD= md - -.include Index: sbin/geom/class/raid3/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/raid3/Makefile.depend @@ -1,20 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - lib/libmd \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/raid3/geom_raid3.c =================================================================== --- /dev/null +++ sbin/geom/class/raid3/geom_raid3.c @@ -1,338 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2005 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_RAID3_VERSION; - -static void raid3_main(struct gctl_req *req, unsigned f); -static void raid3_clear(struct gctl_req *req); -static void raid3_dump(struct gctl_req *req); -static void raid3_label(struct gctl_req *req); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "configure", G_FLAG_VERBOSE, NULL, - { - { 'a', "autosync", NULL, G_TYPE_BOOL }, - { '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 }, - { 'r', "round_robin", NULL, G_TYPE_BOOL }, - { 'R', "noround_robin", NULL, G_TYPE_BOOL }, - { 'w', "verify", NULL, G_TYPE_BOOL }, - { 'W', "noverify", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-adfFhnrRvwW] name" - }, - { "dump", 0, raid3_main, G_NULL_OPTS, - "prov ..." - }, - { "insert", G_FLAG_VERBOSE, NULL, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL }, - { 'n', "number", G_VAL_OPTIONAL, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-hv] <-n number> name prov" - }, - { "label", G_FLAG_VERBOSE, raid3_main, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL }, - { 'F', "nofailsync", NULL, G_TYPE_BOOL }, - { 'n', "noautosync", NULL, G_TYPE_BOOL }, - { 'r', "round_robin", NULL, G_TYPE_BOOL }, - { 's', "sectorsize", "0", G_TYPE_NUMBER }, - { 'w', "verify", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-hFnrvw] [-s blocksize] name prov prov prov ..." - }, - { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name prov" - }, - { "remove", G_FLAG_VERBOSE, NULL, - { - { 'n', "number", NULL, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] <-n number> 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 -raid3_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) - raid3_label(req); - else if (strcmp(name, "clear") == 0) - raid3_clear(req); - else if (strcmp(name, "dump") == 0) - raid3_dump(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static void -raid3_label(struct gctl_req *req) -{ - struct g_raid3_metadata md; - u_char sector[512]; - const char *str; - unsigned sectorsize, ssize; - off_t mediasize, msize; - int hardcode, round_robin, verify; - int error, i, nargs; - - bzero(sector, sizeof(sector)); - nargs = gctl_get_int(req, "nargs"); - if (nargs < 4) { - gctl_error(req, "Too few arguments."); - return; - } - if (bitcount32(nargs - 2) != 1) { - gctl_error(req, "Invalid number of components."); - return; - } - - strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); - md.md_version = G_RAID3_VERSION; - str = gctl_get_ascii(req, "arg0"); - strlcpy(md.md_name, str, sizeof(md.md_name)); - md.md_id = 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; - if (gctl_get_int(req, "noautosync")) - md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; - if (gctl_get_int(req, "nofailsync")) - md.md_mflags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC; - round_robin = gctl_get_int(req, "round_robin"); - if (round_robin) - md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; - verify = gctl_get_int(req, "verify"); - if (verify) - md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; - if (round_robin && verify) { - gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); - return; - } - 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 = gctl_get_intmax(req, "sectorsize"); - for (i = 1; i < nargs; i++) { - 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 * (nargs - 2); - md.md_sectorsize = sectorsize * (nargs - 2); - md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); - - if (md.md_sectorsize > MAXPHYS) { - gctl_error(req, "The blocksize is too big."); - return; - } - - /* - * 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); - msize = g_get_mediasize(str); - ssize = g_get_sectorsize(str); - if (mediasize < msize - ssize) { - fprintf(stderr, - "warning: %s: only %jd bytes from %jd bytes used.\n", - str, (intmax_t)mediasize, (intmax_t)(msize - ssize)); - } - - md.md_no = i - 1; - md.md_provsize = msize; - 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)); - } - if (verify && md.md_no == md.md_all - 1) { - /* - * In "verify" mode, force synchronization of parity - * component on start. - */ - md.md_syncid = 0; - } - raid3_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 -raid3_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_RAID3_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 -raid3_dump(struct gctl_req *req) -{ - struct g_raid3_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_RAID3_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 (raid3_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); - raid3_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/raid3/graid3.8 =================================================================== --- /dev/null +++ sbin/geom/class/raid3/graid3.8 @@ -1,257 +0,0 @@ -.\" Copyright (c) 2004-2005 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd January 15, 2012 -.Dt GRAID3 8 -.Os -.Sh NAME -.Nm graid3 -.Nd "control utility for RAID3 devices" -.Sh SYNOPSIS -.Nm -.Cm label -.Op Fl Fhnrvw -.Op Fl s Ar blocksize -.Ar name -.Ar prov prov prov ... -.Nm -.Cm clear -.Op Fl v -.Ar prov ... -.Nm -.Cm configure -.Op Fl adfFhnrRvwW -.Ar name -.Nm -.Cm rebuild -.Op Fl v -.Ar name -.Ar prov -.Nm -.Cm insert -.Op Fl hv -.Op Fl n Ar number -.Ar name -.Ar prov -.Nm -.Cm remove -.Op Fl v -.Fl n Ar number -.Ar name -.Nm -.Cm stop -.Op Fl fv -.Ar name ... -.Nm -.Cm list -.Nm -.Cm status -.Nm -.Cm load -.Nm -.Cm unload -.Sh DESCRIPTION -The -.Nm -utility is used for RAID3 array configuration. -After a device is created, all components are detected and configured -automatically. -All operations such as failure detection, stale component detection, rebuild -of stale components, etc.\& are also done automatically. -The -.Nm -utility uses on-disk metadata (the provider's last sector) to store all needed -information. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm configure" -.It Cm label -Create a RAID3 device. -The last given component will contain parity data, whilst the others -will all contain regular data. -The number of components must be equal to 3, 5, 9, 17, etc.\& (2^n + 1). -.Pp -Additional options include: -.Bl -tag -width ".Fl h" -.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 r -Use parity component for reading in round-robin fashion. -Without this option the parity component is not used at all for reading operations -when the device is in a complete state. -With this option specified random I/O read operations are even 40% faster, -but sequential reads are slower. -One cannot use this option if the -.Fl w -option is also specified. -.It Fl s -Manually specify array block size. Block size will be set equal to least -common multiple of all component's sector sizes and specified value. -Note that array sector size calculated as multiple of block size and number -of regular data components. Big values may decrease performance and compatibility, -as all I/O requests have to be multiple of sector size. -.It Fl w -Use verify reading feature. -When reading from a device in a complete state, also read data from the parity component -and verify the data by comparing XORed regular data with parity data. -If verification fails, an -.Er EIO -error is returned and the value of the -.Va kern.geom.raid3.stat.parity_mismatch -sysctl is increased. -One cannot use this option if the -.Fl r -option is also specified. -.El -.It Cm clear -Clear metadata on the given providers. -.It Cm configure -Configure the given device. -.Pp -Additional options include: -.Bl -tag -width ".Fl a" -.It Fl a -Turn on autosynchronization of stale components. -.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 r -Turn on round-robin reading. -.It Fl R -Turn off round-robin reading. -.It Fl w -Turn on verify reading. -.It Fl W -Turn off verify reading. -.El -.It Cm rebuild -Rebuild the given component forcibly. -If autosynchronization was not turned off for the given device, this command -should be unnecessary. -.It Cm insert -Add the given component to the existing array, if one of the components was -removed previously with the -.Cm remove -command or if one component is missing and will not be connected again. -If no number is given, new component will be added instead of first missed -component. -.Pp -Additional options include: -.Bl -tag -width ".Fl h" -.It Fl h -Hardcode providers' names in metadata. -.El -.It Cm remove -Remove the given component from the given array and clear metadata on it. -.It Cm stop -Stop the given arrays. -.Pp -Additional options include: -.Bl -tag -width ".Fl f" -.It Fl f -Stop the given array even if it is opened. -.El -.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 RAID3 array (with the round-robin reading feature). -Create a file system, mount it, then unmount it and stop device: -.Bd -literal -offset indent -graid3 label -v -r data da0 da1 da2 -newfs /dev/raid3/data -mount /dev/raid3/data /mnt -\&... -umount /mnt -graid3 stop data -graid3 unload -.Ed -.Pp -Create a RAID3 array, but do not use the automatic synchronization feature. -Rebuild parity component: -.Bd -literal -offset indent -graid3 label -n data da0 da1 da2 -graid3 rebuild data da2 -.Ed -.Pp -Replace one data disk with a brand new one: -.Bd -literal -offset indent -graid3 remove -n 0 data -graid3 insert -n 0 data da5 -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 , -.Xr gvinum 8 , -.Xr mount 8 , -.Xr newfs 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 section with an implementation description. -.Pp -Documentation for sysctls -.Va kern.geom.raid3.* -is missing. Index: sbin/geom/class/sched/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/sched/Makefile @@ -1,9 +0,0 @@ -# GEOM_LIBRARY_PATH -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= sched - -.include Index: sbin/geom/class/sched/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/sched/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/sched/geom_sched.c =================================================================== --- /dev/null +++ sbin/geom/class/sched/geom_sched.c @@ -1,128 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2009 Fabio Checconi - * Copyright (c) 2010 Luigi Rizzo, Universita` di Pisa - * 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. - */ - -/* - * $Id$ - * $FreeBSD$ - * - * This file implements the userspace library used by the 'geom' - * command to load and manipulate disk schedulers. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - -#define G_SCHED_VERSION 0 - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_SCHED_VERSION; - -/* - * storage for parameters used by this geom class. - * Right now only the scheduler name is used. - */ -#define GSCHED_ALGO "rr" /* default scheduler */ - -/* - * Adapt to differences in geom library. - * in V1 struct g_command misses gc_argname, eld, and G_BOOL is undefined - */ -#if G_LIB_VERSION <= 1 -#define G_TYPE_BOOL G_TYPE_NUMBER -#endif -#if G_LIB_VERSION >= 3 && G_LIB_VERSION <= 4 -#define G_ARGNAME NULL, -#else -#define G_ARGNAME -#endif - -static void -gcmd_createinsert(struct gctl_req *req, unsigned flags __unused) -{ - const char *reqalgo; - char name[64]; - - if (gctl_has_param(req, "algo")) - reqalgo = gctl_get_ascii(req, "algo"); - else - reqalgo = GSCHED_ALGO; - - snprintf(name, sizeof(name), "gsched_%s", reqalgo); - /* - * Do not complain about errors here, gctl_issue() - * will fail anyway. - */ - if (modfind(name) < 0) - kldload(name); - gctl_issue(req); -} - -struct g_command class_commands[] = { - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, gcmd_createinsert, - { - { 'a', "algo", GSCHED_ALGO, G_TYPE_STRING }, - G_OPT_SENTINEL - }, - G_ARGNAME "[-v] [-a algorithm_name] dev ..." - }, - { "insert", G_FLAG_VERBOSE | G_FLAG_LOADKLD, gcmd_createinsert, - { - { 'a', "algo", GSCHED_ALGO, G_TYPE_STRING }, - G_OPT_SENTINEL - }, - G_ARGNAME "[-v] [-a algorithm_name] dev ..." - }, - { "configure", G_FLAG_VERBOSE, NULL, - { - { 'a', "algo", GSCHED_ALGO, G_TYPE_STRING }, - G_OPT_SENTINEL - }, - G_ARGNAME "[-v] [-a algorithm_name] prov ..." - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - G_ARGNAME "[-fv] prov ..." - }, - { "reset", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - G_ARGNAME "[-v] prov ..." - }, - G_CMD_SENTINEL -}; Index: sbin/geom/class/sched/gsched.8 =================================================================== --- /dev/null +++ sbin/geom/class/sched/gsched.8 @@ -1,162 +0,0 @@ -.\" Copyright (c) 2009-2010 Fabio Checconi -.\" Copyright (c) 2009-2010 Luigi Rizzo, Universita` di Pisa -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd July 26, 2012 -.Dt GSCHED 8 -.Os -.Sh NAME -.Nm gsched -.Nd "control utility for disk scheduler GEOM class" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Op Fl a Ar algorithm -.Ar provider ... -.Nm -.Cm insert -.Op Fl v -.Op Fl a Ar algorithm -.Ar provider ... -.Nm -.Cm configure -.Op Fl v -.Op Fl a Ar algorithm -.Ar node ... -.Nm -.Cm destroy -.Op Fl fv -.Ar node ... -.Nm -.Cm reset -.Op Fl v -.Ar node ... -.Nm -.Cm { list | status | load | unload } -.Sh DESCRIPTION -The -.Nm -utility (also callable as -.Nm geom sched ... ) -changes the scheduling policy of the requests going to a provider. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm configure" -.It Cm create -Create a new provider and geom node using the specified scheduling algorithm. -.Ar algorithm -is the name of the scheduling algorithm used for the provider. -Available algorithms include: -.Ar rr , -which implements anticipatory scheduling with round robin service -among clients; -.Ar as , -which implements a simple form of anticipatory scheduling with -no per-client queue. -.Pp -If the operation succeeds, the new provider should appear with name -.Pa /dev/ Ns Ao Ar dev Ac Ns Pa .sched. . -The kernel module -.Pa geom_sched.ko -will be loaded if it is not loaded already. -.It Cm insert -Operates as "create", but the insertion is "transparent", -i.e. the existing provider is rerouted to the newly created geom, -which in turn forwards requests to the existing geom. -This operation allows one to start/stop a scheduling service -on an already existing provider. -.Pp -A subsequent "destroy" will remove the newly created geom and -hook the provider back to the original geom. -.It Cm configure -Configure existing scheduling provider. It supports the same options -as the -.Nm create -command. -.It Cm destroy -Destroy the geom specified in the parameter. -.It Cm reset -Do nothing. -.It Cm list | status | load | unload -See -.Xr geom 8 . -.El -.Pp -Additional options: -.Bl -tag -width ".Fl f" -.It Fl f -Force the removal of the specified provider. -.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 SCHED -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.sched.debug : No 0 -Debug level of the -.Nm SCHED -GEOM class. -This can be set to a number between 0 and 2 inclusive. -If set to 0 minimal debug information is printed, and if set to 2 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 create a scheduling provider for disk -.Pa /dev/ada0 , -and how to destroy it. -.Bd -literal -offset indent -# Load the geom_sched module: -kldload geom_sched -# Load some scheduler classes used by geom_sched: -kldload gsched_rr -# Configure device ada0 to use scheduler "rr": -geom sched insert -a rr ada0 -# Now provider ada0 uses the "rr" algorithm; -# the new geom is ada0.sched. -# Remove the scheduler on the device: -geom sched destroy -v ada0.sched. -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr geom 8 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 8.1 . -.Sh AUTHORS -.An Fabio Checconi Aq Mt fabio@FreeBSD.org -.An Luigi Rizzo Aq Mt luigi@FreeBSD.org Index: sbin/geom/class/shsec/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/shsec/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= shsec - -.include Index: sbin/geom/class/shsec/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/shsec/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/shsec/geom_shsec.c =================================================================== --- /dev/null +++ sbin/geom/class/shsec/geom_shsec.c @@ -1,262 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2005 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_SHSEC_VERSION; - -static void shsec_main(struct gctl_req *req, unsigned flags); -static void shsec_clear(struct gctl_req *req); -static void shsec_dump(struct gctl_req *req); -static void shsec_label(struct gctl_req *req); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, shsec_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "dump", 0, shsec_main, G_NULL_OPTS, - "prov ..." - }, - { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, shsec_main, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-hv] name prov 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 -shsec_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) - shsec_label(req); - else if (strcmp(name, "clear") == 0) - shsec_clear(req); - else if (strcmp(name, "dump") == 0) - shsec_dump(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static void -shsec_label(struct gctl_req *req) -{ - struct g_shsec_metadata md; - off_t compsize, msize; - u_char sector[512]; - unsigned ssize, secsize; - const char *name; - int error, i, nargs, hardcode; - - 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. - */ - compsize = 0; - secsize = 0; - for (i = 1; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (msize == 0 || ssize == 0) { - gctl_error(req, "Can't get informations about %s: %s.", - name, strerror(errno)); - return; - } - msize -= ssize; - if (compsize == 0 || (compsize > 0 && msize < compsize)) - compsize = msize; - if (secsize == 0) - secsize = ssize; - else - secsize = g_lcm(secsize, ssize); - - 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_SHSEC_MAGIC, sizeof(md.md_magic)); - md.md_version = G_SHSEC_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); - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (compsize < msize - ssize) { - fprintf(stderr, - "warning: %s: only %jd bytes from %jd bytes used.\n", - name, (intmax_t)compsize, (intmax_t)(msize - ssize)); - } - - md.md_no = i - 1; - md.md_provsize = msize; - 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)); - } - shsec_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 -shsec_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_SHSEC_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 -shsec_metadata_dump(const struct g_shsec_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 -shsec_dump(struct gctl_req *req) -{ - struct g_shsec_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_SHSEC_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - shsec_metadata_decode((u_char *)&tmpmd, &md); - printf("Metadata on %s:\n", name); - shsec_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/shsec/gshsec.8 =================================================================== --- /dev/null +++ sbin/geom/class/shsec/gshsec.8 @@ -1,130 +0,0 @@ -.\" Copyright (c) 2005 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd October 1, 2013 -.Dt GSHSEC 8 -.Os -.Sh NAME -.Nm gshsec -.Nd "control utility for shared secret devices" -.Sh SYNOPSIS -.Nm -.Cm label -.Op Fl hv -.Ar name -.Ar prov 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 setting up a device which contains a shared secret. -The secret is shared between the given providers. -To collect the secret, all providers are needed. -If one of the components is missing, there is no way to get any useful data from -the rest of them. -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm destroy" -.It Cm label -Set up a shared secret device from the given components with the specified -.Ar name . -Metadata are stored in the last sector of every component. -.It Cm stop -Turn off an existing shared secret device by its -.Ar name . -This command does not touch on-disk metadata! -.It Cm clear -Clear metadata on the given providers. -.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: -.Bl -tag -width ".Fl f" -.It Fl f -Force the removal of the specified shared secret device. -.It Fl h -Hardcode providers' names in metadata. -.It Fl v -Be more verbose. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -The following example shows how to create a shared secret device. -The secret will be split between a slice on a local disk and a USB Pen drive. -.Bd -literal -offset indent -gshsec label -v secret /dev/ada0s1 /dev/da0 -newfs /dev/shsec/secret -.Ed -.Pp -From now on, when the USB Pen drive is inserted, it will be automatically -detected and connected, making the secret available via the -.Pa /dev/shsec/secret -device. -.Sh SEE ALSO -.Xr geom 4 , -.Xr gbde 8 , -.Xr geom 8 , -.Xr newfs 8 -.Sh HISTORY -The -.Nm -utility appeared in -.Fx 5.4 . -.Sh AUTHORS -.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org Index: sbin/geom/class/stripe/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/stripe/Makefile @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc - -GEOM_CLASS= stripe - -.include Index: sbin/geom/class/stripe/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/stripe/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/stripe/geom_stripe.c =================================================================== --- /dev/null +++ sbin/geom/class/stripe/geom_stripe.c @@ -1,288 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-2005 Pawel Jakub Dawidek - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/geom.h" -#include "misc/subr.h" - - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_STRIPE_VERSION; - -#define GSTRIPE_STRIPESIZE "65536" - -static void stripe_main(struct gctl_req *req, unsigned flags); -static void stripe_clear(struct gctl_req *req); -static void stripe_dump(struct gctl_req *req); -static void stripe_label(struct gctl_req *req); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, stripe_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, - { - { 's', "stripesize", GSTRIPE_STRIPESIZE, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-v] [-s stripesize] name prov prov ..." - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL }, - G_OPT_SENTINEL - }, - "[-fv] name ..." - }, - { "dump", 0, stripe_main, G_NULL_OPTS, - "prov ..." - }, - { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, stripe_main, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL }, - { 's', "stripesize", GSTRIPE_STRIPESIZE, G_TYPE_NUMBER }, - G_OPT_SENTINEL - }, - "[-hv] [-s stripesize] name prov 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 -stripe_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) - stripe_label(req); - else if (strcmp(name, "clear") == 0) - stripe_clear(req); - else if (strcmp(name, "dump") == 0) - stripe_dump(req); - else - gctl_error(req, "Unknown command: %s.", name); -} - -static void -stripe_label(struct gctl_req *req) -{ - struct g_stripe_metadata md; - intmax_t stripesize; - off_t compsize, msize; - u_char sector[512]; - unsigned ssize, secsize; - const char *name; - int error, i, nargs, hardcode; - - bzero(sector, sizeof(sector)); - nargs = gctl_get_int(req, "nargs"); - if (nargs < 3) { - gctl_error(req, "Too few arguments."); - return; - } - hardcode = gctl_get_int(req, "hardcode"); - - /* - * Clear last sector first to spoil all components if device exists. - */ - compsize = 0; - secsize = 0; - for (i = 1; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (msize == 0 || ssize == 0) { - gctl_error(req, "Can't get informations about %s: %s.", - name, strerror(errno)); - return; - } - msize -= ssize; - if (compsize == 0 || (compsize > 0 && msize < compsize)) - compsize = msize; - if (secsize == 0) - secsize = ssize; - else - secsize = g_lcm(secsize, ssize); - - 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_STRIPE_MAGIC, sizeof(md.md_magic)); - md.md_version = G_STRIPE_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; - stripesize = gctl_get_intmax(req, "stripesize"); - if ((stripesize % secsize) != 0) { - gctl_error(req, "Stripesize should be multiple of %u.", - secsize); - return; - } - md.md_stripesize = stripesize; - - /* - * Ok, store metadata. - */ - for (i = 1; i < nargs; i++) { - name = gctl_get_ascii(req, "arg%d", i); - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (compsize < msize - ssize) { - fprintf(stderr, - "warning: %s: only %jd bytes from %jd bytes used.\n", - name, (intmax_t)compsize, (intmax_t)(msize - ssize)); - } - - md.md_no = i - 1; - md.md_provsize = msize; - 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)); - } - stripe_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 -stripe_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_STRIPE_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 -stripe_metadata_dump(const struct g_stripe_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(" Stripe size: %u\n", (u_int)md->md_stripesize); - printf(" Hardcoded provider: %s\n", md->md_provider); -} - -static void -stripe_dump(struct gctl_req *req) -{ - struct g_stripe_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_STRIPE_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, "Not fully done."); - continue; - } - stripe_metadata_decode((u_char *)&tmpmd, &md); - printf("Metadata on %s:\n", name); - stripe_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/stripe/gstripe.8 =================================================================== --- /dev/null +++ sbin/geom/class/stripe/gstripe.8 @@ -1,243 +0,0 @@ -.\" Copyright (c) 2004-2005 Pawel Jakub Dawidek -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd May 21, 2004 -.Dt GSTRIPE 8 -.Os -.Sh NAME -.Nm gstripe -.Nd "control utility for striped devices" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Op Fl s Ar stripesize -.Ar name -.Ar prov prov ... -.Nm -.Cm destroy -.Op Fl fv -.Ar name ... -.Nm -.Cm label -.Op Fl hv -.Op Fl s Ar stripesize -.Ar name -.Ar prov 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 setting up a stripe on two or more disks. -The striped device 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 striped -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 -Set up a striped device from the given devices with specified -.Ar name . -This is the -.Dq manual -method and the stripe will not exist after a reboot (see -.Sx DESCRIPTION -above). -The kernel module -.Pa geom_stripe.ko -will be loaded if it is not loaded already. -.It Cm label -Set up a striped device from 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_stripe.ko -will be loaded if it is not loaded already. -.It Cm stop -Turn off an existing striped device by its -.Ar name . -This command does not touch on-disk metadata! -.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 ".Fl s Ar stripesize" -.It Fl f -Force the removal of the specified striped device. -.It Fl h -Hardcode providers' names in metadata. -.It Fl s Ar stripesize -Specifies size of stripe block in bytes. -The -.Ar stripesize -must be a multiple of the largest sector size of all the providers. -.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 STRIPE -GEOM class. -The default value is shown next to each variable. -.Bl -tag -width indent -.It Va kern.geom.stripe.debug : No 0 -Debug level of the -.Nm STRIPE -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. -.It Va kern.geom.stripe.fast : No 0 -If set to a non-zero value enable -.Dq "fast mode" -instead of the normal -.Dq "economic mode" . -Compared to -.Dq "economic mode" , -.Dq "fast mode" -uses more memory, but it is much faster for smaller stripe sizes. -If enough memory cannot be allocated, -.Nm STRIPE -will fall back to -.Dq "economic mode" . -.It Va kern.geom.stripe.maxmem : No 13107200 -Maximum amount of memory that can be consumed by -.Dq "fast mode" -(in bytes). -This -.Xr sysctl 8 -variable is read-only and can only be set as a tunable in -.Xr loader.conf 5 . -.It Va kern.geom.stripe.fast_failed -A count of how many times -.Dq "fast mode" -has failed due to an insufficient amount of memory. -If this value is large, you should consider increasing the -.Va kern.geom.stripe.maxmem -value. -.El -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command fails. -.Sh EXAMPLES -The following example shows how to set up a striped device from four disks with a -128KB stripe size for automatic configuration, -create a file system on it, -and mount it: -.Bd -literal -offset indent -gstripe label -v -s 131072 data /dev/da0 /dev/da1 /dev/da2 /dev/da3 -newfs /dev/stripe/data -mount /dev/stripe/data /mnt -[...] -umount /mnt -gstripe stop data -gstripe unload -.Ed -.Sh COMPATIBILITY -The -.Nm -interleave is in number of bytes, -unlike -.Xr ccdconfig 8 -which use the number of sectors. -A -.Xr ccdconfig 8 -.Ar ileave -of -.Ql 128 -is 64 KB (128 512B sectors). -The same stripe interleave would be specified as -.Ql 65536 -for -.Nm . -.Sh SEE ALSO -.Xr geom 4 , -.Xr loader.conf 5 , -.Xr ccdconfig 8 , -.Xr geom 8 , -.Xr gvinum 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 Index: sbin/geom/class/virstor/Makefile =================================================================== --- /dev/null +++ sbin/geom/class/virstor/Makefile @@ -1,11 +0,0 @@ -# $FreeBSD$ - -PACKAGE=runtime -.PATH: ${.CURDIR:H:H}/misc ${SRCTOP}/sys/geom/virstor - -GEOM_CLASS= virstor - -SRCS+= binstream.c -SRCS+= g_virstor_md.c - -.include Index: sbin/geom/class/virstor/Makefile.depend =================================================================== --- /dev/null +++ sbin/geom/class/virstor/Makefile.depend @@ -1,19 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - gnu/lib/csu \ - include \ - include/xlocale \ - lib/${CSU_DIR} \ - lib/libc \ - lib/libcompiler_rt \ - lib/libgeom \ - sbin/geom/core \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: sbin/geom/class/virstor/geom_virstor.c =================================================================== --- /dev/null +++ sbin/geom/class/virstor/geom_virstor.c @@ -1,530 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2005 Ivan Voras - * - * 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -uint32_t lib_version = G_LIB_VERSION; -uint32_t version = G_VIRSTOR_VERSION; - -#define GVIRSTOR_CHUNK_SIZE "4M" -#define GVIRSTOR_VIR_SIZE "2T" - -#if G_LIB_VERSION == 1 -/* Support RELENG_6 */ -#define G_TYPE_BOOL G_TYPE_NONE -#endif - -/* - * virstor_main gets called by the geom(8) utility - */ -static void virstor_main(struct gctl_req *req, unsigned flags); - -struct g_command class_commands[] = { - { "clear", G_FLAG_VERBOSE, virstor_main, G_NULL_OPTS, - "[-v] prov ..." - }, - { "dump", 0, virstor_main, G_NULL_OPTS, - "prov ..." - }, - { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, virstor_main, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL}, - { 'm', "chunk_size", GVIRSTOR_CHUNK_SIZE, G_TYPE_NUMBER}, - { 's', "vir_size", GVIRSTOR_VIR_SIZE, G_TYPE_NUMBER}, - G_OPT_SENTINEL - }, - "[-h] [-v] [-m chunk_size] [-s vir_size] name provider0 [provider1 ...]" - }, - { "destroy", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL}, - G_OPT_SENTINEL - }, - "[-fv] name ..." - }, - { "stop", G_FLAG_VERBOSE, NULL, - { - { 'f', "force", NULL, G_TYPE_BOOL}, - G_OPT_SENTINEL - }, - "[-fv] name ... (alias for \"destroy\")" - }, - { "add", G_FLAG_VERBOSE, NULL, - { - { 'h', "hardcode", NULL, G_TYPE_BOOL}, - G_OPT_SENTINEL - }, - "[-vh] name prov [prov ...]" - }, - { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, - "[-v] name ..." - }, - G_CMD_SENTINEL -}; - -static int verbose = 0; - -/* Helper functions' declarations */ -static void virstor_clear(struct gctl_req *req); -static void virstor_dump(struct gctl_req *req); -static void virstor_label(struct gctl_req *req); - -/* Dispatcher function (no real work done here, only verbose flag recorder) */ -static void -virstor_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) - virstor_label(req); - else if (strcmp(name, "clear") == 0) - virstor_clear(req); - else if (strcmp(name, "dump") == 0) - virstor_dump(req); - else - gctl_error(req, "%s: Unknown command: %s.", __func__, name); - - /* No CTASSERT in userland - CTASSERT(VIRSTOR_MAP_BLOCK_ENTRIES*VIRSTOR_MAP_ENTRY_SIZE == MAXPHYS); - */ -} - -/* - * Labels a new geom Meaning: parses and checks the parameters, calculates & - * writes metadata to the relevant providers so when the next round of - * "tasting" comes (which will be just after the provider(s) are closed) geom - * can be instantiated with the tasted metadata. - */ -static void -virstor_label(struct gctl_req *req) -{ - struct g_virstor_metadata md; - off_t msize; - unsigned char *sect; - unsigned int i; - size_t ssize, secsize; - const char *name; - char param[32]; - int hardcode, nargs, error; - struct virstor_map_entry *map; - size_t total_chunks; /* We'll run out of memory if - this needs to be bigger. */ - unsigned int map_chunks; /* Chunks needed by the map (map size). */ - size_t map_size; /* In bytes. */ - ssize_t written; - int fd; - - nargs = gctl_get_int(req, "nargs"); - if (nargs < 2) { - gctl_error(req, "Too few arguments (%d): expecting: name " - "provider0 [provider1 ...]", nargs); - return; - } - - hardcode = gctl_get_int(req, "hardcode"); - - /* - * Initialize constant parts of metadata: magic signature, version, - * name. - */ - bzero(&md, sizeof(md)); - strlcpy(md.md_magic, G_VIRSTOR_MAGIC, sizeof(md.md_magic)); - md.md_version = G_VIRSTOR_VERSION; - name = gctl_get_ascii(req, "arg0"); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", 0); - return; - } - strlcpy(md.md_name, name, sizeof(md.md_name)); - - md.md_virsize = (off_t)gctl_get_intmax(req, "vir_size"); - md.md_chunk_size = gctl_get_intmax(req, "chunk_size"); - md.md_count = nargs - 1; - - if (md.md_virsize == 0 || md.md_chunk_size == 0) { - gctl_error(req, "Virtual size and chunk size must be non-zero"); - return; - } - - if (md.md_chunk_size % MAXPHYS != 0) { - /* XXX: This is not strictly needed, but it's convenient to - * impose some limitations on it, so why not MAXPHYS. */ - size_t new_size = rounddown(md.md_chunk_size, MAXPHYS); - if (new_size < md.md_chunk_size) - new_size += MAXPHYS; - fprintf(stderr, "Resizing chunk size to be a multiple of " - "MAXPHYS (%d kB).\n", MAXPHYS / 1024); - fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024); - md.md_chunk_size = new_size; - } - - if (md.md_virsize % md.md_chunk_size != 0) { - off_t chunk_count = md.md_virsize / md.md_chunk_size; - md.md_virsize = chunk_count * md.md_chunk_size; - fprintf(stderr, "Resizing virtual size to be a multiple of " - "chunk size.\n"); - fprintf(stderr, "New virtual size: %zu MB\n", - (size_t)(md.md_virsize/(1024 * 1024))); - } - - msize = secsize = 0; - for (i = 1; i < (unsigned)nargs; i++) { - snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_ascii(req, "%s", param); - ssize = g_get_sectorsize(name); - if (ssize == 0) - fprintf(stderr, "%s for %s\n", strerror(errno), name); - msize += g_get_mediasize(name); - if (secsize == 0) - secsize = ssize; - else if (secsize != ssize) { - gctl_error(req, "Devices need to have same sector size " - "(%u on %s needs to be %u).", - (u_int)ssize, name, (u_int)secsize); - return; - } - } - - if (secsize == 0) { - gctl_error(req, "Device not specified"); - return; - } - - if (md.md_chunk_size % secsize != 0) { - fprintf(stderr, "Error: chunk size is not a multiple of sector " - "size."); - gctl_error(req, "Chunk size (in bytes) must be multiple of %u.", - (unsigned int)secsize); - return; - } - - total_chunks = md.md_virsize / md.md_chunk_size; - map_size = total_chunks * sizeof(*map); - assert(md.md_virsize % md.md_chunk_size == 0); - - ssize = map_size % secsize; - if (ssize != 0) { - size_t add_chunks = (secsize - ssize) / sizeof(*map); - total_chunks += add_chunks; - md.md_virsize = (off_t)total_chunks * (off_t)md.md_chunk_size; - map_size = total_chunks * sizeof(*map); - fprintf(stderr, "Resizing virtual size to fit virstor " - "structures.\n"); - fprintf(stderr, "New virtual size: %ju MB (%zu new chunks)\n", - (uintmax_t)(md.md_virsize / (1024 * 1024)), add_chunks); - } - - if (verbose) - printf("Total virtual chunks: %zu (%zu MB each), %ju MB total " - "virtual size.\n", - total_chunks, (size_t)(md.md_chunk_size / (1024 * 1024)), - md.md_virsize/(1024 * 1024)); - - if ((off_t)md.md_virsize < msize) - fprintf(stderr, "WARNING: Virtual storage size < Physical " - "available storage (%ju < %ju)\n", md.md_virsize, msize); - - /* Clear last sector first to spoil all components if device exists. */ - if (verbose) - printf("Clearing metadata on"); - - for (i = 1; i < (unsigned)nargs; i++) { - snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_ascii(req, "%s", param); - - if (verbose) - printf(" %s", name); - - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - if (msize == 0 || ssize == 0) { - gctl_error(req, "Can't retrieve information about " - "%s: %s.", name, strerror(errno)); - return; - } - if (msize < (off_t) MAX(md.md_chunk_size*4, map_size)) - gctl_error(req, "Device %s is too small", name); - error = g_metadata_clear(name, NULL); - if (error != 0) { - gctl_error(req, "Can't clear metadata on %s: %s.", name, - strerror(error)); - return; - } - } - - - /* Write allocation table to the first provider - this needs to be done - * before metadata is written because when kernel tastes it it's too - * late */ - name = gctl_get_ascii(req, "arg1"); /* device with metadata */ - if (verbose) - printf(".\nWriting allocation table to %s...", name); - - /* How many chunks does the map occupy? */ - map_chunks = map_size/md.md_chunk_size; - if (map_size % md.md_chunk_size != 0) - map_chunks++; - if (verbose) { - printf(" (%zu MB, %d chunks) ", map_size/(1024*1024), map_chunks); - fflush(stdout); - } - - if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - fd = open(name, O_RDWR); - else { - sprintf(param, "%s%s", _PATH_DEV, name); - fd = open(param, O_RDWR); - } - if (fd < 0) - gctl_error(req, "Cannot open provider %s to write map", name); - - /* Do it with calloc because there might be a need to set up chunk flags - * in the future */ - map = calloc(total_chunks, sizeof(*map)); - if (map == NULL) { - gctl_error(req, - "Out of memory (need %zu bytes for allocation map)", - map_size); - } - - written = pwrite(fd, map, map_size, 0); - free(map); - if ((size_t)written != map_size) { - if (verbose) { - fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n", - map_size, written, strerror(errno)); - } - gctl_error(req, "Error writing out allocation map!"); - return; - } - close (fd); - - if (verbose) - printf("\nStoring metadata on "); - - /* - * ID is randomly generated, unique for a geom. This is used to - * recognize all providers belonging to one geom. - */ - md.md_id = arc4random(); - - /* Ok, store metadata. */ - for (i = 1; i < (unsigned)nargs; i++) { - snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_ascii(req, "%s", param); - - msize = g_get_mediasize(name); - ssize = g_get_sectorsize(name); - - if (verbose) - printf("%s ", name); - - /* this provider's position/type in geom */ - md.no = i - 1; - /* this provider's size */ - md.provsize = msize; - /* chunk allocation info */ - md.chunk_count = md.provsize / md.md_chunk_size; - if (verbose) - printf("(%u chunks) ", md.chunk_count); - /* Check to make sure last sector is unused */ - if ((off_t)(md.chunk_count * md.md_chunk_size) > (off_t)(msize-ssize)) - md.chunk_count--; - md.chunk_next = 0; - if (i != 1) { - md.chunk_reserved = 0; - md.flags = 0; - } else { - md.chunk_reserved = map_chunks * 2; - md.flags = VIRSTOR_PROVIDER_ALLOCATED | - VIRSTOR_PROVIDER_CURRENT; - md.chunk_next = md.chunk_reserved; - if (verbose) - printf("(%u reserved) ", md.chunk_reserved); - } - - if (!hardcode) - bzero(md.provider, sizeof(md.provider)); - else { - /* convert "/dev/something" to "something" */ - if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { - strlcpy(md.provider, name + sizeof(_PATH_DEV) - 1, - sizeof(md.provider)); - } else - strlcpy(md.provider, name, sizeof(md.provider)); - } - sect = malloc(ssize); - if (sect == NULL) - err(1, "Cannot allocate sector of %zu bytes", ssize); - bzero(sect, ssize); - virstor_metadata_encode(&md, sect); - error = g_metadata_store(name, sect, ssize); - free(sect); - if (error != 0) { - if (verbose) - printf("\n"); - fprintf(stderr, "Can't store metadata on %s: %s.\n", - name, strerror(error)); - gctl_error(req, - "Not fully done (error storing metadata)."); - return; - } - } -#if 0 - if (verbose) - printf("\n"); -#endif -} - -/* Clears metadata on given provider(s) IF it's owned by us */ -static void -virstor_clear(struct gctl_req *req) -{ - const char *name; - char param[32]; - unsigned i; - int nargs, error; - int fd; - - nargs = gctl_get_int(req, "nargs"); - if (nargs < 1) { - gctl_error(req, "Too few arguments."); - return; - } - for (i = 0; i < (unsigned)nargs; i++) { - snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_ascii(req, "%s", param); - - error = g_metadata_clear(name, G_VIRSTOR_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't clear metadata on %s: %s " - "(do I own it?)\n", name, strerror(error)); - gctl_error(req, - "Not fully done (can't clear metadata)."); - continue; - } - if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - fd = open(name, O_RDWR); - else { - sprintf(param, "%s%s", _PATH_DEV, name); - fd = open(param, O_RDWR); - } - if (fd < 0) { - gctl_error(req, "Cannot clear header sector for %s", - name); - continue; - } - if (verbose) - printf("Metadata cleared on %s.\n", name); - } -} - -/* Print some metadata information */ -static void -virstor_metadata_dump(const struct g_virstor_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(" Provider index: %u\n", (u_int) md->no); - printf(" Active providers: %u\n", (u_int) md->md_count); - printf(" Hardcoded provider: %s\n", - md->provider[0] != '\0' ? md->provider : "(not hardcoded)"); - printf(" Virtual size: %u MB\n", - (unsigned int)(md->md_virsize/(1024 * 1024))); - printf(" Chunk size: %u kB\n", md->md_chunk_size / 1024); - printf(" Chunks on provider: %u\n", md->chunk_count); - printf(" Chunks free: %u\n", md->chunk_count - md->chunk_next); - printf(" Reserved chunks: %u\n", md->chunk_reserved); -} - -/* Called by geom(8) via gvirstor_main() to dump metadata information */ -static void -virstor_dump(struct gctl_req *req) -{ - struct g_virstor_metadata md; - u_char tmpmd[512]; /* temporary buffer */ - const char *name; - char param[16]; - int nargs, error, i; - - assert(sizeof(tmpmd) >= sizeof(md)); - - nargs = gctl_get_int(req, "nargs"); - if (nargs < 1) { - gctl_error(req, "Too few arguments."); - return; - } - for (i = 0; i < nargs; i++) { - snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_ascii(req, "%s", param); - - error = g_metadata_read(name, (u_char *) & tmpmd, sizeof(tmpmd), - G_VIRSTOR_MAGIC); - if (error != 0) { - fprintf(stderr, "Can't read metadata from %s: %s.\n", - name, strerror(error)); - gctl_error(req, - "Not fully done (error reading metadata)."); - continue; - } - virstor_metadata_decode((u_char *) & tmpmd, &md); - printf("Metadata on %s:\n", name); - virstor_metadata_dump(&md); - printf("\n"); - } -} Index: sbin/geom/class/virstor/gvirstor.8 =================================================================== --- /dev/null +++ sbin/geom/class/virstor/gvirstor.8 @@ -1,299 +0,0 @@ -.\" Copyright (c) 2006-2011 Ivan Voras -.\" 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. -.\" -.\" $FreeBSD$ -.\" -.Dd October 1, 2013 -.Dt GVIRSTOR 8 -.Os -.Sh NAME -.Nm gvirstor -.Nd "control utility for virtual data storage devices" -.Sh SYNOPSIS -.Nm -.Cm label -.Op Fl hv -.Op Fl s Ar virsize -.Op Fl m Ar chunksize -.Ar name -.Ar prov ... -.Nm -.Cm stop -.Op Fl fv -.Ar name ... -.Nm -.Cm destroy -.Op Fl fv -.Ar name ... -.Nm -.Cm add -.Op Fl vh -.Ar name prov ... -.Nm -.Cm remove -.Op Fl v -.Ar name prov ... -.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 setting up a virtual storage device of arbitrary -large size -.Pq for example, several TB , -consisting of an arbitrary number of physical storage devices with the -total size which is equal to or smaller than the virtual size. -Data for the virtual devices will be allocated from physical devices on -demand. -The idea behind -.Nm -is similar to the concept of Virtual Memory in operating systems, -effectively allowing users to overcommit on storage -.Pq free file system space . -The concept is also known as "thin provisioning" in virtualization -environments, only here it is implemented on the level of physical storage -devices. -.Pp -The first argument to -.Nm -indicates an action to be performed: -.Bl -tag -width ".Cm remove" -.It Cm label -Set up a virtual device from the given components with the specified -.Ar name . -Metadata is stored in the last sector of every component. -Argument -.Fl s Ar virsize -is the size of new virtual device, with default being set to 2 TiB -.Pq 2097152 MiB . -Argument -.Fl m Ar chunksize -is the chunk size, with default being set to 4 MiB -.Pq 4096 KiB . -The default arguments are thus -.Qq Fl s Ar 2097152 Fl m Ar 4096 . -.It Cm stop -Turn off an existing virtual device with the given -.Ar name . -This command does not touch on-disk metadata. -As with other GEOM classes, stopped geoms cannot be started manually. -.It Cm destroy -Same as -.Cm stop. -.It Cm add -Adds new components to existing virtual device with the given -.Ar name . -The specified virstor device must exist and be active -.Pq i.e. module loaded, device present in Pa /dev . -This action can be safely performed while the virstor device is in use -.Pq Qo hot Qc operation . -.It Cm remove -Removes components from existing virtual device with the given -.Ar name . -Only unallocated providers can be removed. -.It Cm clear -Clear metadata on the given providers. -.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: -.Bl -tag -width ".Fl f" -.It Fl f -Force the removal of the specified virtual device. -.It Fl h -Hardcode providers' names in metadata. -.It Fl v -Be more verbose. -.El -.Sh EXAMPLES -The following example shows how to create a virtual device of default size -.Pq 2 TiB , -of default chunk -.Pq extent -size -.Pq 4 MiB , -with two physical devices for backing storage. -.Bd -literal -offset indent -.No gvirstor label -v Ar mydata Ar /dev/ada4 Ar /dev/ada6 -.No newfs Ar /dev/virstor/mydata -.Ed -.Pp -From now on, the virtual device will be available via the -.Pa /dev/virstor/mydata -device entry. -To add a new physical device / component to an active virstor device: -.Bd -literal -offset indent -.No gvirstor add Ar mydata Ar ada8 -.Ed -.Pp -This will add physical storage of -.Ar ada8 -to -.Pa /dev/virstor/mydata -device. -.Pp -To see the device status information -.Pq including how much physical storage is still available for the virtual device , -use: -.Bd -literal -offset indent -gvirstor list -.Ed -.Pp -All standard -.Xr geom 8 -subcommands -.Pq e.g. Cm status , Cm help -are also supported. -.Sh SYSCTL VARIABLES -.Nm -has several -.Xr sysctl 8 -tunable variables. -.Bd -literal -offset indent -.Va int kern.geom.virstor.debug -.Ed -.Pp -This sysctl controls verbosity of the kernel module, in the range -1 to 15. -Messages that are marked with higher verbosity levels than this are -suppressed. -Default value is 5 and it is not recommended to set this tunable to less -than 2, because level 1 messages are error events, and level 2 messages -are system warnings. -.Bd -literal -offset indent -.Va int kern.geom.virstor.chunk_watermark -.Ed -.Pp -Value in this sysctl sets warning watermark level for physical chunk -usage on a single component. -The warning is issued when a virstor component has less than this many -free chunks -.Pq default 100 . -.Bd -literal -offset indent -.Va int kern.geom.virstor.component_watermark -.Ed -.Pp -Value in this sysctl sets warning watermark level for component usage. -The warning is issued when there are less than this many unallocated -components -.Pq default is 1 . -.Pp -All these sysctls are also available as -.Xr loader 8 -tunables. -.Sh DIAGNOSTICS -.Ex -std -.Pp -.Nm -kernel module issues log messages with prefixes in standardized format, -which is useful for log message filtering and dispatching. -Each message line begins with -.Bd -literal -offset indent -.Li GEOM_VIRSTOR[%d]: -.Ed -.Pp -The number -.Pq %d -is message verbosity / importance level, in the range 1 to 15. -If a message filtering, dispatching or operator alert system is used, it -is recommended that messages with levels 1 and 2 be taken seriously -.Pq for example, to catch out-of-space conditions as set by watermark -sysctls. -.Sh SEE ALSO -.Xr geom 4 , -.Xr fstab 5 , -.Xr geom 8 , -.Xr glabel 8 , -.Xr newfs 8 -.Sh HISTORY -The -.Nm -utility first appeared in -.Fx 7.0 . -.Sh AUTHORS -.An Ivan Voras Aq Mt ivoras@FreeBSD.org -.Pp -Sponsored by Google Summer of Code 2006. -.Sh BUGS -Commands -.Cm add -and -.Cm remove -contain unavoidable critical sections which may make the virstor -device unusable if a power failure -.Pq or other disruptive event -happens during their execution. -It is recommended to run them when the system is quiescent. -.Sh ASSUMPTIONS AND INTERACTION WITH FILE SYSTEMS -There are several assumptions that -.Nm -has in its operation: that the size of the virtual storage device will not -change once it is set, and that the sizes of individual physical storage -components will always remain constant during their existence. -For alternative ways to implement virtual or resizable file systems see -.Xr zfs 1M , -.Xr gconcat 8 -and -.Xr growfs 8 . -.Pp -Note that -.Nm -has nontrivial interaction with file systems which initialize a large -number of on-disk structures during newfs. -If such file systems attempt to spread their structures across the drive -media -.Pq like UFS/UFS2 does , -their efforts will be effectively foiled by sequential allocation of -chunks in -.Nm -and all their structures will be physically allocated at the start -of the first virstor component. -This could have a significant impact on file system performance -.Pq which can in some rare cases be even positive . Index: sbin/geom/core/Makefile =================================================================== --- sbin/geom/core/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR:H}/misc - -PACKAGE=runtime -PROG= geom -MAN= geom.8 -SRCS= geom.c subr.c - -NO_SHARED=NO - -CFLAGS+= -DGEOM_CLASS_DIR=\"${GEOM_CLASS_DIR}\" -CFLAGS+= -I${SRCTOP}/sys -I${.CURDIR} -I${.CURDIR:H} - -LIBADD= geom util - -.include