1 /* 2 * Copyright (c) 2006,2014-2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * CCMS - Cache Coherency Management System. 37 * 38 * This subsystem can be tied into a VFS in order to supply persistent 39 * cache management state for cluster or for remote cache-coherent operations. 40 * 41 * Local and cluster/remote cache state is maintained in a cache-coherent 42 * fashion as well as integrated into the VFS's inode locking subsystem 43 * (as a means of avoiding deadlocks). 44 * 45 * To operate properly the VFS must maintain a complete directory topology 46 * leading to any given vnode/inode either open or cached by the system. 47 * The vnode/namecache subsystem does not have to implement this but the 48 * VFS (aka HAMMER2) does. 49 * 50 * The filesystem embeds CCMS_CST structures in its internal inode 51 * representatino as needed and implements callback to allow CCMS to 52 * do topological recursions. 53 * 54 * -- 55 * 56 * The CCMS_CST structures represent granted cache and local locking states. 57 * Grants can be recursively inherited, minimizing protocol overhead in 58 * situations where there are no conflicts of interest. 59 * 60 * -- 61 * 62 * CCMS supports active front-end 'locks' on data objects utilizing the 63 * ccms_inode, key, and desired cache state. It can grant the lock based 64 * on inherited CST state and prevents downgrading of the CST by other 65 * parties or threads while the lock is held. The CST's arranged 66 * lock within the embedded CCMS_INODE and ref-counts the related CST. 67 */ 68 69 #ifndef _SYS_CCMS_H_ 70 #define _SYS_CCMS_H_ 71 72 #ifndef _SYS_TYPES_H_ 73 #include <sys/types.h> 74 #endif 75 #ifndef _SYS_PARAM_H_ 76 #include <sys/param.h> 77 #endif 78 #ifndef _SYS_SERIALIZE_H_ 79 #include <sys/serialize.h> 80 #endif 81 #ifndef _SYS_SPINLOCK_H_ 82 #include <sys/spinlock.h> 83 #endif 84 85 typedef uint64_t ccms_key_t; 86 typedef uint64_t ccms_tid_t; 87 typedef uint8_t ccms_state_t; 88 typedef uint8_t ccms_type_t; 89 90 struct ccms_cst; 91 92 /* 93 * CCMS_STATE_T - CCMS cache states. 94 * 95 * INVALID - Cache state is unknown and must be acquired. 96 * 97 * ALLOWED - Cache state allows any recursive state to be acquired. 98 * 99 * SHARED - Cache state allows shared access. 100 * 101 * EXCLUSIVE - Cache state allows exclusive access. 102 * 103 * CCMS Implements an extended MESI model. The extensions are implemented 104 * as CCMS_TYPE_T flags. 105 */ 106 #define CCMS_STATE_INVALID 0 /* unknown cache state */ 107 #define CCMS_STATE_SHARED 2 /* clean, shared, read-only */ 108 #define CCMS_STATE_EXCLUSIVE 3 /* clean, exclusive, read-only */ 109 110 /* 111 * CCMS_TYPE_T FLAGS 112 * 113 * INHERITED - Indicates the state field was inherited and was not directly 114 * granted by the cluster controller. 115 * 116 * MODIFIED - This is a type-field flag associated with an EXCLUSIVE cache 117 * state 118 * 119 * MASTER - This is a type-field flag associated with an EXCLUSIVE+MODIFIED 120 * cache state which indicates that slaves might be present 121 * which are caching our unsynchronized state. 122 * 123 * SLAVE - This is a type-field flag associated with the SHARED cache 124 * state which indicates that the data present in our memory 125 * caches is being mastered elsewhere and has not been 126 * synchronized (meaning no quorum protocol has been run to 127 * sync the data yet). Thus only the version of the data in 128 * our memory and its originator is valid. 129 * 130 * QSLAVE - This indicates that the slaved data is also present in the 131 * memory caches of a quorum of master nodes. 132 */ 133 #define CCMS_TYPE_INHERITED 0x01 134 #define CCMS_TYPE_MODIFIED 0x02 135 #define CCMS_TYPE_MASTER 0x04 136 #define CCMS_TYPE_SLAVE 0x08 137 #define CCMS_TYPE_QSALVE 0x10 138 #define CCMS_TYPE_RECURSIVE 0x80 139 140 /* 141 * CCMS_CST - Low level locking state, persistent cache state 142 * 143 * Offset ranges are byte-inclusive, allowing the entire 64 bit data space 144 * to be represented without overflowing the edge case. For example, a 145 * 64 byte area might be represented as (0,63). The offsets are UNSIGNED 146 * entities. 147 * 148 * High level CST locks must be obtained top-down. 149 * 150 * count - Negative value indicates active exclusive lock, positive value 151 * indicates active shared lock. 152 * 153 * spin - Structural spinlock, typically just one is held at a time. 154 * However, to complement the top-down nature of the higher level 155 * lock we allow the spin lock to be held recursively in a bottom-up 156 * fashion for race-to-root flags updates and lastdrop iterations. 157 */ 158 struct ccms_cst { 159 hammer2_spin_t spin; /* thread spinlock */ 160 ccms_state_t state; /* granted or inherited state */ 161 ccms_type_t type; /* CST type and flags */ 162 uint8_t unused02; 163 uint8_t unused03; 164 165 int32_t upgrade; /* upgrades pending */ 166 int32_t count; /* active shared/exclusive count */ 167 int32_t blocked; /* wakeup blocked on release */ 168 thread_t td; /* if excl lock (count < 0) */ 169 }; 170 171 typedef struct ccms_cst ccms_cst_t; 172 173 /* 174 * Kernel API 175 */ 176 #ifdef _KERNEL 177 178 void ccms_cst_init(ccms_cst_t *cst); 179 void ccms_cst_uninit(ccms_cst_t *cst); 180 181 void ccms_thread_lock(ccms_cst_t *cst, ccms_state_t state); 182 int ccms_thread_lock_nonblock(ccms_cst_t *cst, ccms_state_t state); 183 ccms_state_t ccms_thread_lock_temp_release(ccms_cst_t *cst); 184 void ccms_thread_lock_temp_restore(ccms_cst_t *cst, ccms_state_t ostate); 185 ccms_state_t ccms_thread_lock_upgrade(ccms_cst_t *cst); 186 void ccms_thread_lock_downgrade(ccms_cst_t *cst, ccms_state_t ostate); 187 void ccms_thread_unlock(ccms_cst_t *cst); 188 void ccms_thread_unlock_upgraded(ccms_cst_t *cst, ccms_state_t ostate); 189 int ccms_thread_lock_owned(ccms_cst_t *cst); 190 void ccms_thread_lock_setown(ccms_cst_t *cst); 191 192 #endif 193 194 #endif 195