Bring in the GEOM Virtualisation class, which allows to create huge GEOM

providers with limited physical storage and add physical storage as
needed.

Submitted by:	Ivan Voras
Sponsored by:	Google Summer of Code 2006
Approved by:	re (kensmith)
This commit is contained in:
Pawel Jakub Dawidek 2007-09-23 07:34:23 +00:00
parent a95a61fc19
commit f854db0bf5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172302
17 changed files with 3276 additions and 2 deletions

View File

@ -174,6 +174,8 @@
..
stripe
..
virstor
..
..
gnu
posix

View File

@ -49,7 +49,7 @@ LSUBDIRS= cam/scsi \
fs/devfs fs/fdescfs fs/fifofs fs/msdosfs fs/ntfs fs/nullfs \
${_fs_nwfs} fs/portalfs fs/procfs fs/smbfs fs/udf fs/unionfs \
geom/cache geom/concat geom/eli geom/gate geom/journal geom/label \
geom/mirror geom/nop geom/raid3 geom/shsec geom/stripe \
geom/mirror geom/nop geom/raid3 geom/shsec geom/stripe geom/virstor \
netgraph/atm netgraph/netflow \
security/audit \
security/mac_biba security/mac_bsdextended security/mac_lomac \

View File

@ -16,5 +16,6 @@ SUBDIR+=part
SUBDIR+=raid3
SUBDIR+=shsec
SUBDIR+=stripe
SUBDIR+=virstor
.include <bsd.subdir.mk>

View File

@ -0,0 +1,13 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../misc ${.CURDIR}/../../../../sys/geom/virstor
CLASS= virstor
SRCS+= binstream.c
SRCS+= g_virstor_md.c
DPADD= ${LIBMD}
LDADD= -lmd
.include <bsd.lib.mk>

View File

