code:
/*-
 * Copyright (c) 2002 Poul-Henning Kamp
 * Copyright (c) 2002 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
 * and NAI Labs, the Security Research Division of Network Associates, Inc.
 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
 * DARPA CHATS research program.
 *
 * 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.
 * 3. The names of the authors may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/geom_slice.h 155802 2006-02-18 11:21:17Z pjd $
 */

#ifndef _GEOM_GEOM_SLICE_H_
#define _GEOM_GEOM_SLICE_H_

struct g_slice {
	off_t	offset;
	off_t	length;
	u_int	sectorsize;
	struct	g_provider *provider;
};

struct g_slice_hot {
	off_t	offset;
	off_t	length;
	int	ract;
	int	dact;
	int	wact;
};

typedef int g_slice_start_t (struct bio *bp);

struct g_slicer {
	u_int			nslice;
	u_int			nprovider;
	struct g_slice		*slices;

	u_int			nhotspot;
	struct g_slice_hot	*hotspot;

	void			*softc;
	g_slice_start_t		*start;
	g_event_t		*hot;
};

g_dumpconf_t g_slice_dumpconf;
int g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...);
void g_slice_spoiled(struct g_consumer *cp);
void g_slice_orphan(struct g_consumer *cp);
#define G_SLICE_CONFIG_CHECK	0
#define G_SLICE_CONFIG_SET	1
#define G_SLICE_CONFIG_FORCE	2
struct g_geom * g_slice_new(struct g_class *mp, u_int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start);

int g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact);
#define G_SLICE_HOT_ALLOW	1
#define G_SLICE_HOT_DENY	2
#define G_SLICE_HOT_START	4
#define G_SLICE_HOT_CALL	8

int g_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp);

void g_slice_finish_hot(struct bio *bp);

#endif /* _GEOM_GEOM_SLICE_H_ */


code:
/*-
 * Copyright (c) 2004 Poul-Henning Kamp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/geom_vfs.h 183754 2008-10-10 21:23:50Z attilio $
 */

#ifndef _GEOM_GEOM_VFS_H_
#define _GEOM_GEOM_VFS_H_

struct vnode;
struct bufobj;
struct buf;

extern struct buf_ops *g_vfs_bufops;

void g_vfs_strategy(struct bufobj *bo, struct buf *bp);
int g_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr);
void g_vfs_close(struct g_consumer *cp);

#endif /* _GEOM_GEOM_VFS_H_ */

repo_name: veiledmerc/mira

license: mit


code:
/*-
 * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/journal/g_journal.h 185693 2008-12-06 11:33:10Z trasz $
 */

#ifndef	_G_JOURNAL_H_
#define	_G_JOURNAL_H_

#include <sys/endian.h>
#include <sys/md5.h>
#ifdef _KERNEL
#include <sys/bio.h>
#endif

#define	G_JOURNAL_CLASS_NAME	"JOURNAL"

#define	G_JOURNAL_MAGIC		"GEOM::JOURNAL"
/*
 * Version history:
 * 0 - Initial version number.
 */
#define	G_JOURNAL_VERSION	0

#ifdef _KERNEL
extern int g_journal_debug;

#define	GJ_DEBUG(lvl, ...)	do {					\
	if (g_journal_debug >= (lvl)) {					\
		printf("GEOM_JOURNAL");					\
		if (g_journal_debug > 0)				\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	GJ_LOGREQ(lvl, bp, ...)	do {					\
	if (g_journal_debug >= (lvl)) {					\
		printf("GEOM_JOURNAL");					\
		if (g_journal_debug > 0)				\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

#define	JEMPTY(sc)	((sc)->sc_journal_offset -			\
			 (sc)->sc_jprovider->sectorsize ==		\
			 (sc)->sc_active.jj_offset &&			\
			 (sc)->sc_current_count == 0)

#define	GJ_BIO_REGULAR		0x00
#define	GJ_BIO_READ		0x01
#define	GJ_BIO_JOURNAL		0x02
#define	GJ_BIO_COPY		0x03
#define	GJ_BIO_MASK		0x0f

#if 0
#define	GJF_BIO_DONT_FREE	0x10
#define	GJF_BIO_MASK		0xf0
#endif

#define	GJF_DEVICE_HARDCODED		0x0001
#define	GJF_DEVICE_DESTROY		0x0010
#define	GJF_DEVICE_SWITCH		0x0020
#define	GJF_DEVICE_BEFORE_SWITCH	0x0040
#define	GJF_DEVICE_CLEAN		0x0080
#define	GJF_DEVICE_CHECKSUM		0x0100

#define	GJ_HARD_LIMIT		64

/*
 * We keep pointers to journaled data in bio structure and because we
 * need to store two off_t values (offset in data provider and offset in
 * journal), we have to borrow bio_completed field for this.
 */
#define	bio_joffset	bio_completed
/*
 * Use bio_caller1 field as a pointer in queue.
 */
#define	bio_next	bio_caller1

/*
 * There are two such structures maintained inside each journaled device.
 * One describes active part of the journal, were recent requests are stored.
 * The second describes the last consistent part of the journal with requests
 * that are copied to the destination provider.
 */
struct g_journal_journal {
	struct bio	*jj_queue;	/* Cached journal entries. */
	off_t		 jj_offset;	/* Journal's start offset. */
};

struct g_journal_softc {
	uint32_t	 sc_id;
	uint8_t		 sc_type;
	uint8_t		 sc_orig_type;
	struct g_geom	*sc_geom;
	u_int		 sc_flags;
	struct mtx	 sc_mtx;
	off_t		 sc_mediasize;
	u_int		 sc_sectorsize;
#define	GJ_FLUSH_DATA		0x01
#define	GJ_FLUSH_JOURNAL	0x02
	u_int		 sc_bio_flush;

	uint32_t	 sc_journal_id;
	uint32_t	 sc_journal_next_id;
	int		 sc_journal_copying;
	off_t		 sc_journal_offset;
	off_t		 sc_journal_previous_id;

	struct bio_queue_head sc_back_queue;
	struct bio_queue_head sc_regular_queue;

	struct bio_queue_head sc_delayed_queue;
	int		 sc_delayed_count;

	struct bio	*sc_current_queue;
	int		 sc_current_count;

	struct bio	*sc_flush_queue;
	int		 sc_flush_count;
	int		 sc_flush_in_progress;

	struct bio	*sc_copy_queue;
	int		 sc_copy_in_progress;

	struct g_consumer *sc_dconsumer;
	struct g_consumer *sc_jconsumer;

	struct g_journal_journal sc_inactive;
	struct g_journal_journal sc_active;

	off_t		 sc_jstart;	/* Journal space start offset. */
	off_t		 sc_jend;	/* Journal space end offset. */

	struct callout	 sc_callout;
	struct proc	*sc_worker;

	struct root_hold_token *sc_rootmount;
};
#define	sc_dprovider	sc_dconsumer->provider
#define	sc_jprovider	sc_jconsumer->provider
#define	sc_name		sc_dprovider->name

#define	GJQ_INSERT_HEAD(head, bp)	do {				\
	(bp)->bio_next = (head);					\
	(head) = (bp);							\
} while (0)
#define	GJQ_INSERT_AFTER(head, bp, pbp)	do {				\
	if ((pbp) == NULL)						\
		GJQ_INSERT_HEAD(head, bp);				\
	else {								\
		(bp)->bio_next = (pbp)->bio_next;			\
		(pbp)->bio_next = (bp);					\
	}								\
} while (0)
#define	GJQ_FIRST(head)	(head)
#define	GJQ_REMOVE(head, bp)	do {					\
	struct bio *_bp;						\
									\
	if ((head) == (bp)) {						\
		(head) = (bp)->bio_next;				\
		(bp)->bio_next = NULL;					\
		break;							\
	}								\
	for (_bp = (head); _bp->bio_next != NULL; _bp = _bp->bio_next) {\
		if (_bp->bio_next == (bp))				\
			break;						\
	}								\
	KASSERT(_bp->bio_next != NULL, ("NULL bio_next"));		\
	KASSERT(_bp->bio_next == (bp), ("bio_next != bp"));		\
	_bp->bio_next = (bp)->bio_next;					\
	(bp)->bio_next = NULL;						\
} while (0)
#define GJQ_FOREACH(head, bp)						\
	for ((bp) = (head); (bp) != NULL; (bp) = (bp)->bio_next)

#define	GJ_HEADER_MAGIC	"GJHDR"

struct g_journal_header {
	char		jh_magic[sizeof(GJ_HEADER_MAGIC)];
	uint32_t	jh_journal_id;
	uint32_t	jh_journal_next_id;
} __packed;

struct g_journal_entry {
	uint64_t	je_joffset;
	uint64_t	je_offset;
	uint64_t	je_length;
} __packed;

#define	GJ_RECORD_HEADER_MAGIC		"GJRHDR"
#define	GJ_RECORD_HEADER_NENTRIES	(20)
#define	GJ_RECORD_MAX_SIZE(sc)	\
	((sc)->sc_jprovider->sectorsize + GJ_RECORD_HEADER_NENTRIES * MAXPHYS)
#define	GJ_VALIDATE_OFFSET(offset, sc)	do {				\
	if ((offset) + GJ_RECORD_MAX_SIZE(sc) >= (sc)->sc_jend) {	\
		(offset) = (sc)->sc_jstart;				\
		GJ_DEBUG(2, "Starting from the begining (%s).",		\
		    (sc)->sc_name);					\
	}								\
} while (0)

struct g_journal_record_header {
	char		jrh_magic[sizeof(GJ_RECORD_HEADER_MAGIC)];
	uint32_t	jrh_journal_id;
	uint16_t	jrh_nentries;
	u_char		jrh_sum[8];
	struct g_journal_entry jrh_entries[GJ_RECORD_HEADER_NENTRIES];
} __packed;

typedef int (g_journal_clean_t)(struct mount *mp);
typedef void (g_journal_dirty_t)(struct g_consumer *cp);

struct g_journal_desc {
	const char		*jd_fstype;
	g_journal_clean_t	*jd_clean;
	g_journal_dirty_t	*jd_dirty;
};

/* Supported file systems. */
extern const struct g_journal_desc g_journal_ufs;

#define	GJ_TIMER_START(lvl, bt)	do {					\
	if (g_journal_debug >= (lvl))					\
		binuptime(bt);						\
} while (0)
#define	GJ_TIMER_STOP(lvl, bt, ...)	do {				\
	if (g_journal_debug >= (lvl)) {					\
		struct bintime _bt2;					\
		struct timeval _tv;					\
									\
		binuptime(&_bt2);					\
		bintime_sub(&_bt2, bt);					\
		bintime2timeval(&_bt2, &_tv);				\
		printf("GEOM_JOURNAL");					\
		if (g_journal_debug > 0)				\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf(": %jd.%06jds\n", (intmax_t)_tv.tv_sec,		\
		    (intmax_t)_tv.tv_usec);				\
	}								\
} while (0)
#endif	/* _KERNEL */

#define	GJ_TYPE_DATA		0x01
#define	GJ_TYPE_JOURNAL		0x02
#define	GJ_TYPE_COMPLETE	(GJ_TYPE_DATA|GJ_TYPE_JOURNAL)

