1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * A tagged pointer implementation 4 */ 5 #ifndef __EROFS_FS_TAGPTR_H 6 #define __EROFS_FS_TAGPTR_H 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) \ 16 typedef 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 27 extern void __compiletime_error("bad tagptr tags") 28 __bad_tagptr_tags(void); 29 30 extern 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(); \ 60 tagptr_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); \ 83 tagptr_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 107 #endif /* __EROFS_FS_TAGPTR_H */ 108