xref: /dragonfly/sys/vfs/hammer2/hammer2_ccms.h (revision 476d2aad)
1f03672ecSMatthew Dillon /*
2f03672ecSMatthew Dillon  * Copyright (c) 2006,2012 The DragonFly Project.  All rights reserved.
3f03672ecSMatthew Dillon  *
4f03672ecSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5f03672ecSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6f03672ecSMatthew Dillon  *
7f03672ecSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8f03672ecSMatthew Dillon  * modification, are permitted provided that the following conditions
9f03672ecSMatthew Dillon  * are met:
10f03672ecSMatthew Dillon  *
11f03672ecSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12f03672ecSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13f03672ecSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14f03672ecSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15f03672ecSMatthew Dillon  *    the documentation and/or other materials provided with the
16f03672ecSMatthew Dillon  *    distribution.
17f03672ecSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18f03672ecSMatthew Dillon  *    contributors may be used to endorse or promote products derived
19f03672ecSMatthew Dillon  *    from this software without specific, prior written permission.
20f03672ecSMatthew Dillon  *
21f03672ecSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22f03672ecSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23f03672ecSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24f03672ecSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25f03672ecSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26f03672ecSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27f03672ecSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28f03672ecSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29f03672ecSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30f03672ecSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31f03672ecSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32f03672ecSMatthew Dillon  * SUCH DAMAGE.
33f03672ecSMatthew Dillon  */
3446558838SMatthew Dillon 
35f03672ecSMatthew Dillon /*
3646558838SMatthew Dillon  * CCMS - Cache Coherency Management System.
371ad77ed9SMatthew Dillon  *
3846558838SMatthew Dillon  * This subsystem can be tied into a VFS in order to supply persistent
3946558838SMatthew Dillon  * cache management state for cluster or for remote cache-coherent operations.
40f03672ecSMatthew Dillon  *
4146558838SMatthew Dillon  * Local and cluster/remote cache state is maintained in a cache-coherent
4246558838SMatthew Dillon  * fashion as well as integrated into the VFS's inode locking subsystem
4346558838SMatthew Dillon  * (as a means of avoiding deadlocks).
44f03672ecSMatthew Dillon  *
4546558838SMatthew Dillon  * To operate properly the VFS must maintain a complete directory topology
4646558838SMatthew Dillon  * leading to any given vnode/inode either open or cached by the system.
4746558838SMatthew Dillon  * The vnode/namecache subsystem does not have to implement this but the
4846558838SMatthew Dillon  * VFS (aka HAMMER2) does.
491ad77ed9SMatthew Dillon  *
5046558838SMatthew Dillon  * The filesystem embeds CCMS_CST structures in its internal inode
5146558838SMatthew Dillon  * representatino as needed and implements callback to allow CCMS to
5246558838SMatthew Dillon  * do topological recursions.
531ad77ed9SMatthew Dillon  *
5446558838SMatthew Dillon  * --
551ad77ed9SMatthew Dillon  *
5646558838SMatthew Dillon  * The CCMS_CST structures represent granted cache and local locking states.
5746558838SMatthew Dillon  * Grants can be recursively inherited, minimizing protocol overhead in
5846558838SMatthew Dillon  * situations where there are no conflicts of interest.
591ad77ed9SMatthew Dillon  *
6046558838SMatthew Dillon  * --
611ad77ed9SMatthew Dillon  *
6246558838SMatthew Dillon  * CCMS supports active front-end 'locks' on data objects utilizing the
6346558838SMatthew Dillon  * ccms_inode, key, and desired cache state.  It can grant the lock based
6446558838SMatthew Dillon  * on inherited CST state and prevents downgrading of the CST by other
6546558838SMatthew Dillon  * parties or threads while the lock is held.  The CST's arranged
6646558838SMatthew Dillon  * lock within the embedded CCMS_INODE and ref-counts the related CST.
67f03672ecSMatthew Dillon  */
68f03672ecSMatthew Dillon 
69f03672ecSMatthew Dillon #ifndef _SYS_CCMS_H_
70f03672ecSMatthew Dillon #define _SYS_CCMS_H_
71f03672ecSMatthew Dillon 
72f03672ecSMatthew Dillon #ifndef _SYS_TYPES_H_
73f03672ecSMatthew Dillon #include <sys/types.h>
74f03672ecSMatthew Dillon #endif
75f03672ecSMatthew Dillon #ifndef _SYS_PARAM_H_
76f03672ecSMatthew Dillon #include <sys/param.h>
77f03672ecSMatthew Dillon #endif
78f03672ecSMatthew Dillon #ifndef _SYS_SERIALIZE_H_
79f03672ecSMatthew Dillon #include <sys/serialize.h>
80f03672ecSMatthew Dillon #endif
81f03672ecSMatthew Dillon #ifndef _SYS_SPINLOCK_H_
82f03672ecSMatthew Dillon #include <sys/spinlock.h>
83f03672ecSMatthew Dillon #endif
84f03672ecSMatthew Dillon 
8546558838SMatthew Dillon typedef uint64_t	ccms_key_t;
8646558838SMatthew Dillon typedef uint64_t	ccms_tid_t;
871ad77ed9SMatthew Dillon typedef uint8_t		ccms_state_t;
8846558838SMatthew Dillon typedef uint8_t		ccms_type_t;
891ad77ed9SMatthew Dillon 
90f03672ecSMatthew Dillon struct ccms_cst;
911ad77ed9SMatthew Dillon struct ccms_lock;
92f03672ecSMatthew Dillon 
93f03672ecSMatthew Dillon /*
9446558838SMatthew Dillon  * CCMS_STATE_T - CCMS cache states.
95f03672ecSMatthew Dillon  *
961ad77ed9SMatthew Dillon  * INVALID   -	Cache state is unknown and must be acquired.
97f03672ecSMatthew Dillon  *
9846558838SMatthew Dillon  * ALLOWED   -  Cache state allows any recursive state to be acquired.
99f03672ecSMatthew Dillon  *
10046558838SMatthew Dillon  * SHARED    -	Cache state allows shared access.  If this is a topo_cst
10146558838SMatthew Dillon  *		only INVALID or SHARED recursive states are allowed.
1021ad77ed9SMatthew Dillon  *
10346558838SMatthew Dillon  * EXCLUSIVE -  Cache state allows exclusive access.  If this is a
10446558838SMatthew Dillon  *		topo_cst then INVALID, SHARED, or EXCLUSIVE recursive
10546558838SMatthew Dillon  *		state is allowed.
1061ad77ed9SMatthew Dillon  *
10746558838SMatthew Dillon  * CCMS Implements an extended MESI model.  The extensions are implemented
10846558838SMatthew Dillon  * as CCMS_TYPE_T flags.
109f03672ecSMatthew Dillon  */
1101ad77ed9SMatthew Dillon #define CCMS_STATE_INVALID	0	/* unknown cache state */
1111ad77ed9SMatthew Dillon #define CCMS_STATE_ALLOWED	1	/* allow subsystem (topo only) */
1121ad77ed9SMatthew Dillon #define CCMS_STATE_SHARED	2	/* clean, shared, read-only */
11346558838SMatthew Dillon #define CCMS_STATE_EXCLUSIVE	3	/* clean, exclusive, read-only */
114f03672ecSMatthew Dillon 
115f03672ecSMatthew Dillon /*
11646558838SMatthew Dillon  * CCMS_TYPE_T FLAGS
11746558838SMatthew Dillon  *
11846558838SMatthew Dillon  * INHERITED -  Indicates the state field was inherited and was not directly
11946558838SMatthew Dillon  *		granted by the cluster controller.
12046558838SMatthew Dillon  *
12146558838SMatthew Dillon  * MODIFIED  -  This is a type-field flag associated with an EXCLUSIVE cache
12246558838SMatthew Dillon  *		state
12346558838SMatthew Dillon  *
12446558838SMatthew Dillon  * MASTER    -  This is a type-field flag associated with an EXCLUSIVE+MODIFIED
12546558838SMatthew Dillon  *		cache state which indicates that slaves might be present
12646558838SMatthew Dillon  *		which are caching our unsynchronized state.
12746558838SMatthew Dillon  *
12846558838SMatthew Dillon  * SLAVE     -  This is a type-field flag associated with the SHARED cache
12946558838SMatthew Dillon  *		state which indicates that the data present in our memory
13046558838SMatthew Dillon  *		caches is being mastered elsewhere and has not been
13146558838SMatthew Dillon  *		synchronized (meaning no quorum protocol has been run to
13246558838SMatthew Dillon  *		sync the data yet).  Thus only the version of the data in
13346558838SMatthew Dillon  *		our memory and its originator is valid.
13446558838SMatthew Dillon  *
13546558838SMatthew Dillon  * QSLAVE    -  This indicates that the slaved data is also present in the
13646558838SMatthew Dillon  *		memory caches of a quorum of master nodes.
13746558838SMatthew Dillon  */
13846558838SMatthew Dillon #define CCMS_TYPE_INHERITED	0x01
13946558838SMatthew Dillon #define CCMS_TYPE_MODIFIED	0x02
14046558838SMatthew Dillon #define CCMS_TYPE_MASTER	0x04
14146558838SMatthew Dillon #define CCMS_TYPE_SLAVE		0x08
14246558838SMatthew Dillon #define CCMS_TYPE_QSALVE	0x10
14346558838SMatthew Dillon #define CCMS_TYPE_RECURSIVE	0x80
14446558838SMatthew Dillon 
14546558838SMatthew Dillon /*
14646558838SMatthew Dillon  * CCMS_LOCK - High level active lock
14746558838SMatthew Dillon  *
14846558838SMatthew Dillon  * This represents a high level locking request, such as used by
14946558838SMatthew Dillon  * read, write, and attribute operations.  Initialize the ccms_lock
15046558838SMatthew Dillon  * structure and call ccms_lock_get().
151f03672ecSMatthew Dillon  *
152f03672ecSMatthew Dillon  * When a CCMS lock is established the cache state of the underlying elements
153f03672ecSMatthew Dillon  * is adjusted to meet the requirements of the lock.  The cache state
1541ad77ed9SMatthew Dillon  * requirements are infered by the lock type.  CCMS locks can block on
1551ad77ed9SMatthew Dillon  * third party interactions if the underlying remote cache state is not
1561ad77ed9SMatthew Dillon  * compatible.
157f03672ecSMatthew Dillon  *
1581ad77ed9SMatthew Dillon  * CCMS data locks imply a shared CCMS inode lock.  A CCMS topology lock does
1591ad77ed9SMatthew Dillon  * not imply a data or inode lock but topology locks can have far-reaching
16046558838SMatthew Dillon  * effects such as block ccms_locks on multiple inodes.
161f03672ecSMatthew Dillon  */
162f03672ecSMatthew Dillon struct ccms_lock {
1631ad77ed9SMatthew Dillon 	TAILQ_ENTRY(ccms_lock) entry;
16446558838SMatthew Dillon 	ccms_state_t	req_t;
16546558838SMatthew Dillon 	ccms_state_t	req_a;
16646558838SMatthew Dillon 	ccms_state_t	req_d;
16746558838SMatthew Dillon 	uint8_t		flags;
16846558838SMatthew Dillon 	struct ccms_cst	*topo_cst;
16946558838SMatthew Dillon 	struct ccms_cst	*attr_cst;
17046558838SMatthew Dillon 	struct ccms_cst	*data_cst;
17146558838SMatthew Dillon 	ccms_key_t	key_beg;	/* applies to dstate */
17246558838SMatthew Dillon 	ccms_key_t	key_end;	/* applies to dstate */
173f03672ecSMatthew Dillon };
174f03672ecSMatthew Dillon 
17546558838SMatthew Dillon #define CCMS_LOCK_FAILED	0x01
1761ad77ed9SMatthew Dillon 
177f03672ecSMatthew Dillon /*
17846558838SMatthew Dillon  * CCMS_CST - Low level locking state, persistent cache state
179f03672ecSMatthew Dillon  *
18046558838SMatthew Dillon  * Offset ranges are byte-inclusive, allowing the entire 64 bit data space
181f03672ecSMatthew Dillon  * to be represented without overflowing the edge case.  For example, a
1821ad77ed9SMatthew Dillon  * 64 byte area might be represented as (0,63).  The offsets are UNSIGNED
1831ad77ed9SMatthew Dillon  * entities.
18446558838SMatthew Dillon  *
185f3843dc2SMatthew Dillon  * High level CST locks must be obtained top-down.
186f3843dc2SMatthew Dillon  *
187f3843dc2SMatthew Dillon  * count - Negative value indicates active exclusive lock, positive value
18846558838SMatthew Dillon  *	   indicates active shared lock.
189f3843dc2SMatthew Dillon  *
190f3843dc2SMatthew Dillon  * spin  - Structural spinlock, typically just one is held at a time.
191f3843dc2SMatthew Dillon  *	   However, to complement the top-down nature of the higher level
192f3843dc2SMatthew Dillon  *	   lock we allow the spin lock to be held recursively in a bottom-up
193f3843dc2SMatthew Dillon  *	   fashion for race-to-root flags updates and lastdrop iterations.
194f03672ecSMatthew Dillon  */
195f03672ecSMatthew Dillon struct ccms_cst {
19646558838SMatthew Dillon 	struct spinlock spin;		/* thread spinlock */
19746558838SMatthew Dillon 	void		*handle;	/* opaque VFS handle */
19846558838SMatthew Dillon 	ccms_state_t	state;		/* granted or inherited state */
19946558838SMatthew Dillon 	ccms_type_t	type;		/* CST type and flags */
20046558838SMatthew Dillon 	uint8_t		unused02;
20146558838SMatthew Dillon 	uint8_t		unused03;
2021ad77ed9SMatthew Dillon 
20346558838SMatthew Dillon 	ccms_tid_t	path_id;	/* rendezvous inode id */
20446558838SMatthew Dillon 	ccms_tid_t	tid;		/* [meta]data versioning id */
20546558838SMatthew Dillon 	ccms_key_t	key_beg;	/* key range (inclusive) */
20646558838SMatthew Dillon 	ccms_key_t	key_end;	/* key range (inclusive) */
20746558838SMatthew Dillon 
208a0ed3c24SMatthew Dillon 	int32_t		upgrade;	/* upgrades pending */
20946558838SMatthew Dillon 	int32_t		count;		/* active shared/exclusive count */
21046558838SMatthew Dillon 	int32_t		blocked;	/* wakeup blocked on release */
21146558838SMatthew Dillon 	thread_t	td;		/* if excl lock (count < 0) */
212f03672ecSMatthew Dillon };
213f03672ecSMatthew Dillon 
2141ad77ed9SMatthew Dillon /*
2151ad77ed9SMatthew Dillon  * Domain management, contains a pseudo-root for the CCMS topology.
2161ad77ed9SMatthew Dillon  */
2171ad77ed9SMatthew Dillon struct ccms_domain {
2181ad77ed9SMatthew Dillon 	int			cst_count;	/* dynamic cst count */
2191ad77ed9SMatthew Dillon 	int			cst_limit;	/* dynamic cst limit */
2201ad77ed9SMatthew Dillon };
2211ad77ed9SMatthew Dillon 
2221ad77ed9SMatthew Dillon typedef struct ccms_lock	ccms_lock_t;
2231ad77ed9SMatthew Dillon typedef struct ccms_cst		ccms_cst_t;
2241ad77ed9SMatthew Dillon typedef struct ccms_domain	ccms_domain_t;
225f03672ecSMatthew Dillon 
226f03672ecSMatthew Dillon /*
227f03672ecSMatthew Dillon  * Kernel API
228f03672ecSMatthew Dillon  */
229f03672ecSMatthew Dillon #ifdef _KERNEL
230f03672ecSMatthew Dillon 
2311ad77ed9SMatthew Dillon void ccms_domain_init(ccms_domain_t *dom);
23246558838SMatthew Dillon void ccms_domain_uninit(ccms_domain_t *dom);
23346558838SMatthew Dillon void ccms_cst_init(ccms_cst_t *cst, void *handle);
23446558838SMatthew Dillon void ccms_cst_uninit(ccms_cst_t *cst);
2351ad77ed9SMatthew Dillon 
23646558838SMatthew Dillon void ccms_thread_lock(ccms_cst_t *cst, ccms_state_t state);
23746558838SMatthew Dillon int ccms_thread_lock_nonblock(ccms_cst_t *cst, ccms_state_t state);
238*476d2aadSMatthew Dillon ccms_state_t ccms_thread_lock_temp_release(ccms_cst_t *cst);
239a0ed3c24SMatthew Dillon ccms_state_t ccms_thread_lock_upgrade(ccms_cst_t *cst);
240a0ed3c24SMatthew Dillon void ccms_thread_lock_restore(ccms_cst_t *cst, ccms_state_t ostate);
24146558838SMatthew Dillon void ccms_thread_unlock(ccms_cst_t *cst);
24246558838SMatthew Dillon int ccms_thread_unlock_zero(ccms_cst_t *cst);
243a0ed3c24SMatthew Dillon int ccms_thread_lock_owned(ccms_cst_t *cst);
24446558838SMatthew Dillon 
24546558838SMatthew Dillon void ccms_lock_get(ccms_lock_t *lock);
24646558838SMatthew Dillon void ccms_lock_put(ccms_lock_t *lock);
247f03672ecSMatthew Dillon 
248f03672ecSMatthew Dillon #endif
249f03672ecSMatthew Dillon 
250f03672ecSMatthew Dillon #endif
251