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
47 TAILQ_HEAD(wiplist, g_union_wip);
48
49 /*
50 * State maintained by each instance of a UNION GEOM.
51 */
52 struct 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 */
96 struct 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 */
126 static inline int
g_union_get_writelock(struct g_union_softc * sc)127 g_union_get_writelock(struct g_union_softc *sc)
128 {
129
130 return (atomic_testandset_long(&sc->sc_flags, DOING_COMMIT_BITNUM));
131 }
132
133 static inline void
g_union_rel_writelock(struct g_union_softc * sc)134 g_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