@ -0,0 +1,578 @@
/*-
* Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgeom.h>
#include <err.h>
#include <assert.h>
#include <core/geom.h>
#include <misc/subr.h>
#include <geom/virstor/g_virstor_md.h>
#include <geom/virstor/g_virstor.h>
uint32_t lib_version = G_LIB_VERSION;
uint32_t version = G_VIRSTOR_VERSION;
static intmax_t chunk_size = 4 * 1024 * 1024; /* in kB (default: 4 MB) */
static intmax_t vir_size = 2ULL << 40; /* in MB (default: 2 TB) */
#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, NULL,
"[-v] prov ..."
},
{"dump", 0, virstor_main, G_NULL_OPTS, NULL,
"prov ..."
},
{"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, virstor_main,
{
{'h', "hardcode", NULL, G_TYPE_BOOL},
{'m', "chunk_size", &chunk_size, G_TYPE_NUMBER},
{'s', "vir_size", &vir_size, G_TYPE_NUMBER},
G_OPT_SENTINEL
},
NULL, "[-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
},
NULL, "[-fv] name ..."
},
{"stop", G_FLAG_VERBOSE, NULL,
{
{'f', "force", NULL, G_TYPE_BOOL},
G_OPT_SENTINEL
},
NULL, "[-fv] name ... (alias for \"destroy\")"
},
{"add", G_FLAG_VERBOSE, NULL,
{
{'h', "hardcode", NULL, G_TYPE_BOOL},
G_OPT_SENTINEL
},
NULL, "[-vh] name prov [prov ...]"
},
{"remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
"[-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);
*/
}
static void
pathgen(const char *name, char *path, size_t size)
{
if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
snprintf(path, size, "%s%s", _PATH_DEV, name);
else
strlcpy(path, name, size);
}
static int
my_g_metadata_store(const char *name, u_char *md, size_t size)
{
char path[MAXPATHLEN];
unsigned sectorsize;
off_t mediasize;
u_char *sector;
int error, fd;
ssize_t abc;
pathgen(name, path, sizeof(path));
sector = NULL;
error = 0;
fd = open(path, O_RDWR);
if (fd == -1)
return (errno);
mediasize = g_get_mediasize(name);
if (mediasize == 0) {
error = errno;
goto out;
}
sectorsize = g_get_sectorsize(name);
if (sectorsize == 0) {
error = errno;
goto out;
}
assert(sectorsize >= size);
sector = malloc(sectorsize);
if (sector == NULL) {
error = ENOMEM;
goto out;
}
bcopy(md, sector, size);
if ((abc = pwrite(fd, sector, sectorsize, mediasize - sectorsize)) !=
(ssize_t)sectorsize) {
error = errno;
goto out;
}
out:
if (sector != NULL)
free(sector);
close(fd);
return (error);
}
/*
* 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 = (md.md_chunk_size / MAXPHYS) * 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 = ssize = 0;
for (i = 1; i < (unsigned)nargs; i++) {
snprintf(param, sizeof(param), "arg%u", i);
name = gctl_get_ascii(req, 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 (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, 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 < 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, strlen(_PATH_DEV)) == 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, 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 > 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, strlen(_PATH_DEV)) == 0) {
strlcpy(md.provider, name + strlen(_PATH_DEV),
sizeof(md.provider));
} else
strlcpy(md.provider, name, sizeof(md.provider));
}
sect = malloc(ssize);
bzero(sect, ssize);
if (sect == NULL)
err(1, "Cannot allocate sector of %zu bytes", ssize);
virstor_metadata_encode(&md, sect);
error = my_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, 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, strlen(_PATH_DEV)) == 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, 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");
}
}

View File

@ -0,0 +1,227 @@
.\" Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2005 Ivan Voras <ivoras@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 8, 2006
.Dt GVIRSTOR 8
.Os
.Sh NAME
.Nm gvirstor
.Nd "provides virtual data storage geom"
.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 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 storage device of arbitrary large size (for example,
several TB), consisting of an arbitrary number of physical storage devices with
total size <= the virtual size. Data for the virtual devices will be allocated from
physical devices on demand. In short, this is the virtual storage functionality.
The first argument to
.Nm
indicates an action to be performed:
.Bl -tag -width ".Cm destroy"
.It Cm label
Set up a virtual device from the given components with the specified
.Ar name .
Metadata are stored in the last sector of every component.
Argument
.Ar virsize
is the size of new virtual device, with default being 2 TiB (2097152 MiB).
Argument
.Ar chunksize
is the chunk size, with default being 4 MiB (4096 KiB).
The default is thus "-s 2097152 -m 4096".
.It Cm stop
Turn off an existing virtual device by its
.Ar name .
This command does not touch on-disk metadata.
As with other GEOM classes, stopped geoms cannot be started manually.
.It Cm add
Adds new components to existing virtual device by its
.Ar name .
The specified virstor device must exist and be active (i.e.
module loaded, device present in /dev).
.It Cm remove
Removes components from existing virtual device by its
.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 EXIT STATUS
Exit status is 0 on success, and 1 if the command fails.
.Sh EXAMPLES
The following example shows how to create a virtual device of default size
(2 TiB), of default chunk (extent) size (4 MiB), with two physical devices for
backing storage.
.Bd -literal -offset indent
gvirstor label -v mydata /dev/ad4 /dev/ad6
newfs /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 / provider to an active virstor device:
.Bd -literal -offset indent
gvirstor add mydata ad8
.Ed
.Pp
This will add physical storage (from ad8) to
.Pa /dev/virstor/mydata
device.
To see device status information (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 (e.g. "status", "help") are also supported.
.Sh SYSCTLs
.Nm
has several
.Xr sysctl 8
tunable variables.
.Bd -literal -offset indent
.Pa 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 supressed. Default value is 5 and it's not
recommented 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
.Pa 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 (default 100).
.Bd -literal -offset indent
.Pa int kern.geom.virstor.component_watermark
.Ed
.Pp
Value in this sysctl sets warning watermark level for component usage.
The warning is issed when there are less than this many unallocated
components (default is 1).
.Pp
All these sysctls are also available as
.Xr loader 8
tunables.
.Sh LOG MESSAGES
.Nm
kernel module issues log messages with prefixes in standardised format,
which is useful for log message filtering and dispatching. Each message
line begins with
.Bd -literal -offset indent
.Pa GEOM_VIRSTOR[%d]:
.Ed
.Pp
The number (%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 (for example, to catch out-of-space conditions as set by
watermark sysctls).
.Sh SEE ALSO
.Xr geom 4 ,
.Xr geom 8 ,
.Xr newfs 8 ,
.Xr fstab 5 ,
.Xr glabel 8
.Sh HISTORY
The
.Nm
utility appeared in
.Fx 7.0 .
.Sh BUGS
Commands "add" and "remove" contain unavoidable critical sections
which may make the virstor device unusable if a power failure (or
other disruptive event) happens during their execution.
It's recommended to run them when the system is quiescent.
.Sh AUTHOR
.An Ivan Voras Aq ivoras@FreeBSD.org
Sponsored by Google Summer of Code 2006

View File

@ -123,6 +123,8 @@ RAID3
SHSEC
.It
STRIPE
.It
VIRSTOR
.El
.Sh ENVIRONMENT
The following environment variables affect the execution of
@ -161,7 +163,8 @@ geom md unload
.Xr gnop 8 ,
.Xr graid3 8 ,
.Xr gshsec 8 ,
.Xr gstripe 8
.Xr gstripe 8 ,
.Xr gvirstor 8
.Sh HISTORY
The
.Nm

View File

@ -154,6 +154,7 @@ options GEOM_SHSEC # Shared secret.
options GEOM_STRIPE # Disk striping.
options GEOM_SUNLABEL # Sun/Solaris partitioning
options GEOM_UZIP # Read-only compressed disks
options GEOM_VIRSTOR # Virtual storage.
options GEOM_VOL # Volume names from UFS superblock
options GEOM_ZERO # Performance testing helper.

View File

@ -1301,6 +1301,9 @@ geom/raid3/g_raid3_ctl.c optional geom_raid3
geom/shsec/g_shsec.c optional geom_shsec
geom/stripe/g_stripe.c optional geom_stripe
geom/uzip/g_uzip.c optional geom_uzip
geom/virstor/binstream.c optional geom_virstor
geom/virstor/g_virstor.c optional geom_virstor
geom/virstor/g_virstor_md.c optional geom_virstor
geom/zero/g_zero.c optional geom_zero
gnu/fs/ext2fs/ext2_alloc.c optional ext2fs \
warning "kernel contains GPL contaminated ext2fs filesystem"

View File

@ -96,6 +96,7 @@ GEOM_SHSEC opt_geom.h
GEOM_STRIPE opt_geom.h
GEOM_SUNLABEL opt_geom.h
GEOM_UZIP opt_geom.h
GEOM_VIRSTOR opt_geom.h
GEOM_VOL opt_geom.h
GEOM_ZERO opt_geom.h
KSE opt_global.h

View File

@ -0,0 +1,185 @@
/*-
* Copyright (c) 2005 Ivan Voras <ivoras@gmail.com>
* 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: binstream.c,v 1.1 2006/07/05 10:47:54 ivoras Exp $
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/endian.h>
#include <sys/param.h>
#include <geom/virstor/binstream.h>
/* "Open" a binary stream for reading */
void
bs_open(bin_stream_t * bs, void *data)
{
bs->data = (char *)data;
bs->pos = 0;
}
/* "Reset" position in binary stream to zero */
void
bs_reset(bin_stream_t * bs)
{
bs->pos = 0;
}
/* Write a zero-terminated string; return next position */
unsigned
bs_write_str(bin_stream_t * bs, char *data)
{
int len = 0;
do {
*(bs->data + bs->pos + len) = *data;
len++;
} while (*(data++) != '\0');
bs->pos += len;
return bs->pos;
}
/* Write an arbitrary buffer; return next position */
unsigned
bs_write_buf(bin_stream_t * bs, char *data, unsigned data_size)
{
unsigned i;
for (i = 0; i < data_size; i++)
*(bs->data + bs->pos + i) = *(data + i);
bs->pos += data_size;
return bs->pos;
}
/* Write a 8bit uint; return next position. */
unsigned
bs_write_u8(bin_stream_t * bs, uint8_t data)
{
*((uint8_t *) (bs->data + bs->pos)) = data;
return ++(bs->pos);
}
/* Write a 16bit uint; return next position. */
unsigned
bs_write_u16(bin_stream_t * bs, uint16_t data)
{
le16enc(bs->data + bs->pos, data);
return (bs->pos += 2);
}
/* Write a 32bit uint; return next position. */
unsigned
bs_write_u32(bin_stream_t * bs, uint32_t data)
{
le32enc(bs->data + bs->pos, data);
return (bs->pos += 4);
}
/* Write a 64bit uint; return next position. */
unsigned
bs_write_u64(bin_stream_t * bs, uint64_t data)
{
le64enc(bs->data + bs->pos, data);
return (bs->pos += 8);
}
/* Read a 8bit uint & return it */
uint8_t
bs_read_u8(bin_stream_t * bs)
{
uint8_t data = *((uint8_t *) (bs->data + bs->pos));
bs->pos++;
return data;
}
/*
* Read a null-terminated string from stream into a buffer; buf_size is size
* of the buffer, including the final \0. Returns buf pointer or NULL if
* garbage input.
*/
char*
bs_read_str(bin_stream_t * bs, char *buf, unsigned buf_size)
{
unsigned len = 0;
char *work_buf = buf;
if (buf == NULL || buf_size < 1)
return NULL;
do {
*work_buf = *(bs->data + bs->pos + len);
} while (len++ < buf_size - 1 && *(work_buf++) != '\0');
*(buf + buf_size - 1) = '\0';
bs->pos += len;
return buf;
}
/* Read an arbitrary buffer. */
void
bs_read_buf(bin_stream_t * bs, char *buf, unsigned buf_size)
{
unsigned i;
for (i = 0; i < buf_size; i++)
*(buf + i) = *(bs->data + bs->pos + i);
bs->pos += buf_size;
}
/* Read a 16bit uint & return it */
uint16_t
bs_read_u16(bin_stream_t * bs)
{
uint16_t data = le16dec(bs->data + bs->pos);
bs->pos += 2;
return data;
}
/* Read a 32bit uint & return it */
uint32_t
bs_read_u32(bin_stream_t * bs)
{
uint32_t data = le32dec(bs->data + bs->pos);
bs->pos += 4;
return data;
}
/* Read a 64bit uint & return it */
uint64_t
bs_read_u64(bin_stream_t * bs)
{
uint64_t data = le64dec(bs->data + bs->pos);
bs->pos += 8;
return data;
}