#define	GJ_FLAG_CLEAN		0x01
#define	GJ_FLAG_CHECKSUM	0x02

struct g_journal_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	uint32_t	md_id;		/* Journal unique ID. */
	uint8_t		md_type;	/* Provider type. */
	uint64_t	md_jstart;	/* Journal space start offset. */
	uint64_t	md_jend;	/* Journal space end offset. */
	uint64_t	md_joffset;	/* Last known consistent journal offset. */
	uint32_t	md_jid;		/* Last known consistent journal ID. */
	uint64_t	md_flags;	/* Journal flags. */
	char		md_provider[16]; /* Hardcoded provider. */
	uint64_t	md_provsize;	/* Provider's size. */
	u_char		md_hash[16];	/* MD5 hash. */
};
static __inline void
journal_metadata_encode(struct g_journal_metadata *md, u_char *data)
{
	MD5_CTX ctx;

	bcopy(md->md_magic, data, 16);
	le32enc(data + 16, md->md_version);
	le32enc(data + 20, md->md_id);
	*(data + 24) = md->md_type;
	le64enc(data + 25, md->md_jstart);
	le64enc(data + 33, md->md_jend);
	le64enc(data + 41, md->md_joffset);
	le32enc(data + 49, md->md_jid);
	le64enc(data + 53, md->md_flags);
	bcopy(md->md_provider, data + 61, 16);
	le64enc(data + 77, md->md_provsize);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 85);
	MD5Final(md->md_hash, &ctx);
	bcopy(md->md_hash, data + 85, 16);
}
static __inline int
journal_metadata_decode_v0(const u_char *data, struct g_journal_metadata *md)
{
	MD5_CTX ctx;

	md->md_id = le32dec(data + 20);
	md->md_type = *(data + 24);
	md->md_jstart = le64dec(data + 25);
	md->md_jend = le64dec(data + 33);
	md->md_joffset = le64dec(data + 41);
	md->md_jid = le32dec(data + 49);
	md->md_flags = le64dec(data + 53);
	bcopy(data + 61, md->md_provider, 16);
	md->md_provsize = le64dec(data + 77);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 85);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 85, 16) != 0)
		return (EINVAL);
	return (0);
}
static __inline int
journal_metadata_decode(const u_char *data, struct g_journal_metadata *md)
{
	int error;

	bcopy(data, md->md_magic, 16);
	md->md_version = le32dec(data + 16);
	switch (md->md_version) {
	case 0:
		error = journal_metadata_decode_v0(data, md);
		break;
	default:
		error = EINVAL;
		break;
	}
	return (error);
}

static __inline void
journal_metadata_dump(const struct g_journal_metadata *md)
{
	static const char hex[] = "0123456789abcdef";
	char hash[16 * 2 + 1];
	u_int i;

	printf("     magic: %s\n", md->md_magic);
	printf("   version: %u\n", (u_int)md->md_version);
	printf("        id: %u\n", (u_int)md->md_id);
	printf("      type: %u\n", (u_int)md->md_type);
	printf("     start: %ju\n", (uintmax_t)md->md_jstart);
	printf("       end: %ju\n", (uintmax_t)md->md_jend);
	printf("   joffset: %ju\n", (uintmax_t)md->md_joffset);
	printf("       jid: %u\n", (u_int)md->md_jid);
	printf("     flags: %u\n", (u_int)md->md_flags);
	printf("hcprovider: %s\n", md->md_provider);
	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
	bzero(hash, sizeof(hash));
	for (i = 0; i < 16; i++) {
		hash[i * 2] = hex[md->md_hash[i] >> 4];
		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
	}
	printf("  MD5 hash: %s\n", hash);
}
#endif	/* !_G_JOURNAL_H_ */


code:
/*-
 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/label/g_label.h 199875 2009-11-28 11:57:43Z trasz $
 */

#ifndef	_G_LABEL_H_
#define	_G_LABEL_H_

#include <sys/endian.h>
#ifdef _KERNEL
#include <sys/sysctl.h>
#endif

#define	G_LABEL_CLASS_NAME	"LABEL"

#define	G_LABEL_MAGIC		"GEOM::LABEL"
/*
 * Version history:
 * 1 - Initial version number.
 * 2 - Added md_provsize field to metadata.
 */
#define	G_LABEL_VERSION		2
#define	G_LABEL_DIR		"label"

#ifdef _KERNEL
extern u_int g_label_debug;

#define	G_LABEL_DEBUG(lvl, ...)	do {					\
	if (g_label_debug >= (lvl)) {					\
		printf("GEOM_LABEL");					\
		if (g_label_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)

SYSCTL_DECL(_kern_geom_label);

#define	G_LABEL_INIT(kind, label, descr) 				\
	SYSCTL_NODE(_kern_geom_label, OID_AUTO, kind, CTLFLAG_RD,	\
	    NULL, "");							\
	SYSCTL_INT(_kern_geom_label_##kind, OID_AUTO, enable, 		\
	    CTLFLAG_RW, &label.ld_enabled, 1, descr);			\
	TUNABLE_INT("kern.geom.label." __XSTRING(kind) ".enable",	\
	    &label.ld_enabled)

typedef void g_label_taste_t (struct g_consumer *cp, char *label, size_t size);

struct g_label_desc {
	g_label_taste_t	*ld_taste;
	char		*ld_dir;
	int		 ld_enabled;
};

/* Supported labels. */
extern struct g_label_desc g_label_ufs_id;
extern struct g_label_desc g_label_ufs_volume;
extern struct g_label_desc g_label_iso9660;
extern struct g_label_desc g_label_msdosfs;
extern struct g_label_desc g_label_ext2fs;
extern struct g_label_desc g_label_reiserfs;
extern struct g_label_desc g_label_ntfs;
extern struct g_label_desc g_label_gpt;
extern struct g_label_desc g_label_gpt_uuid;
#endif	/* _KERNEL */

struct g_label_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	char		md_label[16];	/* Label. */
	uint64_t	md_provsize;	/* Provider's size. */
};
static __inline void
label_metadata_encode(const struct g_label_metadata *md, u_char *data)
{

	bcopy(md->md_magic, data, sizeof(md->md_magic));
	le32enc(data + 16, md->md_version);
	bcopy(md->md_label, data + 20, sizeof(md->md_label));
	le64enc(data + 36, md->md_provsize);
}
static __inline void
label_metadata_decode(const u_char *data, struct g_label_metadata *md)
{

	bcopy(data, md->md_magic, sizeof(md->md_magic));
	md->md_version = le32dec(data + 16);
	bcopy(data + 20, md->md_label, sizeof(md->md_label));
	md->md_provsize = le64dec(data + 36);
}
#endif	/* _G_LABEL_H_ */


code:
/*-
 * Copyright (c) 2006 Tobias Reifenberger
 * 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: release/9.0.0/sys/geom/label/g_label_msdosfs.h 162834 2006-09-30 08:16:49Z pjd $
 */

#include <sys/types.h>

/*
 * Conversion macros for little endian encoded unsigned integers
 * in byte streams to the local unsigned integer format.
 */
#define UINT16BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1])))
#define UINT32BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1]) +		\
	    (65536*(p)[2]) + (16777216*(p)[3])))

/*
 * All following structures are according to:
 *
 * Microsoft Extensible Firmware Initiative FAT32 File System Specification
 * FAT: General Overview of On-Disk Format
 * Version 1.03, December 6, 2000
 * Microsoft Corporation
 */

/*
 * FAT boot sector and boot parameter block for
 * FAT12 and FAT16 volumes
 */
typedef struct fat_bsbpb {
	/* common fields */
	uint8_t BS_jmpBoot[3];
	uint8_t BS_OEMName[8];
	uint8_t BPB_BytsPerSec[2];
	uint8_t BPB_SecPerClus;
	uint8_t BPB_RsvdSecCnt[2];
	uint8_t BPB_NumFATs;
	uint8_t BPB_RootEntCnt[2];
	uint8_t BPB_TotSec16[2];
	uint8_t BPB_Media;
	uint8_t BPB_FATSz16[2];
	uint8_t BPB_SecPerTrack[2];
	uint8_t BPB_NumHeads[2];
	uint8_t BPB_HiddSec[4];
	uint8_t BPB_TotSec32[4];
	/* FAT12/FAT16 only fields */
	uint8_t BS_DrvNum;
	uint8_t BS_Reserved1;
	uint8_t BS_BootSig;
	uint8_t BS_VolID[4];
	uint8_t BS_VolLab[11];
	uint8_t BS_FilSysType[8];
} FAT_BSBPB; /* 62 bytes */

/*
 * FAT boot sector and boot parameter block for
 * FAT32 volumes
 */
typedef struct fat32_bsbpb {
	/* common fields */
	uint8_t BS_jmpBoot[3];
	uint8_t BS_OEMName[8];
	uint8_t BPB_BytsPerSec[2];
	uint8_t BPB_SecPerClus;
	uint8_t BPB_RsvdSecCnt[2];
	uint8_t BPB_NumFATs;
	uint8_t BPB_RootEntCnt[2];
	uint8_t BPB_TotSec16[2];
	uint8_t BPB_Media;
	uint8_t BPB_FATSz16[2];
	uint8_t BPB_SecPerTrack[2];
	uint8_t BPB_NumHeads[2];
	uint8_t BPB_HiddSec[4];
	uint8_t BPB_TotSec32[4];
	/* FAT32 only fields */
	uint8_t BPB_FATSz32[4];
	uint8_t BPB_ExtFlags[2];
	uint8_t BPB_FSVer[2];
	uint8_t BPB_RootClus[4];
	uint8_t BPB_FSInfo[2];
	uint8_t BPB_BkBootSec[2];
	uint8_t BPB_Reserved[12];
	uint8_t BS_DrvNum;
	uint8_t BS_Reserved1;
	uint8_t BS_BootSig;
	uint8_t BS_VolID[4];
	uint8_t BS_VolLab[11];
	uint8_t BS_FilSysType[8];
} FAT32_BSBPB; /* 90 bytes */

/*
 * FAT directory entry structure
 */
#define	FAT_DES_ATTR_READ_ONLY	0x01
#define	FAT_DES_ATTR_HIDDEN	0x02
#define	FAT_DES_ATTR_SYSTEM	0x04
#define	FAT_DES_ATTR_VOLUME_ID	0x08
#define	FAT_DES_ATTR_DIRECTORY	0x10
#define	FAT_DES_ATTR_ARCHIVE	0x20
#define	FAT_DES_ATTR_LONG_NAME	(FAT_DES_ATTR_READ_ONLY |		\
				 FAT_DES_ATTR_HIDDEN |			\
				 FAT_DES_ATTR_SYSTEM |			\
				 FAT_DES_ATTR_VOLUME_ID)

typedef struct fat_des {
	uint8_t DIR_Name[11];
	uint8_t DIR_Attr;
	uint8_t DIR_NTRes;
	uint8_t DIR_CrtTimeTenth;
	uint8_t DIR_CrtTime[2];
	uint8_t DIR_CrtDate[2];
	uint8_t DIR_LstAccDate[2];
	uint8_t DIR_FstClusHI[2];
	uint8_t DIR_WrtTime[2];
	uint8_t DIR_WrtDate[2];
	uint8_t DIR_FstClusLO[2];
	uint8_t DIR_FileSize[4];
} FAT_DES;


