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