View File

@ -0,0 +1,93 @@
/*-
* Copyright (c) 2005 Ivan Voras <ivoras@gmail.com>
* 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$
*/
// $Id: binstream.h,v 1.1 2006/07/05 10:47:54 ivoras Exp $
#ifndef _BIN_STREAM_
#define _BIN_STREAM_
#ifndef uint8_t
#define uint8_t unsigned char
#endif
typedef struct {
unsigned char *data;
int pos;
} bin_stream_t;
/* "Open" a binary stream for reading */
void bs_open (bin_stream_t * bs, void *data);
/* "Reset" position in binary stream to zero */
void bs_reset (bin_stream_t * bs);
/* Write a zero-terminated string; return next position */
unsigned bs_write_str(bin_stream_t * bs, char *data);
/* Write an arbitrary buffer; return next position */
unsigned bs_write_buf(bin_stream_t * bs, char *data, unsigned data_size);
/* Write a 8bit uint; return next position. */
unsigned bs_write_u8(bin_stream_t * bs, uint8_t data);
/* Write a 16bit uint; return next position. */
unsigned bs_write_u16(bin_stream_t * bs, uint16_t data);
/* Write a 32bit uint; return next position. */
unsigned bs_write_u32(bin_stream_t * bs, uint32_t data);
/* Write a 64bit uint; return next position. */
unsigned bs_write_u64(bin_stream_t * bs, uint64_t data);
/*
* Read a null-terminated string from stream into a buffer; buf_size is size
* of the buffer, including the final \0. Returns buf pointer or NULL if
* garbage input.
*/
char *bs_read_str(bin_stream_t * bs, char *buf, unsigned buf_size);
/* Read an arbitrary buffer. */
void bs_read_buf(bin_stream_t * bs, char *buf, unsigned buf_size);
/* Read a 8bit uint * return it */
uint8_t bs_read_u8(bin_stream_t * bs);
/* Read a 16bit uint * return it */
uint16_t bs_read_u16(bin_stream_t * bs);
/* Read a 8bit uint * return it */
uint32_t bs_read_u32(bin_stream_t * bs);
/* Read a 8bit uint * return it */
uint64_t bs_read_u64(bin_stream_t * bs);
#endif

