Merge tag 'powerpc-6.1-5' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-block.git] / fs / erofs / tagptr.h
CommitLineData
29b24f6c
GX
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * A tagged pointer implementation
b8b58b32 4 */
57b78c9f
GX
5#ifndef __EROFS_FS_TAGPTR_H
6#define __EROFS_FS_TAGPTR_H
b8b58b32
GX
7
8#include <linux/types.h>
9#include <linux/build_bug.h>
10
11/*
12 * the name of tagged pointer types are tagptr{1, 2, 3...}_t
13 * avoid directly using the internal structs __tagptr{1, 2, 3...}
14 */
15#define __MAKE_TAGPTR(n) \
16typedef struct __tagptr##n { \
17 uintptr_t v; \
18} tagptr##n##_t;
19
20__MAKE_TAGPTR(1)
21__MAKE_TAGPTR(2)
22__MAKE_TAGPTR(3)
23__MAKE_TAGPTR(4)
24
25#undef __MAKE_TAGPTR
26
27extern void __compiletime_error("bad tagptr tags")
28 __bad_tagptr_tags(void);
29
30extern void __compiletime_error("bad tagptr type")
31 __bad_tagptr_type(void);
32
33/* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
34#define __tagptr_mask_1(ptr, n) \
35 __builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
36 (1UL << (n)) - 1 :
37
38#define __tagptr_mask(ptr) (\
39 __tagptr_mask_1(ptr, 1) ( \
40 __tagptr_mask_1(ptr, 2) ( \
41 __tagptr_mask_1(ptr, 3) ( \
42 __tagptr_mask_1(ptr, 4) ( \
43 __bad_tagptr_type(), 0)))))
44
45/* generate a tagged pointer from a raw value */
46#define tagptr_init(type, val) \
47 ((typeof(type)){ .v = (uintptr_t)(val) })
48
49/*
50 * directly cast a tagged pointer to the native pointer type, which
51 * could be used for backward compatibility of existing code.
52 */
53#define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
54
55/* encode tagged pointers */
56#define tagptr_fold(type, ptr, _tags) ({ \
57 const typeof(_tags) tags = (_tags); \
58 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
59 __bad_tagptr_tags(); \
60tagptr_init(type, (uintptr_t)(ptr) | tags); })
61
62/* decode tagged pointers */
63#define tagptr_unfold_ptr(tptr) \
64 ((void *)((tptr).v & ~__tagptr_mask(tptr)))
65
66#define tagptr_unfold_tags(tptr) \
67 ((tptr).v & __tagptr_mask(tptr))
68
69/* operations for the tagger pointer */
70#define tagptr_eq(_tptr1, _tptr2) ({ \
71 typeof(_tptr1) tptr1 = (_tptr1); \
72 typeof(_tptr2) tptr2 = (_tptr2); \
73 (void)(&tptr1 == &tptr2); \
74(tptr1).v == (tptr2).v; })
75
76/* lock-free CAS operation */
77#define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
78 typeof(_ptptr) ptptr = (_ptptr); \
79 typeof(_o) o = (_o); \
80 typeof(_n) n = (_n); \
81 (void)(&o == &n); \
82 (void)(&o == ptptr); \
83tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
84
85/* wrap WRITE_ONCE if atomic update is needed */
86#define tagptr_replace_tags(_ptptr, tags) ({ \
87 typeof(_ptptr) ptptr = (_ptptr); \
88 *ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
89*ptptr; })
90
91#define tagptr_set_tags(_ptptr, _tags) ({ \
92 typeof(_ptptr) ptptr = (_ptptr); \
93 const typeof(_tags) tags = (_tags); \
94 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
95 __bad_tagptr_tags(); \
96 ptptr->v |= tags; \
97*ptptr; })
98
99#define tagptr_clear_tags(_ptptr, _tags) ({ \
100 typeof(_ptptr) ptptr = (_ptptr); \
101 const typeof(_tags) tags = (_tags); \
102 if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
103 __bad_tagptr_tags(); \
104 ptptr->v &= ~tags; \
105*ptptr; })
106
57b78c9f 107#endif /* __EROFS_FS_TAGPTR_H */