code:
/*-
 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/mirror/g_mirror.h 200086 2009-12-03 21:47:51Z mav $
 */

#ifndef	_G_MIRROR_H_
#define	_G_MIRROR_H_

#include <sys/endian.h>
#include <sys/md5.h>

#define	G_MIRROR_CLASS_NAME	"MIRROR"

#define	G_MIRROR_MAGIC		"GEOM::MIRROR"
/*
 * Version history:
 * 0 - Initial version number.
 * 1 - Added 'prefer' balance algorithm.
 * 2 - Added md_genid field to metadata.
 * 3 - Added md_provsize field to metadata.
 * 4 - Added 'no failure synchronization' flag.
 */
#define	G_MIRROR_VERSION	4

#define	G_MIRROR_BALANCE_NONE		0
#define	G_MIRROR_BALANCE_ROUND_ROBIN	1
#define	G_MIRROR_BALANCE_LOAD		2
#define	G_MIRROR_BALANCE_SPLIT		3
#define	G_MIRROR_BALANCE_PREFER		4
#define	G_MIRROR_BALANCE_MIN		G_MIRROR_BALANCE_NONE
#define	G_MIRROR_BALANCE_MAX		G_MIRROR_BALANCE_PREFER

#define	G_MIRROR_DISK_FLAG_DIRTY		0x0000000000000001ULL
#define	G_MIRROR_DISK_FLAG_SYNCHRONIZING	0x0000000000000002ULL
#define	G_MIRROR_DISK_FLAG_FORCE_SYNC		0x0000000000000004ULL
#define	G_MIRROR_DISK_FLAG_INACTIVE		0x0000000000000008ULL
#define	G_MIRROR_DISK_FLAG_HARDCODED		0x0000000000000010ULL
#define	G_MIRROR_DISK_FLAG_BROKEN		0x0000000000000020ULL
#define	G_MIRROR_DISK_FLAG_MASK		(G_MIRROR_DISK_FLAG_DIRTY |	\
					 G_MIRROR_DISK_FLAG_SYNCHRONIZING | \
					 G_MIRROR_DISK_FLAG_FORCE_SYNC | \
					 G_MIRROR_DISK_FLAG_INACTIVE)

#define	G_MIRROR_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
#define	G_MIRROR_DEVICE_FLAG_NOFAILSYNC	0x0000000000000002ULL
#define	G_MIRROR_DEVICE_FLAG_MASK	(G_MIRROR_DEVICE_FLAG_NOAUTOSYNC | \
					 G_MIRROR_DEVICE_FLAG_NOFAILSYNC)

#ifdef _KERNEL
extern u_int g_mirror_debug;

#define	G_MIRROR_DEBUG(lvl, ...)	do {				\
	if (g_mirror_debug >= (lvl)) {					\
		printf("GEOM_MIRROR");					\
		if (g_mirror_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_MIRROR_LOGREQ(lvl, bp, ...)	do {				\
	if (g_mirror_debug >= (lvl)) {					\
		printf("GEOM_MIRROR");					\
		if (g_mirror_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

#define	G_MIRROR_BIO_FLAG_REGULAR	0x01
#define	G_MIRROR_BIO_FLAG_SYNC		0x02

/*
 * Informations needed for synchronization.
 */
struct g_mirror_disk_sync {
	struct g_consumer *ds_consumer;	/* Consumer connected to our mirror. */
	off_t		  ds_offset;	/* Offset of next request to send. */
	off_t		  ds_offset_done; /* Offset of already synchronized
					   region. */
	u_int		  ds_syncid;	/* Disk's synchronization ID. */
	u_int		  ds_inflight;	/* Number of in-flight sync requests. */
	struct bio	**ds_bios;	/* BIOs for synchronization I/O. */
};

/*
 * Informations needed for synchronization.
 */
struct g_mirror_device_sync {
	struct g_geom	*ds_geom;	/* Synchronization geom. */
	u_int		 ds_ndisks;	/* Number of disks in SYNCHRONIZING
					   state. */
};

#define	G_MIRROR_DISK_STATE_NONE		0
#define	G_MIRROR_DISK_STATE_NEW			1
#define	G_MIRROR_DISK_STATE_ACTIVE		2
#define	G_MIRROR_DISK_STATE_STALE		3
#define	G_MIRROR_DISK_STATE_SYNCHRONIZING	4
#define	G_MIRROR_DISK_STATE_DISCONNECTED	5
#define	G_MIRROR_DISK_STATE_DESTROY		6
struct g_mirror_disk {
	uint32_t	 d_id;		/* Disk ID. */
	struct g_consumer *d_consumer;	/* Consumer. */
	struct g_mirror_softc	*d_softc; /* Back-pointer to softc. */
	int		 d_state;	/* Disk state. */
	u_int		 d_priority;	/* Disk priority. */
	u_int		 load;		/* Averaged queue length */
	off_t		 d_last_offset;	/* Last read offset */
	uint64_t	 d_flags;	/* Additional flags. */
	u_int		 d_genid;	/* Disk's generation ID. */
	struct g_mirror_disk_sync d_sync;/* Sync information. */
	LIST_ENTRY(g_mirror_disk) d_next;
};
#define	d_name	d_consumer->provider->name

#define	G_MIRROR_EVENT_DONTWAIT	0x1
#define	G_MIRROR_EVENT_WAIT	0x2
#define	G_MIRROR_EVENT_DEVICE	0x4
#define	G_MIRROR_EVENT_DONE	0x8
struct g_mirror_event {
	struct g_mirror_disk	*e_disk;
	int			 e_state;
	int			 e_flags;
	int			 e_error;
	TAILQ_ENTRY(g_mirror_event) e_next;
};

#define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
#define	G_MIRROR_DEVICE_FLAG_WAIT	0x0200000000000000ULL
#define	G_MIRROR_DEVICE_FLAG_DESTROYING	0x0400000000000000ULL

#define	G_MIRROR_DEVICE_STATE_STARTING		0
#define	G_MIRROR_DEVICE_STATE_RUNNING		1

/* Bump syncid on first write. */
#define	G_MIRROR_BUMP_SYNCID	0x1
/* Bump genid immediately. */
#define	G_MIRROR_BUMP_GENID	0x2
struct g_mirror_softc {
	u_int		sc_state;	/* Device state. */
	uint32_t	sc_slice;	/* Slice size. */
	uint8_t		sc_balance;	/* Balance algorithm. */
	uint64_t	sc_mediasize;	/* Device size. */
	uint32_t	sc_sectorsize;	/* Sector size. */
	uint64_t	sc_flags;	/* Additional flags. */

	struct g_geom	*sc_geom;
	struct g_provider *sc_provider;

	uint32_t	sc_id;		/* Mirror unique ID. */

	struct sx	 sc_lock;
	struct bio_queue_head sc_queue;
	struct mtx	 sc_queue_mtx;
	struct proc	*sc_worker;
	struct bio_queue_head sc_regular_delayed; /* Delayed I/O requests due
						     collision with sync
						     requests. */
	struct bio_queue_head sc_inflight; /* In-flight regular write
					      requests. */
	struct bio_queue_head sc_sync_delayed; /* Delayed sync requests due
						  collision with regular
						  requests. */

	LIST_HEAD(, g_mirror_disk) sc_disks;
	u_int		sc_ndisks;	/* Number of disks. */
	struct g_mirror_disk *sc_hint;

	u_int		sc_genid;	/* Generation ID. */
	u_int		sc_syncid;	/* Synchronization ID. */
	int		sc_bump_id;
	struct g_mirror_device_sync sc_sync;
	int		sc_idle;	/* DIRTY flags removed. */
	time_t		sc_last_write;
	u_int		sc_writes;

	TAILQ_HEAD(, g_mirror_event) sc_events;
	struct mtx	sc_events_mtx;

	struct callout	sc_callout;

	struct root_hold_token *sc_rootmount;
};
#define	sc_name	sc_geom->name

u_int g_mirror_ndisks(struct g_mirror_softc *sc, int state);
#define	G_MIRROR_DESTROY_SOFT		0
#define	G_MIRROR_DESTROY_DELAYED	1
#define	G_MIRROR_DESTROY_HARD		2
int g_mirror_destroy(struct g_mirror_softc *sc, int how);
int g_mirror_event_send(void *arg, int state, int flags);
struct g_mirror_metadata;
int g_mirror_add_disk(struct g_mirror_softc *sc, struct g_provider *pp,
    struct g_mirror_metadata *md);
int g_mirror_read_metadata(struct g_consumer *cp, struct g_mirror_metadata *md);
void g_mirror_fill_metadata(struct g_mirror_softc *sc,
    struct g_mirror_disk *disk, struct g_mirror_metadata *md);
void g_mirror_update_metadata(struct g_mirror_disk *disk);

g_ctl_req_t g_mirror_config;
#endif	/* _KERNEL */

struct g_mirror_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	char		md_name[16];	/* Mirror name. */
	uint32_t	md_mid;		/* Mirror unique ID. */
	uint32_t	md_did;		/* Disk unique ID. */
	uint8_t		md_all;		/* Number of disks in mirror. */
	uint32_t	md_genid;	/* Generation ID. */
	uint32_t	md_syncid;	/* Synchronization ID. */
	uint8_t		md_priority;	/* Disk priority. */
	uint32_t	md_slice;	/* Slice size. */
	uint8_t		md_balance;	/* Balance type. */
	uint64_t	md_mediasize;	/* Size of the smallest
					   disk in mirror. */
	uint32_t	md_sectorsize;	/* Sector size. */
	uint64_t	md_sync_offset;	/* Synchronized offset. */
	uint64_t	md_mflags;	/* Additional mirror flags. */
	uint64_t	md_dflags;	/* Additional disk flags. */
	char		md_provider[16]; /* Hardcoded provider. */
	uint64_t	md_provsize;	/* Provider's size. */
	u_char		md_hash[16];	/* MD5 hash. */
};
static __inline void
mirror_metadata_encode(struct g_mirror_metadata *md, u_char *data)
{
	MD5_CTX ctx;

	bcopy(md->md_magic, data, 16);
	le32enc(data + 16, md->md_version);
	bcopy(md->md_name, data + 20, 16);
	le32enc(data + 36, md->md_mid);
	le32enc(data + 40, md->md_did);
	*(data + 44) = md->md_all;
	le32enc(data + 45, md->md_genid);
	le32enc(data + 49, md->md_syncid);
	*(data + 53) = md->md_priority;
	le32enc(data + 54, md->md_slice);
	*(data + 58) = md->md_balance;
	le64enc(data + 59, md->md_mediasize);
	le32enc(data + 67, md->md_sectorsize);
	le64enc(data + 71, md->md_sync_offset);
	le64enc(data + 79, md->md_mflags);
	le64enc(data + 87, md->md_dflags);
	bcopy(md->md_provider, data + 95, 16);
	le64enc(data + 111, md->md_provsize);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 119);
	MD5Final(md->md_hash, &ctx);
	bcopy(md->md_hash, data + 119, 16);
}
static __inline int
mirror_metadata_decode_v0v1(const u_char *data, struct g_mirror_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_mid = le32dec(data + 36);
	md->md_did = le32dec(data + 40);
	md->md_all = *(data + 44);
	md->md_syncid = le32dec(data + 45);
	md->md_priority = *(data + 49);
	md->md_slice = le32dec(data + 50);
	md->md_balance = *(data + 54);
	md->md_mediasize = le64dec(data + 55);
	md->md_sectorsize = le32dec(data + 63);
	md->md_sync_offset = le64dec(data + 67);
	md->md_mflags = le64dec(data + 75);
	md->md_dflags = le64dec(data + 83);
	bcopy(data + 91, md->md_provider, 16);
	bcopy(data + 107, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 107);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 107, 16) != 0)
		return (EINVAL);

	/* New fields. */
	md->md_genid = 0;
	md->md_provsize = 0;

	return (0);
}
static __inline int
mirror_metadata_decode_v2(const u_char *data, struct g_mirror_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_mid = le32dec(data + 36);
	md->md_did = le32dec(data + 40);
	md->md_all = *(data + 44);
	md->md_genid = le32dec(data + 45);
	md->md_syncid = le32dec(data + 49);
	md->md_priority = *(data + 53);
	md->md_slice = le32dec(data + 54);
	md->md_balance = *(data + 58);
	md->md_mediasize = le64dec(data + 59);
	md->md_sectorsize = le32dec(data + 67);
	md->md_sync_offset = le64dec(data + 71);
	md->md_mflags = le64dec(data + 79);
	md->md_dflags = le64dec(data + 87);
	bcopy(data + 95, md->md_provider, 16);
	bcopy(data + 111, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 111);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 111, 16) != 0)
		return (EINVAL);

	/* New fields. */
	md->md_provsize = 0;

	return (0);
}
static __inline int
mirror_metadata_decode_v3v4(const u_char *data, struct g_mirror_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_mid = le32dec(data + 36);
	md->md_did = le32dec(data + 40);
	md->md_all = *(data + 44);
	md->md_genid = le32dec(data + 45);
	md->md_syncid = le32dec(data + 49);
	md->md_priority = *(data + 53);
	md->md_slice = le32dec(data + 54);
	md->md_balance = *(data + 58);
	md->md_mediasize = le64dec(data + 59);
	md->md_sectorsize = le32dec(data + 67);
	md->md_sync_offset = le64dec(data + 71);
	md->md_mflags = le64dec(data + 79);
	md->md_dflags = le64dec(data + 87);
	bcopy(data + 95, md->md_provider, 16);
	md->md_provsize = le64dec(data + 111);
	bcopy(data + 119, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 119);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 119, 16) != 0)
		return (EINVAL);
	return (0);
}
static __inline int
mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md)
{
	int error;

	bcopy(data, md->md_magic, 16);
	md->md_version = le32dec(data + 16);
	switch (md->md_version) {
	case 0:
	case 1:
		error = mirror_metadata_decode_v0v1(data, md);
		break;
	case 2:
		error = mirror_metadata_decode_v2(data, md);
		break;
	case 3:
	case 4:
		error = mirror_metadata_decode_v3v4(data, md);
		break;
	default:
		error = EINVAL;
		break;
	}
	return (error);
}

