aboutsummaryrefslogtreecommitdiff
path: root/lib/geom/cache
diff options
context:
space:
mode:
Diffstat (limited to 'lib/geom/cache')
-rw-r--r--lib/geom/cache/Makefile5
-rw-r--r--lib/geom/cache/Makefile.depend16
-rw-r--r--lib/geom/cache/gcache.8190
-rw-r--r--lib/geom/cache/geom_cache.c240
4 files changed, 451 insertions, 0 deletions
diff --git a/lib/geom/cache/Makefile b/lib/geom/cache/Makefile
new file mode 100644
index 000000000000..e307351c1de5
--- /dev/null
+++ b/lib/geom/cache/Makefile
@@ -0,0 +1,5 @@
+PACKAGE=geom
+
+GEOM_CLASS= cache
+
+.include <bsd.lib.mk>
diff --git a/lib/geom/cache/Makefile.depend b/lib/geom/cache/Makefile.depend
new file mode 100644
index 000000000000..0dd05cace3c0
--- /dev/null
+++ b/lib/geom/cache/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libgeom \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/geom/cache/gcache.8 b/lib/geom/cache/gcache.8
new file mode 100644
index 000000000000..026c66b0966b
--- /dev/null
+++ b/lib/geom/cache/gcache.8
@@ -0,0 +1,190 @@
+.\"-
+.\" 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.
+.\"
+.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
diff --git a/lib/geom/cache/geom_cache.c b/lib/geom/cache/geom_cache.c
new file mode 100644
index 000000000000..7be54004f196
--- /dev/null
+++ b/lib/geom/cache/geom_cache.c
@@ -0,0 +1,240 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2006 Ruslan Ermilov <ru@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 <sys/cdefs.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <libgeom.h>
+#include <geom/cache/g_cache.h>
+
+#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");
+ }
+}