1864
sys/geom/virstor/g_virstor.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
/*-
* Copyright (c) 2006-2007 Ivan Voras <ivoras@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _G_VIRSTOR_H_
#define _G_VIRSTOR_H_
#define G_VIRSTOR_CLASS_NAME "VIRSTOR"
#define VIRSTOR_MAP_ALLOCATED 1
struct virstor_map_entry {
uint16_t flags;
uint16_t provider_no;
uint32_t provider_chunk;
};
#define VIRSTOR_MAP_ENTRY_SIZE (sizeof(struct virstor_map_entry))
#define VIRSTOR_MAP_BLOCK_ENTRIES (MAXPHYS / VIRSTOR_MAP_ENTRY_SIZE)
/* Struct size is guarded by CTASSERT in main source */
#ifdef _KERNEL
#define LOG_MSG(lvl, ...) do { \
if (g_virstor_debug >= (lvl)) { \
printf("GEOM_" G_VIRSTOR_CLASS_NAME); \
if (lvl > 0) \
printf("[%u]", lvl); \
printf(": "); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
} while (0)
#define LOG_MESSAGE LOG_MSG
#define LOG_REQ(lvl, bp, ...) do { \
if (g_virstor_debug >= (lvl)) { \
printf("GEOM_" G_VIRSTOR_CLASS_NAME); \
if (lvl > 0) \
printf("[%u]", lvl); \
printf(": "); \
printf(__VA_ARGS__); \
printf(" "); \
g_print_bio(bp); \
printf("\n"); \
} \
} while (0)
#define LOG_REQUEST LOG_REQ
/* "critical" system announcements (e.g. "geom is up") */
#define LVL_ANNOUNCE 0
/* errors */
#define LVL_ERROR 1
/* warnings */
#define LVL_WARNING 2
/* info, noncritical for system operation (user doesn't have to see it */
#define LVL_INFO 5
/* debug info */
#define LVL_DEBUG 10
/* more debug info */
#define LVL_DEBUG2 12
/* superfluous debug info (large volumes of data) */
#define LVL_MOREDEBUG 15
/* Component data */
struct g_virstor_component {
struct g_consumer *gcons;
struct g_virstor_softc *sc;
unsigned int index; /* Component index in array */
unsigned int chunk_count;
unsigned int chunk_next;
unsigned int chunk_reserved;
unsigned int flags;
};
/* Internal geom instance data */
struct g_virstor_softc {
struct g_geom *geom;
struct g_provider *provider;
struct g_virstor_component *components;
u_int n_components;
u_int curr_component; /* Component currently used */
uint32_t id; /* Unique ID of this geom */
off_t virsize; /* Total size of virstor */
off_t sectorsize;
size_t chunk_size;
size_t chunk_count; /* governs map_size */
struct virstor_map_entry *map;
size_t map_size; /* (in bytes) */
size_t map_sectors; /* Size of map in sectors */
size_t me_per_sector; /* # map entries in a sector */
STAILQ_HEAD(, g_virstor_bio_q) delayed_bio_q; /* Queue of delayed BIOs */
struct mtx delayed_bio_q_mtx;
};
/* "delayed BIOs" Queue element */
struct g_virstor_bio_q {
struct bio *bio;
STAILQ_ENTRY(g_virstor_bio_q) linkage;
};
#endif /* _KERNEL */
#ifndef _PATH_DEV
#define _PATH_DEV "/dev/"
#endif
#endif /* !_G_VIRSTOR_H_ */