static __inline const char *
balance_name(u_int balance)
{
	static const char *algorithms[] = {
		[G_MIRROR_BALANCE_NONE] = "none",
		[G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin",
		[G_MIRROR_BALANCE_LOAD] = "load",
		[G_MIRROR_BALANCE_SPLIT] = "split",
		[G_MIRROR_BALANCE_PREFER] = "prefer",
		[G_MIRROR_BALANCE_MAX + 1] = "unknown"
	};

	if (balance > G_MIRROR_BALANCE_MAX)
		balance = G_MIRROR_BALANCE_MAX + 1;

	return (algorithms[balance]);
}

static __inline int
balance_id(const char *name)
{
	static const char *algorithms[] = {
		[G_MIRROR_BALANCE_NONE] = "none",
		[G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin",
		[G_MIRROR_BALANCE_LOAD] = "load",
		[G_MIRROR_BALANCE_SPLIT] = "split",
		[G_MIRROR_BALANCE_PREFER] = "prefer"
	};
	int n;

	for (n = G_MIRROR_BALANCE_MIN; n <= G_MIRROR_BALANCE_MAX; n++) {
		if (strcmp(name, algorithms[n]) == 0)
			return (n);
	}
	return (-1);
}

static __inline void
mirror_metadata_dump(const struct g_mirror_metadata *md)
{
	static const char hex[] = "0123456789abcdef";
	char hash[16 * 2 + 1];
	u_int i;

	printf("     magic: %s\n", md->md_magic);
	printf("   version: %u\n", (u_int)md->md_version);
	printf("      name: %s\n", md->md_name);
	printf("       mid: %u\n", (u_int)md->md_mid);
	printf("       did: %u\n", (u_int)md->md_did);
	printf("       all: %u\n", (u_int)md->md_all);
	printf("     genid: %u\n", (u_int)md->md_genid);
	printf("    syncid: %u\n", (u_int)md->md_syncid);
	printf("  priority: %u\n", (u_int)md->md_priority);
	printf("     slice: %u\n", (u_int)md->md_slice);
	printf("   balance: %s\n", balance_name((u_int)md->md_balance));
	printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize);
	printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
	printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset);
	printf("    mflags:");
	if (md->md_mflags == 0)
		printf(" NONE");
	else {
		if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0)
			printf(" NOFAILSYNC");
		if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0)
			printf(" NOAUTOSYNC");
	}
	printf("\n");
	printf("    dflags:");
	if (md->md_dflags == 0)
		printf(" NONE");
	else {
		if ((md->md_dflags & G_MIRROR_DISK_FLAG_DIRTY) != 0)
			printf(" DIRTY");
		if ((md->md_dflags & G_MIRROR_DISK_FLAG_SYNCHRONIZING) != 0)
			printf(" SYNCHRONIZING");
		if ((md->md_dflags & G_MIRROR_DISK_FLAG_FORCE_SYNC) != 0)
			printf(" FORCE_SYNC");
		if ((md->md_dflags & G_MIRROR_DISK_FLAG_INACTIVE) != 0)
			printf(" INACTIVE");
	}
	printf("\n");
	printf("hcprovider: %s\n", md->md_provider);
	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
	bzero(hash, sizeof(hash));
	for (i = 0; i < 16; i++) {
		hash[i * 2] = hex[md->md_hash[i] >> 4];
		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
	}
	printf("  MD5 hash: %s\n", hash);
}
#endif	/* !_G_MIRROR_H_ */


code:
/*-
 * Copyright (c) 2010 Edward Tomasz Napierala <trasz@FreeBSD.org>
 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/mountver/g_mountver.h 202437 2010-01-16 09:52:49Z trasz $
 */

#ifndef	_G_MOUNTVER_H_
#define	_G_MOUNTVER_H_

#define	G_MOUNTVER_CLASS_NAME	"MOUNTVER"
#define	G_MOUNTVER_VERSION	4
#define	G_MOUNTVER_SUFFIX	".mountver"

#ifdef _KERNEL

