1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 Marshall Kirk McKusick <mckusick@mckusick.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#ifndef	_G_UNION_H_
29#define	_G_UNION_H_
30
31#define	G_UNION_CLASS_NAME	"UNION"
32#define	G_UNION_VERSION		1
33#define	G_UNION_SUFFIX		".union"
34/*
35 * Special flag to instruct gunion to passthrough the underlying provider's
36 * physical path
37 */
38#define G_UNION_PHYSPATH_PASSTHROUGH "\255"
39
40#ifdef _KERNEL
41#define	G_UNION_DEBUG(lvl, ...) \
42    _GEOM_DEBUG("GEOM_UNION", g_union_debug, (lvl), NULL, __VA_ARGS__)
43#define G_UNION_LOGREQLVL(lvl, bp, ...) \
44    _GEOM_DEBUG("GEOM_UNION", g_union_debug, (lvl), (bp), __VA_ARGS__)
45#define	G_UNION_LOGREQ(bp, ...)	G_UNION_LOGREQLVL(3, (bp), __VA_ARGS__)
46
47TAILQ_HEAD(wiplist, g_union_wip);
48
49/*
50 * State maintained by each instance of a UNION GEOM.
51 */
52struct g_union_softc {
53	struct rwlock	   sc_rwlock;		/* writemap lock */
54	uint64_t	 **sc_writemap_root;	/* root of write map */
55	uint64_t	  *sc_leafused;		/* 1 => leaf has allocation */
56	uint64_t	   sc_map_size;		/* size of write map */
57	long		   sc_root_size;	/* entries in root node */
58	long		   sc_leaf_size;	/* entries in leaf node */
59	long		   sc_bits_per_leaf;	/* bits per leaf node entry */
60	long		   sc_writemap_memory;	/* memory used by writemap */
61	off_t		   sc_offset;		/* starting offset in lower */
62	off_t		   sc_size;		/* size of union geom */
63	off_t		   sc_sectorsize;	/* sector size of geom */
64	struct g_consumer *sc_uppercp;		/* upper-level provider */
65	struct g_consumer *sc_lowercp;		/* lower-level provider */
66	struct wiplist	   sc_wiplist;		/* I/O work-in-progress list */
67	long		   sc_flags;		/* see flags below */
68	long		   sc_reads;		/* number of reads done */
69	long		   sc_wrotebytes;	/* number of bytes written */
70	long		   sc_writes;		/* number of writes done */
71	long		   sc_readbytes;	/* number of bytes read */
72	long		   sc_deletes;		/* number of deletes done */
73	long		   sc_getattrs;		/* number of getattrs done */
74	long		   sc_flushes;		/* number of flushes done */
75	long		   sc_cmd0s;		/* number of cmd0's done */
76	long		   sc_cmd1s;		/* number of cmd1's done */
77	long		   sc_cmd2s;		/* number of cmd2's done */
78	long		   sc_speedups;		/* number of speedups done */
79	long		   sc_readcurrentread;	/* reads current with read */
80	long		   sc_readblockwrite;	/* writes blocked by read */
81	long		   sc_writeblockread;	/* reads blocked by write */
82	long		   sc_writeblockwrite;	/* writes blocked by write */
83};
84
85/*
86 * Structure to track work-in-progress I/O operations.
87 *
88 * Used to prevent overlapping I/O operations from running concurrently.
89 * Created for each I/O operation.
90 *
91 * In usual case of no overlap it is linked to sc_wiplist and started.
92 * If found to overlap an I/O on sc_wiplist, it is not started and is
93 * linked to wip_waiting list of the I/O that it overlaps. When an I/O
94 * completes, it restarts all the I/O operations on its wip_waiting list.
95 */
96struct g_union_wip {
97	struct wiplist		 wip_waiting;	/* list of I/Os waiting on me */
98	TAILQ_ENTRY(g_union_wip) wip_next;	/* pending or active I/O list */
99	struct bio		*wip_bp;	/* bio for this I/O */
100	struct g_union_softc	*wip_sc;	/* g_union's softc */
101	off_t			 wip_start;	/* starting offset of I/O */
102	off_t			 wip_end;	/* ending offset of I/O */
103	long			 wip_numios;	/* BIO_READs in progress */
104	long			 wip_error;	/* merged I/O errors */
105};
106
107/*
108 * UNION flags
109 */
110#define DOING_COMMIT	0x00000001	/* a commit command is in progress */
111
112#define DOING_COMMIT_BITNUM	 0	/* a commit command is in progress */
113
114#define BITS_PER_ENTRY	(sizeof(uint64_t) * NBBY)
115#define G_RLOCK(sc)	rw_rlock(&(sc)->sc_rwlock)
116#define G_RUNLOCK(sc)	rw_runlock(&(sc)->sc_rwlock)
117#define G_WLOCK(sc)	rw_wlock(&(sc)->sc_rwlock)
118#define G_WUNLOCK(sc)	rw_wunlock(&(sc)->sc_rwlock)
119#define G_WLOCKOWNED(sc) rw_assert(&(sc)->sc_rwlock, RA_WLOCKED)
120
121/*
122 * The writelock is held while a commit operation is in progress.
123 * While held union device may not be used or in use.
124 * Returns == 0 if lock was successfully obtained.
125 */
126static inline int
127g_union_get_writelock(struct g_union_softc *sc)
128{
129
130	return (atomic_testandset_long(&sc->sc_flags, DOING_COMMIT_BITNUM));
131}
132
133static inline void
134g_union_rel_writelock(struct g_union_softc *sc)
135{
136	long ret __diagused;
137
138	ret = atomic_testandclear_long(&sc->sc_flags, DOING_COMMIT_BITNUM);
139	KASSERT(ret != 0, ("UNION GEOM releasing unheld lock"));
140}
141
142#endif	/* _KERNEL */
143
144#endif	/* _G_UNION_H_ */
145