View File

@ -0,0 +1,91 @@
/*-
* Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/endian.h>
#include <geom/virstor/g_virstor_md.h>
#include <geom/virstor/binstream.h>
/*
* Encode data from g_virstor_metadata structure into a endian-independant
* byte stream.
*/
void
virstor_metadata_encode(struct g_virstor_metadata *md, unsigned char *data)
{
bin_stream_t bs;
bs_open(&bs, data);
bs_write_buf(&bs, md->md_magic, sizeof(md->md_magic));
bs_write_u32(&bs, md->md_version);
bs_write_buf(&bs, md->md_name, sizeof(md->md_name));
bs_write_u64(&bs, md->md_virsize);
bs_write_u32(&bs, md->md_chunk_size);
bs_write_u32(&bs, md->md_id);
bs_write_u16(&bs, md->md_count);
bs_write_buf(&bs, md->provider, sizeof(md->provider));
bs_write_u16(&bs, md->no);
bs_write_u64(&bs, md->provsize);
bs_write_u32(&bs, md->chunk_count);
bs_write_u32(&bs, md->chunk_next);
bs_write_u16(&bs, md->chunk_reserved);
bs_write_u16(&bs, md->flags);
}
/*
* Decode data from endian-independant byte stream into g_virstor_metadata
* structure.
*/
void
virstor_metadata_decode(unsigned char *data, struct g_virstor_metadata *md)
{
bin_stream_t bs;
bs_open(&bs, (char *)(data));
bs_read_buf(&bs, md->md_magic, sizeof(md->md_magic));
md->md_version = bs_read_u32(&bs);
bs_read_buf(&bs, md->md_name, sizeof(md->md_name));
md->md_virsize = bs_read_u64(&bs);
md->md_chunk_size = bs_read_u32(&bs);
md->md_id = bs_read_u32(&bs);
md->md_count = bs_read_u16(&bs);
bs_read_buf(&bs, md->provider, sizeof(md->provider));
md->no = bs_read_u16(&bs);
md->provsize = bs_read_u64(&bs);
md->chunk_count = bs_read_u32(&bs);
md->chunk_next = bs_read_u32(&bs);
md->chunk_reserved = bs_read_u16(&bs);
md->flags = bs_read_u16(&bs);
}