#define	G_MOUNTVER_DEBUG(lvl, ...)	do {				\
	if (g_mountver_debug >= (lvl)) {				\
		printf("GEOM_MOUNTVER");				\
		if (g_mountver_debug > 0)				\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_MOUNTVER_LOGREQ(bp, ...)	do {				\
	if (g_mountver_debug >= 2) {					\
		printf("GEOM_MOUNTVER[2]: ");				\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

struct g_mountver_softc {
	TAILQ_HEAD(, bio)		sc_queue;
	struct mtx			sc_mtx;
	char				*sc_provider_name;
	char				sc_ident[DISK_IDENT_SIZE];
	int				sc_orphaned;
	int				sc_access_r;
	int				sc_access_w;
	int				sc_access_e;
};
#endif	/* _KERNEL */

#endif	/* _G_MOUNTVER_H_ */


code:
/*-
 * Copyright (c) 2006-2007 Matthew Jacob <mjacob@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: release/9.0.0/sys/geom/multipath/g_multipath.h 167050 2007-02-27 04:01:58Z mjacob $
 */
/*
 * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the
 * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM
 * itself, all of which is most gratefully acknowledged.
 */

#ifndef	_G_MULTIPATH_H_
#define	_G_MULTIPATH_H_

#define	G_MULTIPATH_CLASS_NAME	"MULTIPATH"
#define	G_MULTIPATH_VERSION	1
#define	G_MULTIPATH_MAGIC	"GEOM::MULTIPATH"

#include <sys/endian.h>

#ifdef	_KERNEL

struct g_multipath_softc {
	struct g_provider *	pp;
	struct g_consumer *	cp_active;
	char			sc_name[16];
	char			sc_uuid[40];
};
#endif	/* _KERNEL */

struct g_multipath_metadata {
	char		md_magic[16];	/* Magic Value */
	char 		md_uuid[40];	/* more magic */
	char		md_name[16];	/* a friendly name */
	uint32_t	md_version;	/* version */
	uint32_t	md_sectorsize;	/* sectorsize of provider */
	uint64_t	md_size;	/* absolute size of provider */
};

static __inline void
multipath_metadata_encode(const struct g_multipath_metadata *, u_char *);

static __inline void
multipath_metadata_decode(u_char *, struct g_multipath_metadata *);

static __inline void
multipath_metadata_encode(const struct g_multipath_metadata *md, u_char *data)
{
	bcopy(md->md_magic, data, sizeof(md->md_magic));
	data += sizeof(md->md_magic);
	bcopy(md->md_uuid, data, sizeof(md->md_uuid));
	data += sizeof(md->md_uuid);
	bcopy(md->md_name, data, sizeof(md->md_name));
	data += sizeof(md->md_name);
	le32enc(data, md->md_version);
	data += sizeof(md->md_version);
	le32enc(data, md->md_sectorsize);
	data += sizeof(md->md_sectorsize);
	le64enc(data, md->md_size);
}

static __inline void
multipath_metadata_decode(u_char *data, struct g_multipath_metadata *md)
{
	bcopy(data, md->md_magic, sizeof(md->md_magic));
	data += sizeof(md->md_magic);
	bcopy(data, md->md_uuid, sizeof(md->md_uuid));
	data += sizeof(md->md_uuid);
	bcopy(data, md->md_name, sizeof(md->md_name));
	data += sizeof(md->md_name);
	md->md_version = le32dec(data);
	data += sizeof(md->md_version);
	md->md_sectorsize = le32dec(data);
	data += sizeof(md->md_sectorsize);
	md->md_size = le64dec(data);
}
#endif	/* _G_MULTIPATH_H_ */


code:
/*-
 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/nop/g_nop.h 162834 2006-09-30 08:16:49Z pjd $
 */

#ifndef	_G_NOP_H_
#define	_G_NOP_H_

#define	G_NOP_CLASS_NAME	"NOP"
#define	G_NOP_VERSION		4
#define	G_NOP_SUFFIX		".nop"

#ifdef _KERNEL
#define	G_NOP_DEBUG(lvl, ...)	do {					\
	if (g_nop_debug >= (lvl)) {					\
		printf("GEOM_NOP");					\
		if (g_nop_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_NOP_LOGREQ(bp, ...)	do {					\
	if (g_nop_debug >= 2) {						\
		printf("GEOM_NOP[2]: ");				\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

struct g_nop_softc {
	int		sc_error;
	off_t		sc_offset;
	u_int		sc_rfailprob;
	u_int		sc_wfailprob;
	uintmax_t	sc_reads;
	uintmax_t	sc_writes;
	uintmax_t	sc_readbytes;
	uintmax_t	sc_wrotebytes;
};
#endif	/* _KERNEL */

#endif	/* _G_NOP_H_ */


code:
/*-
 * Copyright (c) 2010 Alexander Motin <mav@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: release/9.0.0/sys/geom/raid/g_raid.h 219974 2011-03-24 21:31:32Z mav $
 */

#ifndef	_G_RAID_H_
#define	_G_RAID_H_

#include <sys/param.h>
#include <sys/kobj.h>
#include <sys/bio.h>
#include <sys/time.h>

#define	G_RAID_CLASS_NAME	"RAID"

#define	G_RAID_MAGIC		"GEOM::RAID"

#define	G_RAID_VERSION		0

struct g_raid_md_object;
struct g_raid_tr_object;

#define	G_RAID_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
#define	G_RAID_DEVICE_FLAG_NOFAILSYNC	0x0000000000000002ULL
#define	G_RAID_DEVICE_FLAG_MASK	(G_RAID_DEVICE_FLAG_NOAUTOSYNC | \
					 G_RAID_DEVICE_FLAG_NOFAILSYNC)

#ifdef _KERNEL
extern u_int g_raid_aggressive_spare;
extern u_int g_raid_debug;
extern int g_raid_read_err_thresh;
extern u_int g_raid_start_timeout;
extern struct g_class g_raid_class;

#define	G_RAID_DEBUG(lvl, fmt, ...)	do {				\
	if (g_raid_debug >= (lvl)) {					\
		if (g_raid_debug > 0) {					\
			printf("GEOM_RAID[%u]: " fmt "\n",		\
			    lvl, ## __VA_ARGS__);			\
		} else {						\
			printf("GEOM_RAID: " fmt "\n",			\
			    ## __VA_ARGS__);				\
		}							\
	}								\
} while (0)
#define	G_RAID_DEBUG1(lvl, sc, fmt, ...)	do {			\
	if (g_raid_debug >= (lvl)) {					\
		if (g_raid_debug > 0) {					\
			printf("GEOM_RAID[%u]: %s: " fmt "\n",		\
			    lvl, (sc)->sc_name, ## __VA_ARGS__);	\
		} else {						\
			printf("GEOM_RAID: %s: " fmt "\n",		\
			    (sc)->sc_name, ## __VA_ARGS__);		\
		}							\
	}								\
} while (0)
#define	G_RAID_LOGREQ(lvl, bp, fmt, ...)	do {			\
	if (g_raid_debug >= (lvl)) {					\
		if (g_raid_debug > 0) {					\
			printf("GEOM_RAID[%u]: " fmt " ",		\
			    lvl, ## __VA_ARGS__);			\
		} else							\
			printf("GEOM_RAID: " fmt " ", ## __VA_ARGS__);	\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

/*
 * Flags we use to distinguish I/O initiated by the TR layer to maintain
 * the volume's characteristics, fix subdisks, extra copies of data, etc.
 *
 * G_RAID_BIO_FLAG_SYNC		I/O to update an extra copy of the data
 *				for RAID volumes that maintain extra data
 *				and need to rebuild that data.
 * G_RAID_BIO_FLAG_REMAP	I/O done to try to provoke a subdisk into
 *				doing some desirable action such as bad
 *				block remapping after we detect a bad part
 *				of the disk.
 * G_RAID_BIO_FLAG_LOCKED	I/O holds range lock that should re released.
 *
 * and the following meta item:
 * G_RAID_BIO_FLAG_SPECIAL	And of the I/O flags that need to make it
 *				through the range locking which would
 *				otherwise defer the I/O until after that
 *				range is unlocked.
 */
#define	G_RAID_BIO_FLAG_SYNC		0x01
#define	G_RAID_BIO_FLAG_REMAP		0x02
#define	G_RAID_BIO_FLAG_SPECIAL \
		(G_RAID_BIO_FLAG_SYNC|G_RAID_BIO_FLAG_REMAP)
#define	G_RAID_BIO_FLAG_LOCKED		0x80

struct g_raid_lock {
	off_t			 l_offset;
	off_t			 l_length;
	void			*l_callback_arg;
	int			 l_pending;
	LIST_ENTRY(g_raid_lock)	 l_next;
};

#define	G_RAID_EVENT_WAIT	0x01
#define	G_RAID_EVENT_VOLUME	0x02
#define	G_RAID_EVENT_SUBDISK	0x04
#define	G_RAID_EVENT_DISK	0x08
#define	G_RAID_EVENT_DONE	0x10
struct g_raid_event {
	void			*e_tgt;
	int			 e_event;
	int			 e_flags;
	int			 e_error;
	TAILQ_ENTRY(g_raid_event) e_next;
};
#define G_RAID_DISK_S_NONE		0x00	/* State is unknown. */
#define G_RAID_DISK_S_OFFLINE		0x01	/* Missing disk placeholder. */
#define G_RAID_DISK_S_FAILED		0x02	/* Failed. */
#define G_RAID_DISK_S_STALE_FAILED	0x03	/* Old failed. */
#define G_RAID_DISK_S_SPARE		0x04	/* Hot-spare. */
#define G_RAID_DISK_S_STALE		0x05	/* Old disk, unused now. */
#define G_RAID_DISK_S_ACTIVE		0x06	/* Operational. */

#define G_RAID_DISK_E_DISCONNECTED	0x01

struct g_raid_disk {
	struct g_raid_softc	*d_softc;	/* Back-pointer to softc. */
	struct g_consumer	*d_consumer;	/* GEOM disk consumer. */
	void			*d_md_data;	/* Disk's metadata storage. */
	struct g_kerneldump	 d_kd;		/* Kernel dumping method/args. */
	uint64_t		 d_flags;	/* Additional flags. */
	u_int			 d_state;	/* Disk state. */
	u_int			 d_load;	/* Disk average load. */
	off_t			 d_last_offset;	/* Last head offset. */
	int			 d_read_errs;	/* Count of the read errors */
	TAILQ_HEAD(, g_raid_subdisk)	 d_subdisks; /* List of subdisks. */
	TAILQ_ENTRY(g_raid_disk)	 d_next;	/* Next disk in the node. */
};

#define G_RAID_SUBDISK_S_NONE		0x00	/* Absent. */
#define G_RAID_SUBDISK_S_FAILED		0x01	/* Failed. */
#define G_RAID_SUBDISK_S_NEW		0x02	/* Blank. */
#define G_RAID_SUBDISK_S_REBUILD	0x03	/* Blank + rebuild. */
#define G_RAID_SUBDISK_S_UNINITIALIZED	0x04	/* Disk of the new volume. */
#define G_RAID_SUBDISK_S_STALE		0x05	/* Dirty. */
#define G_RAID_SUBDISK_S_RESYNC		0x06	/* Dirty + check/repair. */
#define G_RAID_SUBDISK_S_ACTIVE		0x07	/* Usable. */

#define G_RAID_SUBDISK_E_NEW		0x01	/* A new subdisk has arrived */
#define G_RAID_SUBDISK_E_FAILED		0x02	/* A subdisk failed, but remains in volume */
#define G_RAID_SUBDISK_E_DISCONNECTED	0x03	/* A subdisk removed from volume. */
#define G_RAID_SUBDISK_E_FIRST_TR_PRIVATE 0x80	/* translation private events */

#define G_RAID_SUBDISK_POS(sd)						\
    ((sd)->sd_disk ? ((sd)->sd_disk->d_last_offset - (sd)->sd_offset) : 0)
#define G_RAID_SUBDISK_TRACK_SIZE	(1 * 1024 * 1024)
#define G_RAID_SUBDISK_LOAD(sd)						\
    ((sd)->sd_disk ? ((sd)->sd_disk->d_load) : 0)
#define G_RAID_SUBDISK_LOAD_SCALE	256

struct g_raid_subdisk {
	struct g_raid_softc	*sd_softc;	/* Back-pointer to softc. */
	struct g_raid_disk	*sd_disk;	/* Where this subdisk lives. */
	struct g_raid_volume	*sd_volume;	/* Volume, sd is a part of. */
	off_t			 sd_offset;	/* Offset on the disk. */
	off_t			 sd_size;	/* Size on the disk. */
	u_int			 sd_pos;	/* Position in volume. */
	u_int			 sd_state;	/* Subdisk state. */
	off_t			 sd_rebuild_pos; /* Rebuild position. */
	int			 sd_recovery;	/* Count of recovery reqs. */
	TAILQ_ENTRY(g_raid_subdisk)	 sd_next; /* Next subdisk on disk. */
};

#define G_RAID_MAX_SUBDISKS	16
#define G_RAID_MAX_VOLUMENAME	32

#define G_RAID_VOLUME_S_STARTING	0x00
#define G_RAID_VOLUME_S_BROKEN		0x01
#define G_RAID_VOLUME_S_DEGRADED	0x02
#define G_RAID_VOLUME_S_SUBOPTIMAL	0x03
#define G_RAID_VOLUME_S_OPTIMAL		0x04
#define G_RAID_VOLUME_S_UNSUPPORTED	0x05
#define G_RAID_VOLUME_S_STOPPED		0x06

#define G_RAID_VOLUME_S_ALIVE(s)			\
    ((s) == G_RAID_VOLUME_S_DEGRADED ||			\
     (s) == G_RAID_VOLUME_S_SUBOPTIMAL ||		\
     (s) == G_RAID_VOLUME_S_OPTIMAL)

#define G_RAID_VOLUME_E_DOWN		0x00
#define G_RAID_VOLUME_E_UP		0x01
#define G_RAID_VOLUME_E_START		0x10
#define G_RAID_VOLUME_E_STARTMD		0x11

#define G_RAID_VOLUME_RL_RAID0		0x00
#define G_RAID_VOLUME_RL_RAID1		0x01
#define G_RAID_VOLUME_RL_RAID3		0x03
#define G_RAID_VOLUME_RL_RAID4		0x04
#define G_RAID_VOLUME_RL_RAID5		0x05
#define G_RAID_VOLUME_RL_RAID6		0x06
#define G_RAID_VOLUME_RL_RAID1E		0x11
#define G_RAID_VOLUME_RL_SINGLE		0x0f
#define G_RAID_VOLUME_RL_CONCAT		0x1f
#define G_RAID_VOLUME_RL_RAID5E		0x15
#define G_RAID_VOLUME_RL_RAID5EE	0x25
#define G_RAID_VOLUME_RL_UNKNOWN	0xff

#define G_RAID_VOLUME_RLQ_NONE		0x00
#define G_RAID_VOLUME_RLQ_UNKNOWN	0xff

struct g_raid_volume;

struct g_raid_volume {
	struct g_raid_softc	*v_softc;	/* Back-pointer to softc. */
	struct g_provider	*v_provider;	/* GEOM provider. */
	struct g_raid_subdisk	 v_subdisks[G_RAID_MAX_SUBDISKS];
						/* Subdisks of this volume. */
	void			*v_md_data;	/* Volume's metadata storage. */
	struct g_raid_tr_object	*v_tr;		/* Transformation object. */
	char			 v_name[G_RAID_MAX_VOLUMENAME];
						/* Volume name. */
	u_int			 v_state;	/* Volume state. */
	u_int			 v_raid_level;	/* Array RAID level. */
	u_int			 v_raid_level_qualifier; /* RAID level det. */
	u_int			 v_disks_count;	/* Number of disks in array. */
	u_int			 v_strip_size;	/* Array strip size. */
	u_int			 v_sectorsize;	/* Volume sector size. */
	off_t			 v_mediasize;	/* Volume media size.  */
	struct bio_queue_head	 v_inflight;	/* In-flight write requests. */
	struct bio_queue_head	 v_locked;	/* Blocked I/O requests. */
	LIST_HEAD(, g_raid_lock) v_locks;	 /* List of locked regions. */
	int			 v_pending_lock; /* writes to locked region */
	int			 v_dirty;	/* Volume is DIRTY. */
	struct timeval		 v_last_done;	/* Time of the last I/O. */
	time_t			 v_last_write;	/* Time of the last write. */
	u_int			 v_writes;	/* Number of active writes. */
	struct root_hold_token	*v_rootmount;	/* Root mount delay token. */
	int			 v_starting;	/* Volume is starting */
	int			 v_stopping;	/* Volume is stopping */
	int			 v_provider_open; /* Number of opens. */
	int			 v_global_id;	/* Global volume ID (rX). */
	TAILQ_ENTRY(g_raid_volume)	 v_next; /* List of volumes entry. */
	LIST_ENTRY(g_raid_volume)	 v_global_next; /* Global list entry. */
};

#define G_RAID_NODE_E_WAKE	0x00
#define G_RAID_NODE_E_START	0x01

struct g_raid_softc {
	struct g_raid_md_object	*sc_md;		/* Metadata object. */
	struct g_geom		*sc_geom;	/* GEOM class instance. */
	uint64_t		 sc_flags;	/* Additional flags. */
	TAILQ_HEAD(, g_raid_volume)	 sc_volumes;	/* List of volumes. */
	TAILQ_HEAD(, g_raid_disk)	 sc_disks;	/* List of disks. */
	struct sx		 sc_lock;	/* Main node lock. */
	struct proc		*sc_worker;	/* Worker process. */
	struct mtx		 sc_queue_mtx;	/* Worker queues lock. */
	TAILQ_HEAD(, g_raid_event) sc_events;	/* Worker events queue. */
	struct bio_queue_head	 sc_queue;	/* Worker I/O queue. */
	int			 sc_stopping;	/* Node is stopping */
};
#define	sc_name	sc_geom->name

/*
 * KOBJ parent class of metadata processing modules.
 */
struct g_raid_md_class {
	KOBJ_CLASS_FIELDS;
	int		 mdc_priority;
	LIST_ENTRY(g_raid_md_class) mdc_list;
};

/*
 * KOBJ instance of metadata processing module.
 */
struct g_raid_md_object {
	KOBJ_FIELDS;
	struct g_raid_md_class	*mdo_class;
	struct g_raid_softc	*mdo_softc;	/* Back-pointer to softc. */
};

int g_raid_md_modevent(module_t, int, void *);

#define	G_RAID_MD_DECLARE(name)					\
    static moduledata_t name##_mod = {				\
	#name,							\
	g_raid_md_modevent,					\
	&name##_class						\
    };								\
    DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);	\
    MODULE_DEPEND(name, geom_raid, 0, 0, 0)

/*
 * KOBJ parent class of data transformation modules.
 */
struct g_raid_tr_class {
	KOBJ_CLASS_FIELDS;
	int		 trc_priority;
	LIST_ENTRY(g_raid_tr_class) trc_list;
};

/*
 * KOBJ instance of data transformation module.
 */
struct g_raid_tr_object {
	KOBJ_FIELDS;
	struct g_raid_tr_class	*tro_class;
	struct g_raid_volume 	*tro_volume;	/* Back-pointer to volume. */
};

int g_raid_tr_modevent(module_t, int, void *);

#define	G_RAID_TR_DECLARE(name)					\
    static moduledata_t name##_mod = {				\
	#name,							\
	g_raid_tr_modevent,					\
	&name##_class						\
    };								\
    DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);	\
    MODULE_DEPEND(name, geom_raid, 0, 0, 0)

const char * g_raid_volume_level2str(int level, int qual);
int g_raid_volume_str2level(const char *str, int *level, int *qual);
const char * g_raid_volume_state2str(int state);
const char * g_raid_subdisk_state2str(int state);
const char * g_raid_disk_state2str(int state);

struct g_raid_softc * g_raid_create_node(struct g_class *mp,
    const char *name, struct g_raid_md_object *md);
int g_raid_create_node_format(const char *format, struct g_geom **gp);
struct g_raid_volume * g_raid_create_volume(struct g_raid_softc *sc,
    const char *name, int id);
struct g_raid_disk * g_raid_create_disk(struct g_raid_softc *sc);
const char * g_raid_get_diskname(struct g_raid_disk *disk);

int g_raid_start_volume(struct g_raid_volume *vol);

int g_raid_destroy_node(struct g_raid_softc *sc, int worker);
int g_raid_destroy_volume(struct g_raid_volume *vol);
int g_raid_destroy_disk(struct g_raid_disk *disk);

void g_raid_iodone(struct bio *bp, int error);
void g_raid_subdisk_iostart(struct g_raid_subdisk *sd, struct bio *bp);
int g_raid_subdisk_kerneldump(struct g_raid_subdisk *sd,
    void *virtual, vm_offset_t physical, off_t offset, size_t length);

struct g_consumer *g_raid_open_consumer(struct g_raid_softc *sc,
    const char *name);
void g_raid_kill_consumer(struct g_raid_softc *sc, struct g_consumer *cp);

void g_raid_report_disk_state(struct g_raid_disk *disk);
void g_raid_change_disk_state(struct g_raid_disk *disk, int state);
void g_raid_change_subdisk_state(struct g_raid_subdisk *sd, int state);
void g_raid_change_volume_state(struct g_raid_volume *vol, int state);

void g_raid_write_metadata(struct g_raid_softc *sc, struct g_raid_volume *vol,
    struct g_raid_subdisk *sd, struct g_raid_disk *disk);
void g_raid_fail_disk(struct g_raid_softc *sc,
    struct g_raid_subdisk *sd, struct g_raid_disk *disk);

void g_raid_tr_flush_common(struct g_raid_tr_object *tr, struct bio *bp);
int g_raid_tr_kerneldump_common(struct g_raid_tr_object *tr,
    void *virtual, vm_offset_t physical, off_t offset, size_t length);

u_int g_raid_ndisks(struct g_raid_softc *sc, int state);
u_int g_raid_nsubdisks(struct g_raid_volume *vol, int state);
u_int g_raid_nopens(struct g_raid_softc *sc);
struct g_raid_subdisk * g_raid_get_subdisk(struct g_raid_volume *vol,
    int state);
#define	G_RAID_DESTROY_SOFT		0
#define	G_RAID_DESTROY_DELAYED	1
#define	G_RAID_DESTROY_HARD		2
int g_raid_destroy(struct g_raid_softc *sc, int how);
int g_raid_event_send(void *arg, int event, int flags);
int g_raid_lock_range(struct g_raid_volume *vol, off_t off, off_t len,
    struct bio *ignore, void *argp);
int g_raid_unlock_range(struct g_raid_volume *vol, off_t off, off_t len);

g_ctl_req_t g_raid_ctl;
#endif	/* _KERNEL */

#endif	/* !_G_RAID_H_ */


code:
/*-
 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/raid3/g_raid3.h 200821 2009-12-21 23:31:03Z mav $
 */

#ifndef	_G_RAID3_H_
#define	_G_RAID3_H_

#include <sys/endian.h>
#include <sys/md5.h>

#define	G_RAID3_CLASS_NAME	"RAID3"

#define	G_RAID3_MAGIC		"GEOM::RAID3"
/*
 * Version history:
 * 0 - Initial version number.
 * 1 - Added 'round-robin reading' algorithm.
 * 2 - Added 'verify reading' algorithm.
 * 3 - Added md_genid field to metadata.
 * 4 - Added md_provsize field to metadata.
 * 5 - Added 'no failure synchronization' flag.
 */
#define	G_RAID3_VERSION		5

#define	G_RAID3_DISK_FLAG_DIRTY		0x0000000000000001ULL
#define	G_RAID3_DISK_FLAG_SYNCHRONIZING	0x0000000000000002ULL
#define	G_RAID3_DISK_FLAG_FORCE_SYNC	0x0000000000000004ULL
#define	G_RAID3_DISK_FLAG_HARDCODED	0x0000000000000008ULL
#define	G_RAID3_DISK_FLAG_BROKEN	0x0000000000000010ULL
#define	G_RAID3_DISK_FLAG_MASK		(G_RAID3_DISK_FLAG_DIRTY |	\
					 G_RAID3_DISK_FLAG_SYNCHRONIZING | \
					 G_RAID3_DISK_FLAG_FORCE_SYNC)

#define	G_RAID3_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
#define	G_RAID3_DEVICE_FLAG_ROUND_ROBIN	0x0000000000000002ULL
#define	G_RAID3_DEVICE_FLAG_VERIFY	0x0000000000000004ULL
#define	G_RAID3_DEVICE_FLAG_NOFAILSYNC	0x0000000000000008ULL
#define	G_RAID3_DEVICE_FLAG_MASK	(G_RAID3_DEVICE_FLAG_NOAUTOSYNC | \
					 G_RAID3_DEVICE_FLAG_ROUND_ROBIN | \
					 G_RAID3_DEVICE_FLAG_VERIFY | \
					 G_RAID3_DEVICE_FLAG_NOFAILSYNC)

#ifdef _KERNEL
extern u_int g_raid3_debug;

#define	G_RAID3_DEBUG(lvl, ...)	do {					\
	if (g_raid3_debug >= (lvl)) {					\
		printf("GEOM_RAID3");					\
		if (g_raid3_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_RAID3_LOGREQ(lvl, bp, ...)	do {				\
	if (g_raid3_debug >= (lvl)) {					\
		printf("GEOM_RAID3");					\
		if (g_raid3_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

#define	G_RAID3_BIO_CFLAG_REGULAR	0x01
#define	G_RAID3_BIO_CFLAG_SYNC		0x02
#define	G_RAID3_BIO_CFLAG_PARITY	0x04
#define	G_RAID3_BIO_CFLAG_NODISK	0x08
#define	G_RAID3_BIO_CFLAG_REGSYNC	0x10
#define	G_RAID3_BIO_CFLAG_MASK		(G_RAID3_BIO_CFLAG_REGULAR |	\
					 G_RAID3_BIO_CFLAG_SYNC |	\
					 G_RAID3_BIO_CFLAG_PARITY |	\
					 G_RAID3_BIO_CFLAG_NODISK |	\
					 G_RAID3_BIO_CFLAG_REGSYNC)

#define	G_RAID3_BIO_PFLAG_DEGRADED	0x01
#define	G_RAID3_BIO_PFLAG_NOPARITY	0x02
#define	G_RAID3_BIO_PFLAG_VERIFY	0x04
#define	G_RAID3_BIO_PFLAG_MASK		(G_RAID3_BIO_PFLAG_DEGRADED |	\
					 G_RAID3_BIO_PFLAG_NOPARITY |	\
					 G_RAID3_BIO_PFLAG_VERIFY)

/*
 * Informations needed for synchronization.
 */
struct g_raid3_disk_sync {
	struct g_consumer *ds_consumer;	/* Consumer connected to our device. */
	off_t		  ds_offset;	/* Offset of next request to send. */
	off_t		  ds_offset_done; /* Offset of already synchronized
					   region. */
	off_t		  ds_resync;	/* Resynchronize from this offset. */
	u_int		  ds_syncid;	/* Disk's synchronization ID. */
	u_int		  ds_inflight;	/* Number of in-flight sync requests. */
	struct bio	**ds_bios;	/* BIOs for synchronization I/O. */
};

/*
 * Informations needed for synchronization.
 */
struct g_raid3_device_sync {
	struct g_geom	*ds_geom;	/* Synchronization geom. */
};

#define	G_RAID3_DISK_STATE_NODISK		0
#define	G_RAID3_DISK_STATE_NONE			1
#define	G_RAID3_DISK_STATE_NEW			2
#define	G_RAID3_DISK_STATE_ACTIVE		3
#define	G_RAID3_DISK_STATE_STALE		4
#define	G_RAID3_DISK_STATE_SYNCHRONIZING	5
#define	G_RAID3_DISK_STATE_DISCONNECTED		6
#define	G_RAID3_DISK_STATE_DESTROY		7
struct g_raid3_disk {
	u_int		 d_no;		/* Disk number. */
	struct g_consumer *d_consumer;	/* Consumer. */
	struct g_raid3_softc *d_softc;	/* Back-pointer to softc. */
	int		 d_state;	/* Disk state. */
	uint64_t	 d_flags;	/* Additional flags. */
	u_int		 d_genid;	/* Disk's generation ID. */
	struct g_raid3_disk_sync d_sync; /* Sync information. */
	LIST_ENTRY(g_raid3_disk) d_next;
};
#define	d_name	d_consumer->provider->name

#define	G_RAID3_EVENT_DONTWAIT	0x1
#define	G_RAID3_EVENT_WAIT	0x2
#define	G_RAID3_EVENT_DEVICE	0x4
#define	G_RAID3_EVENT_DONE	0x8
struct g_raid3_event {
	struct g_raid3_disk	*e_disk;
	int			 e_state;
	int			 e_flags;
	int			 e_error;
	TAILQ_ENTRY(g_raid3_event) e_next;
};

#define	G_RAID3_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
#define	G_RAID3_DEVICE_FLAG_WAIT	0x0200000000000000ULL
#define	G_RAID3_DEVICE_FLAG_DESTROYING	0x0400000000000000ULL

#define	G_RAID3_DEVICE_STATE_STARTING		0
#define	G_RAID3_DEVICE_STATE_DEGRADED		1
#define	G_RAID3_DEVICE_STATE_COMPLETE		2

/* Bump syncid on first write. */
#define	G_RAID3_BUMP_SYNCID	0x1
/* Bump genid immediately. */
#define	G_RAID3_BUMP_GENID	0x2

enum g_raid3_zones {
	G_RAID3_ZONE_64K,
	G_RAID3_ZONE_16K,
	G_RAID3_ZONE_4K,
	G_RAID3_NUM_ZONES
};

static __inline enum g_raid3_zones
g_raid3_zone(size_t nbytes) {
	if (nbytes > 65536)
		return (G_RAID3_NUM_ZONES);
	else if (nbytes > 16384)
		return (G_RAID3_ZONE_64K);
	else if (nbytes > 4096)
		return (G_RAID3_ZONE_16K);
	else
		return (G_RAID3_ZONE_4K);
};

struct g_raid3_softc {
	u_int		sc_state;	/* Device state. */
	uint64_t	sc_mediasize;	/* Device size. */
	uint32_t	sc_sectorsize;	/* Sector size. */
	uint64_t	sc_flags;	/* Additional flags. */

	struct g_geom	*sc_geom;
	struct g_provider *sc_provider;

	uint32_t	sc_id;		/* Device unique ID. */

	struct sx	 sc_lock;
	struct bio_queue_head sc_queue;
	struct mtx	 sc_queue_mtx;
	struct proc	*sc_worker;
	struct bio_queue_head sc_regular_delayed; /* Delayed I/O requests due
						     collision with sync
						     requests. */
	struct bio_queue_head sc_inflight; /* In-flight regular write
					      requests. */
	struct bio_queue_head sc_sync_delayed; /* Delayed sync requests due
						  collision with regular
						  requests. */

	struct g_raid3_disk *sc_disks;
	u_int		sc_ndisks;	/* Number of disks. */
	u_int		sc_round_robin;
	struct g_raid3_disk *sc_syncdisk;

	struct g_raid3_zone {
		uma_zone_t	sz_zone;
		size_t		sz_inuse;
		size_t		sz_max;
		u_int		sz_requested;
		u_int		sz_failed;
	} sc_zones[G_RAID3_NUM_ZONES];

	u_int		sc_genid;	/* Generation ID. */
	u_int		sc_syncid;	/* Synchronization ID. */
	int		sc_bump_id;
	struct g_raid3_device_sync sc_sync;
	int		sc_idle;	/* DIRTY flags removed. */
	time_t		sc_last_write;
	u_int		sc_writes;

	TAILQ_HEAD(, g_raid3_event) sc_events;
	struct mtx	sc_events_mtx;

	struct callout	sc_callout;

	struct root_hold_token *sc_rootmount;
};
#define	sc_name	sc_geom->name

const char *g_raid3_get_diskname(struct g_raid3_disk *disk);
u_int g_raid3_ndisks(struct g_raid3_softc *sc, int state);
#define	G_RAID3_DESTROY_SOFT	0
#define	G_RAID3_DESTROY_DELAYED	1
#define	G_RAID3_DESTROY_HARD	2
int g_raid3_destroy(struct g_raid3_softc *sc, int how);
int g_raid3_event_send(void *arg, int state, int flags);
struct g_raid3_metadata;
int g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp,
    struct g_raid3_metadata *md);
int g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md);
void g_raid3_fill_metadata(struct g_raid3_disk *disk,
    struct g_raid3_metadata *md);
int g_raid3_clear_metadata(struct g_raid3_disk *disk);
void g_raid3_update_metadata(struct g_raid3_disk *disk);

g_ctl_req_t g_raid3_config;
#endif	/* _KERNEL */

struct g_raid3_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	char		md_name[16];	/* Device name. */
	uint32_t	md_id;		/* Device unique ID. */
	uint16_t	md_no;		/* Component number. */
	uint16_t	md_all;		/* Number of disks in device. */
	uint32_t	md_genid;	/* Generation ID. */
	uint32_t	md_syncid;	/* Synchronization ID. */
	uint64_t	md_mediasize;	/* Size of whole device. */
	uint32_t	md_sectorsize;	/* Sector size. */
	uint64_t	md_sync_offset;	/* Synchronized offset. */
	uint64_t	md_mflags;	/* Additional device flags. */
	uint64_t	md_dflags;	/* Additional disk flags. */
	char		md_provider[16]; /* Hardcoded provider. */
	uint64_t	md_provsize;	/* Provider's size. */
	u_char		md_hash[16];	/* MD5 hash. */
};
static __inline void
raid3_metadata_encode(struct g_raid3_metadata *md, u_char *data)
{
	MD5_CTX ctx;

	bcopy(md->md_magic, data, 16);
	le32enc(data + 16, md->md_version);
	bcopy(md->md_name, data + 20, 16);
	le32enc(data + 36, md->md_id);
	le16enc(data + 40, md->md_no);
	le16enc(data + 42, md->md_all);
	le32enc(data + 44, md->md_genid);
	le32enc(data + 48, md->md_syncid);
	le64enc(data + 52, md->md_mediasize);
	le32enc(data + 60, md->md_sectorsize);
	le64enc(data + 64, md->md_sync_offset);
	le64enc(data + 72, md->md_mflags);
	le64enc(data + 80, md->md_dflags);
	bcopy(md->md_provider, data + 88, 16);
	le64enc(data + 104, md->md_provsize);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 112);
	MD5Final(md->md_hash, &ctx);
	bcopy(md->md_hash, data + 112, 16);
}
static __inline int
raid3_metadata_decode_v0v1v2(const u_char *data, struct g_raid3_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_id = le32dec(data + 36);
	md->md_no = le16dec(data + 40);
	md->md_all = le16dec(data + 42);
	md->md_syncid = le32dec(data + 44);
	md->md_mediasize = le64dec(data + 48);
	md->md_sectorsize = le32dec(data + 56);
	md->md_sync_offset = le64dec(data + 60);
	md->md_mflags = le64dec(data + 68);
	md->md_dflags = le64dec(data + 76);
	bcopy(data + 84, md->md_provider, 16);
	bcopy(data + 100, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 100);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 100, 16) != 0)
		return (EINVAL);

	/* New fields. */
	md->md_genid = 0;
	md->md_provsize = 0;

	return (0);
}
static __inline int
raid3_metadata_decode_v3(const u_char *data, struct g_raid3_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_id = le32dec(data + 36);
	md->md_no = le16dec(data + 40);
	md->md_all = le16dec(data + 42);
	md->md_genid = le32dec(data + 44);
	md->md_syncid = le32dec(data + 48);
	md->md_mediasize = le64dec(data + 52);
	md->md_sectorsize = le32dec(data + 60);
	md->md_sync_offset = le64dec(data + 64);
	md->md_mflags = le64dec(data + 72);
	md->md_dflags = le64dec(data + 80);
	bcopy(data + 88, md->md_provider, 16);
	bcopy(data + 104, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 104);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 104, 16) != 0)
		return (EINVAL);

	/* New fields. */
	md->md_provsize = 0;

	return (0);
}
static __inline int
raid3_metadata_decode_v4v5(const u_char *data, struct g_raid3_metadata *md)
{
	MD5_CTX ctx;

	bcopy(data + 20, md->md_name, 16);
	md->md_id = le32dec(data + 36);
	md->md_no = le16dec(data + 40);
	md->md_all = le16dec(data + 42);
	md->md_genid = le32dec(data + 44);
	md->md_syncid = le32dec(data + 48);
	md->md_mediasize = le64dec(data + 52);
	md->md_sectorsize = le32dec(data + 60);
	md->md_sync_offset = le64dec(data + 64);
	md->md_mflags = le64dec(data + 72);
	md->md_dflags = le64dec(data + 80);
	bcopy(data + 88, md->md_provider, 16);
	md->md_provsize = le64dec(data + 104);
	bcopy(data + 112, md->md_hash, 16);
	MD5Init(&ctx);
	MD5Update(&ctx, data, 112);
	MD5Final(md->md_hash, &ctx);
	if (bcmp(md->md_hash, data + 112, 16) != 0)
		return (EINVAL);
	return (0);
}
static __inline int
raid3_metadata_decode(const u_char *data, struct g_raid3_metadata *md)
{
	int error;

	bcopy(data, md->md_magic, 16);
	md->md_version = le32dec(data + 16);
	switch (md->md_version) {
	case 0:
	case 1:
	case 2:
		error = raid3_metadata_decode_v0v1v2(data, md);
		break;
	case 3:
		error = raid3_metadata_decode_v3(data, md);
		break;
	case 4:
	case 5:
		error = raid3_metadata_decode_v4v5(data, md);
		break;
	default:
		error = EINVAL;
		break;
	}
	return (error);
}

