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