View File

@ -0,0 +1,69 @@
/*-
* Copyright (c) 2005 Ivan Voras <ivoras@gmail.com>
* 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 _G_VIRSTOR_MD_H_
#define _G_VIRSTOR_MD_H_
/*
* Metadata declaration
*/
#define G_VIRSTOR_MAGIC "GEOM::VIRSTOR"
#define G_VIRSTOR_VERSION 1
/* flag: provider is allocated */
#define VIRSTOR_PROVIDER_ALLOCATED 1
/* flag: provider is currently being filled (usually it's the last
* provider with VIRSTOR_PROVIDER_ALLOCATED flag */
#define VIRSTOR_PROVIDER_CURRENT 2
struct g_virstor_metadata {
/* Data global to the virstor device */
char md_magic[16]; /* Magic value. */
uint32_t md_version; /* Version number. */
char md_name[16]; /* Device name (e.g. "mydata") */
uint32_t md_id; /* Unique ID. */
uint64_t md_virsize; /* Virtual device's size */
uint32_t md_chunk_size; /* Chunk size in bytes */
uint16_t md_count; /* Total number of providers */
/* Data local to this provider */
char provider[16]; /* Hardcoded provider name */
uint16_t no; /* Provider number/index */
uint64_t provsize; /* Provider's size */
uint32_t chunk_count; /* Number of chunks in this pr. */
uint32_t chunk_next; /* Next chunk to allocate */
uint16_t chunk_reserved; /* Count of "reserved" chunks */
uint16_t flags; /* Provider's flags */
};
void virstor_metadata_encode(struct g_virstor_metadata *md, unsigned char *data);
void virstor_metadata_decode(unsigned char *data, struct g_virstor_metadata *md);
#endif /* !_G_VIRSTOR_H_ */

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../geom/virstor
KMOD= geom_virstor
SRCS= g_virstor.c g_virstor_md.c binstream.c
.include <bsd.kmod.mk>