static __inline void
raid3_metadata_dump(const struct g_raid3_metadata *md)
{
	static const char hex[] = "0123456789abcdef";
	char hash[16 * 2 + 1];
	u_int i;

	printf("     magic: %s\n", md->md_magic);
	printf("   version: %u\n", (u_int)md->md_version);
	printf("      name: %s\n", md->md_name);
	printf("        id: %u\n", (u_int)md->md_id);
	printf("        no: %u\n", (u_int)md->md_no);
	printf("       all: %u\n", (u_int)md->md_all);
	printf("     genid: %u\n", (u_int)md->md_genid);
	printf("    syncid: %u\n", (u_int)md->md_syncid);
	printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize);
	printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
	printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset);
	printf("    mflags:");
	if (md->md_mflags == 0)
		printf(" NONE");
	else {
		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
			printf(" NOAUTOSYNC");
		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0)
			printf(" ROUND-ROBIN");
		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0)
			printf(" VERIFY");
		if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0)
			printf(" NOFAILSYNC");
	}
	printf("\n");
	printf("    dflags:");
	if (md->md_dflags == 0)
		printf(" NONE");
	else {
		if ((md->md_dflags & G_RAID3_DISK_FLAG_DIRTY) != 0)
			printf(" DIRTY");
		if ((md->md_dflags & G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0)
			printf(" SYNCHRONIZING");
		if ((md->md_dflags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0)
			printf(" FORCE_SYNC");
	}
	printf("\n");
	printf("hcprovider: %s\n", md->md_provider);
	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
	bzero(hash, sizeof(hash));
	for (i = 0; i < 16; i++) {
		hash[i * 2] = hex[md->md_hash[i] >> 4];
		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
	}
	printf("  MD5 hash: %s\n", hash);
}
#endif	/* !_G_RAID3_H_ */


code:
/*-
 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/shsec/g_shsec.h 155174 2006-02-01 12:06:01Z pjd $
 */

#ifndef	_G_SHSEC_H_
#define	_G_SHSEC_H_

#include <sys/endian.h>

#define	G_SHSEC_CLASS_NAME	"SHSEC"

#define	G_SHSEC_MAGIC		"GEOM::SHSEC"
/*
 * Version history:
 * 0 - Initial version number.
 * 1 - Added md_provsize field to metadata.
 */
#define	G_SHSEC_VERSION	1

#ifdef _KERNEL
#define	G_SHSEC_BFLAG_FIRST	0x1

#define	G_SHSEC_DEBUG(lvl, ...)	do {					\
	if (g_shsec_debug >= (lvl)) {					\
		printf("GEOM_SHSEC");					\
		if (g_shsec_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_SHSEC_LOGREQ(lvl, bp, ...)	do {				\
	if (g_shsec_debug >= (lvl)) {					\
		printf("GEOM_SHSEC");					\
		if (g_shsec_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

struct g_shsec_softc {
	u_int		 sc_type;	/* provider type */
	struct g_geom	*sc_geom;
	struct g_provider *sc_provider;
	uint32_t	 sc_id;		/* device unique ID */
	struct g_consumer **sc_disks;
	uint16_t	 sc_ndisks;
};
#define	sc_name	sc_geom->name
#endif	/* _KERNEL */

struct g_shsec_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	char		md_name[16];	/* Stripe name. */
	uint32_t	md_id;		/* Unique ID. */
	uint16_t	md_no;		/* Disk number. */
	uint16_t	md_all;		/* Number of all disks. */
	char		md_provider[16]; /* Hardcoded provider. */
	uint64_t	md_provsize;	/* Provider's size. */
};
static __inline void
shsec_metadata_encode(const struct g_shsec_metadata *md, u_char *data)
{

	bcopy(md->md_magic, data, sizeof(md->md_magic));
	le32enc(data + 16, md->md_version);
	bcopy(md->md_name, data + 20, sizeof(md->md_name));
	le32enc(data + 36, md->md_id);
	le16enc(data + 40, md->md_no);
	le16enc(data + 42, md->md_all);
	bcopy(md->md_provider, data + 44, sizeof(md->md_provider));
	le64enc(data + 60, md->md_provsize);
}
static __inline void
shsec_metadata_decode(const u_char *data, struct g_shsec_metadata *md)
{

	bcopy(data, md->md_magic, sizeof(md->md_magic));
	md->md_version = le32dec(data + 16);
	bcopy(data + 20, md->md_name, sizeof(md->md_name));
	md->md_id = le32dec(data + 36);
	md->md_no = le16dec(data + 40);
	md->md_all = le16dec(data + 42);
	bcopy(data + 44, md->md_provider, sizeof(md->md_provider));
	md->md_provsize = le64dec(data + 60);
}
#endif	/* _G_SHSEC_H_ */


code:
/*-
 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.0.0/sys/geom/stripe/g_stripe.h 155174 2006-02-01 12:06:01Z pjd $
 */

#ifndef	_G_STRIPE_H_
#define	_G_STRIPE_H_

#include <sys/endian.h>

#define	G_STRIPE_CLASS_NAME	"STRIPE"

#define	G_STRIPE_MAGIC		"GEOM::STRIPE"
/*
 * Version history:
 * 0 - Initial version number.
 * 1 - Added 'stop' command for gstripe(8).
 * 2 - Added md_provider field to metadata and '-h' option for gstripe(8).
 * 3 - Added md_provsize field to metadata.
 */
#define	G_STRIPE_VERSION	3

#ifdef _KERNEL
#define	G_STRIPE_TYPE_MANUAL	0
#define	G_STRIPE_TYPE_AUTOMATIC	1

#define	G_STRIPE_DEBUG(lvl, ...)	do {				\
	if (g_stripe_debug >= (lvl)) {					\
		printf("GEOM_STRIPE");					\
		if (g_stripe_debug > 0)					\
			printf("[%u]", lvl);				\
		printf(": ");						\
		printf(__VA_ARGS__);					\
		printf("\n");						\
	}								\
} while (0)
#define	G_STRIPE_LOGREQ(bp, ...)	do {				\
	if (g_stripe_debug >= 2) {					\
		printf("GEOM_STRIPE[2]: ");				\
		printf(__VA_ARGS__);					\
		printf(" ");						\
		g_print_bio(bp);					\
		printf("\n");						\
	}								\
} while (0)

struct g_stripe_softc {
	u_int		 sc_type;	/* provider type */
	struct g_geom	*sc_geom;
	struct g_provider *sc_provider;
	uint32_t	 sc_id;		/* stripe unique ID */
	struct g_consumer **sc_disks;
	uint16_t	 sc_ndisks;
	uint32_t	 sc_stripesize;
	uint32_t	 sc_stripebits;
};
#define	sc_name	sc_geom->name
#endif	/* _KERNEL */

struct g_stripe_metadata {
	char		md_magic[16];	/* Magic value. */
	uint32_t	md_version;	/* Version number. */
	char		md_name[16];	/* Stripe name. */
	uint32_t	md_id;		/* Unique ID. */
	uint16_t	md_no;		/* Disk number. */
	uint16_t	md_all;		/* Number of all disks. */
	uint32_t	md_stripesize;	/* Stripe size. */
	char		md_provider[16]; /* Hardcoded provider. */
	uint64_t	md_provsize;	/* Provider's size. */
};
static __inline void
stripe_metadata_encode(const struct g_stripe_metadata *md, u_char *data)
{

	bcopy(md->md_magic, data, sizeof(md->md_magic));
	le32enc(data + 16, md->md_version);
	bcopy(md->md_name, data + 20, sizeof(md->md_name));
	le32enc(data + 36, md->md_id);
	le16enc(data + 40, md->md_no);
	le16enc(data + 42, md->md_all);
	le32enc(data + 44, md->md_stripesize);
	bcopy(md->md_provider, data + 48, sizeof(md->md_provider));
	le64enc(data + 64, md->md_provsize);
}
static __inline void
stripe_metadata_decode(const u_char *data, struct g_stripe_metadata *md)
{

	bcopy(data, md->md_magic, sizeof(md->md_magic));
	md->md_version = le32dec(data + 16);
	bcopy(data + 20, md->md_name, sizeof(md->md_name));
	md->md_id = le32dec(data + 36);
	md->md_no = le16dec(data + 40);
	md->md_all = le16dec(data + 42);
	md->md_stripesize = le32dec(data + 44);
	bcopy(data + 48, md->md_provider, sizeof(md->md_provider));
	md->md_provsize = le64dec(data + 64);
}

#endif	/* _G_STRIPE_H_ */


code:
/*-
 * 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: release/9.0.0/sys/geom/virstor/binstream.h 172302 2007-09-23 07:34:23Z pjd $
 */

// $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


code:
/*-
 * 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: release/9.0.0/sys/geom/virstor/g_virstor.h 172302 2007-09-23 07:34:23Z pjd $
 */

#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_ */


code:
/*-
 * 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: release/9.0.0/sys/geom/virstor/g_virstor_md.h 172302 2007-09-23 07:34:23Z pjd $
 */

#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_ */


code:
/*	$NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $	*/
/*	$FreeBSD: release/9.0.0/include/getopt.h 203963 2010-02-16 19:28:10Z imp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Dieter Baron and Thomas Klausner.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

#ifndef _GETOPT_H_
#define _GETOPT_H_

#include <sys/cdefs.h>

/*
 * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension.
 * getopt() is declared here too for GNU programs.
 */
#define no_argument        0
#define required_argument  1
#define optional_argument  2

struct option {
	/* name of long option */
	const char *name;
	/*
	 * one of no_argument, required_argument, and optional_argument:
	 * whether option takes an argument
	 */
	int has_arg;
	/* if not NULL, set *flag to val when option found */
	int *flag;
	/* if flag not NULL, value to set *flag to; else return value */
	int val;
};

__BEGIN_DECLS
int	getopt_long(int, char * const *, const char *,
	const struct option *, int *);
int	getopt_long_only(int, char * const *, const char *,
	const struct option *, int *);
#ifndef _GETOPT_DECLARED
#define	_GETOPT_DECLARED
int	 getopt(int, char * const [], const char *);

extern char *optarg;			/* getopt(3) external variables */
extern int optind, opterr, optopt;
#endif
#ifndef _OPTRESET_DECLARED
#define	_OPTRESET_DECLARED
extern int optreset;			/* getopt(3) external variable */
#endif
__END_DECLS

#endif /* !_GETOPT_H_ */