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