1132904Spjd/*-
2156878Spjd * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3132904Spjd * All rights reserved.
4132904Spjd *
5132904Spjd * Redistribution and use in source and binary forms, with or without
6132904Spjd * modification, are permitted provided that the following conditions
7132904Spjd * are met:
8132904Spjd * 1. Redistributions of source code must retain the above copyright
9132904Spjd *    notice, this list of conditions and the following disclaimer.
10132904Spjd * 2. Redistributions in binary form must reproduce the above copyright
11132904Spjd *    notice, this list of conditions and the following disclaimer in the
12132904Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14132904Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15132904Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132904Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132904Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18132904Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132904Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132904Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132904Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132904Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132904Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132904Spjd * SUCH DAMAGE.
25132904Spjd *
26132904Spjd * $FreeBSD: stable/11/sys/geom/mirror/g_mirror.h 328086 2018-01-17 15:12:52Z markj $
27132904Spjd */
28132904Spjd
29132904Spjd#ifndef	_G_MIRROR_H_
30132904Spjd#define	_G_MIRROR_H_
31132904Spjd
32132904Spjd#include <sys/endian.h>
33132904Spjd#include <sys/md5.h>
34132904Spjd
35132904Spjd#define	G_MIRROR_CLASS_NAME	"MIRROR"
36132904Spjd
37132904Spjd#define	G_MIRROR_MAGIC		"GEOM::MIRROR"
38139213Spjd/*
39139213Spjd * Version history:
40139213Spjd * 0 - Initial version number.
41139213Spjd * 1 - Added 'prefer' balance algorithm.
42139213Spjd * 2 - Added md_genid field to metadata.
43142727Spjd * 3 - Added md_provsize field to metadata.
44163888Spjd * 4 - Added 'no failure synchronization' flag.
45139213Spjd */
46163888Spjd#define	G_MIRROR_VERSION	4
47132904Spjd
48132904Spjd#define	G_MIRROR_BALANCE_NONE		0
49132904Spjd#define	G_MIRROR_BALANCE_ROUND_ROBIN	1
50132904Spjd#define	G_MIRROR_BALANCE_LOAD		2
51132904Spjd#define	G_MIRROR_BALANCE_SPLIT		3
52133115Spjd#define	G_MIRROR_BALANCE_PREFER		4
53132904Spjd#define	G_MIRROR_BALANCE_MIN		G_MIRROR_BALANCE_NONE
54133115Spjd#define	G_MIRROR_BALANCE_MAX		G_MIRROR_BALANCE_PREFER
55132904Spjd
56132904Spjd#define	G_MIRROR_DISK_FLAG_DIRTY		0x0000000000000001ULL
57132904Spjd#define	G_MIRROR_DISK_FLAG_SYNCHRONIZING	0x0000000000000002ULL
58132904Spjd#define	G_MIRROR_DISK_FLAG_FORCE_SYNC		0x0000000000000004ULL
59132904Spjd#define	G_MIRROR_DISK_FLAG_INACTIVE		0x0000000000000008ULL
60133373Spjd#define	G_MIRROR_DISK_FLAG_HARDCODED		0x0000000000000010ULL
61155545Spjd#define	G_MIRROR_DISK_FLAG_BROKEN		0x0000000000000020ULL
62237930Sglebius#define	G_MIRROR_DISK_FLAG_CANDELETE		0x0000000000000040ULL
63328086Smarkj
64328086Smarkj/* Per-disk flags which are recorded in on-disk metadata. */
65132904Spjd#define	G_MIRROR_DISK_FLAG_MASK		(G_MIRROR_DISK_FLAG_DIRTY |	\
66132904Spjd					 G_MIRROR_DISK_FLAG_SYNCHRONIZING | \
67132904Spjd					 G_MIRROR_DISK_FLAG_FORCE_SYNC | \
68237930Sglebius					 G_MIRROR_DISK_FLAG_INACTIVE | \
69237930Sglebius					 G_MIRROR_DISK_FLAG_CANDELETE)
70132904Spjd
71132904Spjd#define	G_MIRROR_DEVICE_FLAG_NOAUTOSYNC	0x0000000000000001ULL
72163888Spjd#define	G_MIRROR_DEVICE_FLAG_NOFAILSYNC	0x0000000000000002ULL
73328086Smarkj
74328086Smarkj/* Mirror flags which are recorded in on-disk metadata. */
75163888Spjd#define	G_MIRROR_DEVICE_FLAG_MASK	(G_MIRROR_DEVICE_FLAG_NOAUTOSYNC | \
76163888Spjd					 G_MIRROR_DEVICE_FLAG_NOFAILSYNC)
77132904Spjd
78132904Spjd#ifdef _KERNEL
79326530Smarkjextern int g_mirror_debug;
80132904Spjd
81132904Spjd#define	G_MIRROR_DEBUG(lvl, ...)	do {				\
82132904Spjd	if (g_mirror_debug >= (lvl)) {					\
83132904Spjd		printf("GEOM_MIRROR");					\
84132904Spjd		if (g_mirror_debug > 0)					\
85132904Spjd			printf("[%u]", lvl);				\
86132904Spjd		printf(": ");						\
87132904Spjd		printf(__VA_ARGS__);					\
88132904Spjd		printf("\n");						\
89132904Spjd	}								\
90132904Spjd} while (0)
91132904Spjd#define	G_MIRROR_LOGREQ(lvl, bp, ...)	do {				\
92132904Spjd	if (g_mirror_debug >= (lvl)) {					\
93132904Spjd		printf("GEOM_MIRROR");					\
94132904Spjd		if (g_mirror_debug > 0)					\
95132904Spjd			printf("[%u]", lvl);				\
96132904Spjd		printf(": ");						\
97132904Spjd		printf(__VA_ARGS__);					\
98132904Spjd		printf(" ");						\
99132904Spjd		g_print_bio(bp);					\
100132904Spjd		printf("\n");						\
101132904Spjd	}								\
102132904Spjd} while (0)
103132904Spjd
104133142Spjd#define	G_MIRROR_BIO_FLAG_REGULAR	0x01
105133142Spjd#define	G_MIRROR_BIO_FLAG_SYNC		0x02
106133142Spjd
107132904Spjd/*
108132904Spjd * Informations needed for synchronization.
109132904Spjd */
110132904Spjdstruct g_mirror_disk_sync {
111132904Spjd	struct g_consumer *ds_consumer;	/* Consumer connected to our mirror. */
112156610Spjd	off_t		  ds_offset;	/* Offset of next request to send. */
113156610Spjd	off_t		  ds_offset_done; /* Offset of already synchronized
114132904Spjd					   region. */
115327070Smarkj	time_t		  ds_update_ts; /* Time of last metadata update. */
116156610Spjd	u_int		  ds_syncid;	/* Disk's synchronization ID. */
117156610Spjd	u_int		  ds_inflight;	/* Number of in-flight sync requests. */
118156610Spjd	struct bio	**ds_bios;	/* BIOs for synchronization I/O. */
119132904Spjd};
120132904Spjd
121132904Spjd/*
122132904Spjd * Informations needed for synchronization.
123132904Spjd */
124132904Spjdstruct g_mirror_device_sync {
125132904Spjd	struct g_geom	*ds_geom;	/* Synchronization geom. */
126132904Spjd	u_int		 ds_ndisks;	/* Number of disks in SYNCHRONIZING
127132904Spjd					   state. */
128132904Spjd};
129132904Spjd
130132904Spjd#define	G_MIRROR_DISK_STATE_NONE		0
131132904Spjd#define	G_MIRROR_DISK_STATE_NEW			1
132132904Spjd#define	G_MIRROR_DISK_STATE_ACTIVE		2
133132904Spjd#define	G_MIRROR_DISK_STATE_STALE		3
134132904Spjd#define	G_MIRROR_DISK_STATE_SYNCHRONIZING	4
135132904Spjd#define	G_MIRROR_DISK_STATE_DISCONNECTED	5
136132904Spjd#define	G_MIRROR_DISK_STATE_DESTROY		6
137132904Spjdstruct g_mirror_disk {
138132904Spjd	uint32_t	 d_id;		/* Disk ID. */
139132904Spjd	struct g_consumer *d_consumer;	/* Consumer. */
140132904Spjd	struct g_mirror_softc	*d_softc; /* Back-pointer to softc. */
141132904Spjd	int		 d_state;	/* Disk state. */
142132904Spjd	u_int		 d_priority;	/* Disk priority. */
143200086Smav	u_int		 load;		/* Averaged queue length */
144200086Smav	off_t		 d_last_offset;	/* Last read offset */
145132904Spjd	uint64_t	 d_flags;	/* Additional flags. */
146139213Spjd	u_int		 d_genid;	/* Disk's generation ID. */
147132904Spjd	struct g_mirror_disk_sync d_sync;/* Sync information. */
148132904Spjd	LIST_ENTRY(g_mirror_disk) d_next;
149132904Spjd};
150132904Spjd#define	d_name	d_consumer->provider->name
151132904Spjd
152132904Spjd#define	G_MIRROR_EVENT_DONTWAIT	0x1
153132904Spjd#define	G_MIRROR_EVENT_WAIT	0x2
154132904Spjd#define	G_MIRROR_EVENT_DEVICE	0x4
155132904Spjd#define	G_MIRROR_EVENT_DONE	0x8
156132904Spjdstruct g_mirror_event {
157132904Spjd	struct g_mirror_disk	*e_disk;
158132904Spjd	int			 e_state;
159132904Spjd	int			 e_flags;
160132904Spjd	int			 e_error;
161132904Spjd	TAILQ_ENTRY(g_mirror_event) e_next;
162132904Spjd};
163132904Spjd
164132904Spjd#define	G_MIRROR_DEVICE_FLAG_DESTROY	0x0100000000000000ULL
165326696Smarkj#define	G_MIRROR_DEVICE_FLAG_DRAIN	0x0200000000000000ULL
166326696Smarkj#define	G_MIRROR_DEVICE_FLAG_CLOSEWAIT	0x0400000000000000ULL
167235599Sae#define	G_MIRROR_DEVICE_FLAG_TASTING	0x0800000000000000ULL
168259929Sae#define	G_MIRROR_DEVICE_FLAG_WIPE	0x1000000000000000ULL
169132904Spjd
170132904Spjd#define	G_MIRROR_DEVICE_STATE_STARTING		0
171132904Spjd#define	G_MIRROR_DEVICE_STATE_RUNNING		1
172132904Spjd
173318752Smav#define	G_MIRROR_TYPE_MANUAL	0
174318752Smav#define	G_MIRROR_TYPE_AUTOMATIC	1
175318752Smav
176139213Spjd/* Bump syncid on first write. */
177324588Savg#define	G_MIRROR_BUMP_SYNCID		0x1
178139213Spjd/* Bump genid immediately. */
179324588Savg#define	G_MIRROR_BUMP_GENID		0x2
180324588Savg/* Bump syncid immediately. */
181324588Savg#define	G_MIRROR_BUMP_SYNCID_NOW	0x4
182132904Spjdstruct g_mirror_softc {
183318752Smav	u_int		sc_type;	/* Device type (manual/automatic). */
184132904Spjd	u_int		sc_state;	/* Device state. */
185132904Spjd	uint32_t	sc_slice;	/* Slice size. */
186132904Spjd	uint8_t		sc_balance;	/* Balance algorithm. */
187132904Spjd	uint64_t	sc_mediasize;	/* Device size. */
188132904Spjd	uint32_t	sc_sectorsize;	/* Sector size. */
189132904Spjd	uint64_t	sc_flags;	/* Additional flags. */
190132904Spjd
191132904Spjd	struct g_geom	*sc_geom;
192132904Spjd	struct g_provider *sc_provider;
193307665Smav	int		sc_provider_open;
194132904Spjd
195132904Spjd	uint32_t	sc_id;		/* Mirror unique ID. */
196132904Spjd
197156610Spjd	struct sx	 sc_lock;
198327493Smarkj	struct bio_queue sc_queue;
199132904Spjd	struct mtx	 sc_queue_mtx;
200132904Spjd	struct proc	*sc_worker;
201327493Smarkj	struct bio_queue sc_inflight; /* In-flight regular write requests. */
202327493Smarkj	struct bio_queue sc_regular_delayed; /* Delayed I/O requests due to
203327493Smarkj						collision with sync requests. */
204327493Smarkj	struct bio_queue sc_sync_delayed; /* Delayed sync requests due to
205327493Smarkj					     collision with regular requests. */
206132904Spjd
207132904Spjd	LIST_HEAD(, g_mirror_disk) sc_disks;
208132904Spjd	u_int		sc_ndisks;	/* Number of disks. */
209132904Spjd	struct g_mirror_disk *sc_hint;
210132904Spjd
211139213Spjd	u_int		sc_genid;	/* Generation ID. */
212132904Spjd	u_int		sc_syncid;	/* Synchronization ID. */
213139213Spjd	int		sc_bump_id;
214132904Spjd	struct g_mirror_device_sync sc_sync;
215137248Spjd	int		sc_idle;	/* DIRTY flags removed. */
216155539Spjd	time_t		sc_last_write;
217155539Spjd	u_int		sc_writes;
218309205Smav	u_int		sc_refcnt;	/* Number of softc references */
219132904Spjd
220132904Spjd	TAILQ_HEAD(, g_mirror_event) sc_events;
221132904Spjd	struct mtx	sc_events_mtx;
222132904Spjd
223132904Spjd	struct callout	sc_callout;
224145305Spjd
225145305Spjd	struct root_hold_token *sc_rootmount;
226256880Smav
227256880Smav	struct mtx	 sc_done_mtx;
228132904Spjd};
229132904Spjd#define	sc_name	sc_geom->name
230132904Spjd
231318752Smavstruct g_mirror_metadata;
232318752Smav
233132904Spjdu_int g_mirror_ndisks(struct g_mirror_softc *sc, int state);
234318752Smavstruct g_geom * g_mirror_create(struct g_class *mp,
235318752Smav    const struct g_mirror_metadata *md, u_int type);
236157630Spjd#define	G_MIRROR_DESTROY_SOFT		0
237157630Spjd#define	G_MIRROR_DESTROY_DELAYED	1
238157630Spjd#define	G_MIRROR_DESTROY_HARD		2
239157630Spjdint g_mirror_destroy(struct g_mirror_softc *sc, int how);
240132904Spjdint g_mirror_event_send(void *arg, int state, int flags);
241132904Spjdstruct g_mirror_metadata;
242139650Spjdint g_mirror_add_disk(struct g_mirror_softc *sc, struct g_provider *pp,
243139650Spjd    struct g_mirror_metadata *md);
244139650Spjdint g_mirror_read_metadata(struct g_consumer *cp, struct g_mirror_metadata *md);
245132904Spjdvoid g_mirror_fill_metadata(struct g_mirror_softc *sc,
246132904Spjd    struct g_mirror_disk *disk, struct g_mirror_metadata *md);
247132904Spjdvoid g_mirror_update_metadata(struct g_mirror_disk *disk);
248132904Spjd
249132904Spjdg_ctl_req_t g_mirror_config;
250132904Spjd#endif	/* _KERNEL */
251132904Spjd
252132904Spjdstruct g_mirror_metadata {
253132904Spjd	char		md_magic[16];	/* Magic value. */
254132904Spjd	uint32_t	md_version;	/* Version number. */
255132904Spjd	char		md_name[16];	/* Mirror name. */
256132904Spjd	uint32_t	md_mid;		/* Mirror unique ID. */
257132904Spjd	uint32_t	md_did;		/* Disk unique ID. */
258132904Spjd	uint8_t		md_all;		/* Number of disks in mirror. */
259139213Spjd	uint32_t	md_genid;	/* Generation ID. */
260132904Spjd	uint32_t	md_syncid;	/* Synchronization ID. */
261132904Spjd	uint8_t		md_priority;	/* Disk priority. */
262132904Spjd	uint32_t	md_slice;	/* Slice size. */
263132904Spjd	uint8_t		md_balance;	/* Balance type. */
264132904Spjd	uint64_t	md_mediasize;	/* Size of the smallest
265132904Spjd					   disk in mirror. */
266132904Spjd	uint32_t	md_sectorsize;	/* Sector size. */
267132904Spjd	uint64_t	md_sync_offset;	/* Synchronized offset. */
268132904Spjd	uint64_t	md_mflags;	/* Additional mirror flags. */
269132904Spjd	uint64_t	md_dflags;	/* Additional disk flags. */
270133373Spjd	char		md_provider[16]; /* Hardcoded provider. */
271142727Spjd	uint64_t	md_provsize;	/* Provider's size. */
272132904Spjd	u_char		md_hash[16];	/* MD5 hash. */
273132904Spjd};
274132904Spjdstatic __inline void
275132904Spjdmirror_metadata_encode(struct g_mirror_metadata *md, u_char *data)
276132904Spjd{
277132904Spjd	MD5_CTX ctx;
278132904Spjd
279132904Spjd	bcopy(md->md_magic, data, 16);
280132904Spjd	le32enc(data + 16, md->md_version);
281132904Spjd	bcopy(md->md_name, data + 20, 16);
282132904Spjd	le32enc(data + 36, md->md_mid);
283132904Spjd	le32enc(data + 40, md->md_did);
284132904Spjd	*(data + 44) = md->md_all;
285139213Spjd	le32enc(data + 45, md->md_genid);
286139213Spjd	le32enc(data + 49, md->md_syncid);
287139213Spjd	*(data + 53) = md->md_priority;
288139213Spjd	le32enc(data + 54, md->md_slice);
289139213Spjd	*(data + 58) = md->md_balance;
290139213Spjd	le64enc(data + 59, md->md_mediasize);
291139213Spjd	le32enc(data + 67, md->md_sectorsize);
292139213Spjd	le64enc(data + 71, md->md_sync_offset);
293139213Spjd	le64enc(data + 79, md->md_mflags);
294139213Spjd	le64enc(data + 87, md->md_dflags);
295139213Spjd	bcopy(md->md_provider, data + 95, 16);
296142727Spjd	le64enc(data + 111, md->md_provsize);
297132904Spjd	MD5Init(&ctx);
298142727Spjd	MD5Update(&ctx, data, 119);
299132904Spjd	MD5Final(md->md_hash, &ctx);
300142727Spjd	bcopy(md->md_hash, data + 119, 16);
301132904Spjd}
302132904Spjdstatic __inline int
303139213Spjdmirror_metadata_decode_v0v1(const u_char *data, struct g_mirror_metadata *md)
304132904Spjd{
305132904Spjd	MD5_CTX ctx;
306132904Spjd
307132904Spjd	bcopy(data + 20, md->md_name, 16);
308132904Spjd	md->md_mid = le32dec(data + 36);
309132904Spjd	md->md_did = le32dec(data + 40);
310132904Spjd	md->md_all = *(data + 44);
311132904Spjd	md->md_syncid = le32dec(data + 45);
312132904Spjd	md->md_priority = *(data + 49);
313132904Spjd	md->md_slice = le32dec(data + 50);
314132904Spjd	md->md_balance = *(data + 54);
315132904Spjd	md->md_mediasize = le64dec(data + 55);
316132904Spjd	md->md_sectorsize = le32dec(data + 63);
317132904Spjd	md->md_sync_offset = le64dec(data + 67);
318132904Spjd	md->md_mflags = le64dec(data + 75);
319132904Spjd	md->md_dflags = le64dec(data + 83);
320133373Spjd	bcopy(data + 91, md->md_provider, 16);
321133373Spjd	bcopy(data + 107, md->md_hash, 16);
322132904Spjd	MD5Init(&ctx);
323133373Spjd	MD5Update(&ctx, data, 107);
324132904Spjd	MD5Final(md->md_hash, &ctx);
325133373Spjd	if (bcmp(md->md_hash, data + 107, 16) != 0)
326132904Spjd		return (EINVAL);
327139213Spjd
328139213Spjd	/* New fields. */
329139213Spjd	md->md_genid = 0;
330142727Spjd	md->md_provsize = 0;
331139213Spjd
332132904Spjd	return (0);
333132904Spjd}
334139213Spjdstatic __inline int
335139213Spjdmirror_metadata_decode_v2(const u_char *data, struct g_mirror_metadata *md)
336139213Spjd{
337139213Spjd	MD5_CTX ctx;
338132904Spjd
339139213Spjd	bcopy(data + 20, md->md_name, 16);
340139213Spjd	md->md_mid = le32dec(data + 36);
341139213Spjd	md->md_did = le32dec(data + 40);
342139213Spjd	md->md_all = *(data + 44);
343139213Spjd	md->md_genid = le32dec(data + 45);
344139213Spjd	md->md_syncid = le32dec(data + 49);
345139213Spjd	md->md_priority = *(data + 53);
346139213Spjd	md->md_slice = le32dec(data + 54);
347139213Spjd	md->md_balance = *(data + 58);
348139213Spjd	md->md_mediasize = le64dec(data + 59);
349139213Spjd	md->md_sectorsize = le32dec(data + 67);
350139213Spjd	md->md_sync_offset = le64dec(data + 71);
351139213Spjd	md->md_mflags = le64dec(data + 79);
352139213Spjd	md->md_dflags = le64dec(data + 87);
353139213Spjd	bcopy(data + 95, md->md_provider, 16);
354139213Spjd	bcopy(data + 111, md->md_hash, 16);
355139213Spjd	MD5Init(&ctx);
356139213Spjd	MD5Update(&ctx, data, 111);
357139213Spjd	MD5Final(md->md_hash, &ctx);
358139213Spjd	if (bcmp(md->md_hash, data + 111, 16) != 0)
359139213Spjd		return (EINVAL);
360142727Spjd
361142727Spjd	/* New fields. */
362142727Spjd	md->md_provsize = 0;
363142727Spjd
364139213Spjd	return (0);
365139213Spjd}
366139213Spjdstatic __inline int
367163888Spjdmirror_metadata_decode_v3v4(const u_char *data, struct g_mirror_metadata *md)
368142727Spjd{
369142727Spjd	MD5_CTX ctx;
370142727Spjd
371142727Spjd	bcopy(data + 20, md->md_name, 16);
372142727Spjd	md->md_mid = le32dec(data + 36);
373142727Spjd	md->md_did = le32dec(data + 40);
374142727Spjd	md->md_all = *(data + 44);
375142727Spjd	md->md_genid = le32dec(data + 45);
376142727Spjd	md->md_syncid = le32dec(data + 49);
377142727Spjd	md->md_priority = *(data + 53);
378142727Spjd	md->md_slice = le32dec(data + 54);
379142727Spjd	md->md_balance = *(data + 58);
380142727Spjd	md->md_mediasize = le64dec(data + 59);
381142727Spjd	md->md_sectorsize = le32dec(data + 67);
382142727Spjd	md->md_sync_offset = le64dec(data + 71);
383142727Spjd	md->md_mflags = le64dec(data + 79);
384142727Spjd	md->md_dflags = le64dec(data + 87);
385142727Spjd	bcopy(data + 95, md->md_provider, 16);
386142727Spjd	md->md_provsize = le64dec(data + 111);
387142727Spjd	bcopy(data + 119, md->md_hash, 16);
388142727Spjd	MD5Init(&ctx);
389142727Spjd	MD5Update(&ctx, data, 119);
390142727Spjd	MD5Final(md->md_hash, &ctx);
391142727Spjd	if (bcmp(md->md_hash, data + 119, 16) != 0)
392142727Spjd		return (EINVAL);
393142727Spjd	return (0);
394142727Spjd}
395142727Spjdstatic __inline int
396139213Spjdmirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md)
397139213Spjd{
398139213Spjd	int error;
399139213Spjd
400139213Spjd	bcopy(data, md->md_magic, 16);
401139213Spjd	md->md_version = le32dec(data + 16);
402139213Spjd	switch (md->md_version) {
403139213Spjd	case 0:
404139213Spjd	case 1:
405139213Spjd		error = mirror_metadata_decode_v0v1(data, md);
406139213Spjd		break;
407139213Spjd	case 2:
408139213Spjd		error = mirror_metadata_decode_v2(data, md);
409139213Spjd		break;
410142727Spjd	case 3:
411163888Spjd	case 4:
412163888Spjd		error = mirror_metadata_decode_v3v4(data, md);
413142727Spjd		break;
414139213Spjd	default:
415139213Spjd		error = EINVAL;
416139213Spjd		break;
417139213Spjd	}
418139213Spjd	return (error);
419139213Spjd}
420139213Spjd
421132904Spjdstatic __inline const char *
422132904Spjdbalance_name(u_int balance)
423132904Spjd{
424132904Spjd	static const char *algorithms[] = {
425132904Spjd		[G_MIRROR_BALANCE_NONE] = "none",
426132904Spjd		[G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin",
427132904Spjd		[G_MIRROR_BALANCE_LOAD] = "load",
428132904Spjd		[G_MIRROR_BALANCE_SPLIT] = "split",
429133115Spjd		[G_MIRROR_BALANCE_PREFER] = "prefer",
430132904Spjd		[G_MIRROR_BALANCE_MAX + 1] = "unknown"
431132904Spjd	};
432132904Spjd
433132904Spjd	if (balance > G_MIRROR_BALANCE_MAX)
434132904Spjd		balance = G_MIRROR_BALANCE_MAX + 1;
435132904Spjd
436132904Spjd	return (algorithms[balance]);
437132904Spjd}
438132904Spjd
439132904Spjdstatic __inline int
440132904Spjdbalance_id(const char *name)
441132904Spjd{
442132904Spjd	static const char *algorithms[] = {
443132904Spjd		[G_MIRROR_BALANCE_NONE] = "none",
444132904Spjd		[G_MIRROR_BALANCE_ROUND_ROBIN] = "round-robin",
445132904Spjd		[G_MIRROR_BALANCE_LOAD] = "load",
446133115Spjd		[G_MIRROR_BALANCE_SPLIT] = "split",
447133115Spjd		[G_MIRROR_BALANCE_PREFER] = "prefer"
448132904Spjd	};
449132904Spjd	int n;
450132904Spjd
451132904Spjd	for (n = G_MIRROR_BALANCE_MIN; n <= G_MIRROR_BALANCE_MAX; n++) {
452132904Spjd		if (strcmp(name, algorithms[n]) == 0)
453132904Spjd			return (n);
454132904Spjd	}
455132904Spjd	return (-1);
456132904Spjd}
457132904Spjd
458132904Spjdstatic __inline void
459132904Spjdmirror_metadata_dump(const struct g_mirror_metadata *md)
460132904Spjd{
461132904Spjd	static const char hex[] = "0123456789abcdef";
462132904Spjd	char hash[16 * 2 + 1];
463132904Spjd	u_int i;
464132904Spjd
465132904Spjd	printf("     magic: %s\n", md->md_magic);
466132904Spjd	printf("   version: %u\n", (u_int)md->md_version);
467132904Spjd	printf("      name: %s\n", md->md_name);
468132904Spjd	printf("       mid: %u\n", (u_int)md->md_mid);
469132904Spjd	printf("       did: %u\n", (u_int)md->md_did);
470132904Spjd	printf("       all: %u\n", (u_int)md->md_all);
471139213Spjd	printf("     genid: %u\n", (u_int)md->md_genid);
472132904Spjd	printf("    syncid: %u\n", (u_int)md->md_syncid);
473132904Spjd	printf("  priority: %u\n", (u_int)md->md_priority);
474132904Spjd	printf("     slice: %u\n", (u_int)md->md_slice);
475132904Spjd	printf("   balance: %s\n", balance_name((u_int)md->md_balance));
476132904Spjd	printf(" mediasize: %jd\n", (intmax_t)md->md_mediasize);
477132904Spjd	printf("sectorsize: %u\n", (u_int)md->md_sectorsize);
478132904Spjd	printf("syncoffset: %jd\n", (intmax_t)md->md_sync_offset);
479132904Spjd	printf("    mflags:");
480132904Spjd	if (md->md_mflags == 0)
481132904Spjd		printf(" NONE");
482132904Spjd	else {
483163888Spjd		if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0)
484163888Spjd			printf(" NOFAILSYNC");
485132904Spjd		if ((md->md_mflags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0)
486132904Spjd			printf(" NOAUTOSYNC");
487132904Spjd	}
488132904Spjd	printf("\n");
489132904Spjd	printf("    dflags:");
490133527Spjd	if (md->md_dflags == 0)
491132904Spjd		printf(" NONE");
492132904Spjd	else {
493132904Spjd		if ((md->md_dflags & G_MIRROR_DISK_FLAG_DIRTY) != 0)
494132904Spjd			printf(" DIRTY");
495132904Spjd		if ((md->md_dflags & G_MIRROR_DISK_FLAG_SYNCHRONIZING) != 0)
496132904Spjd			printf(" SYNCHRONIZING");
497132904Spjd		if ((md->md_dflags & G_MIRROR_DISK_FLAG_FORCE_SYNC) != 0)
498132904Spjd			printf(" FORCE_SYNC");
499132904Spjd		if ((md->md_dflags & G_MIRROR_DISK_FLAG_INACTIVE) != 0)
500132904Spjd			printf(" INACTIVE");
501132904Spjd	}
502132904Spjd	printf("\n");
503133373Spjd	printf("hcprovider: %s\n", md->md_provider);
504142727Spjd	printf("  provsize: %ju\n", (uintmax_t)md->md_provsize);
505132904Spjd	bzero(hash, sizeof(hash));
506132904Spjd	for (i = 0; i < 16; i++) {
507132904Spjd		hash[i * 2] = hex[md->md_hash[i] >> 4];
508132904Spjd		hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
509132904Spjd	}
510132904Spjd	printf("  MD5 hash: %s\n", hash);
511132904Spjd}
512132904Spjd#endif	/* !_G_MIRROR_H_ */
513