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:
parent
a4c30a2063
commit
27bd800e61
@ -174,6 +174,8 @@
|
||||
..
|
||||
stripe
|
||||
..
|
||||
virstor
|
||||
..
|
||||
..
|
||||
gnu
|
||||
posix
|
||||
|
@ -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 \
|
||||
|
@ -16,5 +16,6 @@ SUBDIR+=part
|
||||
SUBDIR+=raid3
|
||||
SUBDIR+=shsec
|
||||
SUBDIR+=stripe
|
||||
SUBDIR+=virstor
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
13
sbin/geom/class/virstor/Makefile
Normal file
13
sbin/geom/class/virstor/Makefile
Normal 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>
|
578
sbin/geom/class/virstor/geom_virstor.c
Normal file
578
sbin/geom/class/virstor/geom_virstor.c
Normal 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");
|
||||
}
|
||||
}
|
227
sbin/geom/class/virstor/gvirstor.8
Normal file
227
sbin/geom/class/virstor/gvirstor.8
Normal 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
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
185
sys/geom/virstor/binstream.c
Normal file
185
sys/geom/virstor/binstream.c
Normal 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;
|
||||
}
|
93
sys/geom/virstor/binstream.h
Normal file
93
sys/geom/virstor/binstream.h
Normal 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
1864
sys/geom/virstor/g_virstor.c
Normal file
File diff suppressed because it is too large
Load Diff
135
sys/geom/virstor/g_virstor.h
Normal file
135
sys/geom/virstor/g_virstor.h
Normal 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_ */
|
91
sys/geom/virstor/g_virstor_md.c
Normal file
91
sys/geom/virstor/g_virstor_md.c
Normal 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);
|
||||
}
|
69
sys/geom/virstor/g_virstor_md.h
Normal file
69
sys/geom/virstor/g_virstor_md.h
Normal 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_ */
|
8
sys/modules/geom/geom_virstor/Makefile
Normal file
8
sys/modules/geom/geom_virstor/Makefile
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user