xref: /freebsd/sys/geom/union/g_union.h (revision 8eb2bee6c0f4957c6c1cea826e59cda4d18a2a64)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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
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
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