Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * A tagged pointer implementation
0004  */
0005 #ifndef __EROFS_FS_TAGPTR_H
0006 #define __EROFS_FS_TAGPTR_H
0007 
0008 #include <linux/types.h>
0009 #include <linux/build_bug.h>
0010 
0011 /*
0012  * the name of tagged pointer types are tagptr{1, 2, 3...}_t
0013  * avoid directly using the internal structs __tagptr{1, 2, 3...}
0014  */
0015 #define __MAKE_TAGPTR(n) \
0016 typedef struct __tagptr##n {    \
0017     uintptr_t v;    \
0018 } tagptr##n##_t;
0019 
0020 __MAKE_TAGPTR(1)
0021 __MAKE_TAGPTR(2)
0022 __MAKE_TAGPTR(3)
0023 __MAKE_TAGPTR(4)
0024 
0025 #undef __MAKE_TAGPTR
0026 
0027 extern void __compiletime_error("bad tagptr tags")
0028     __bad_tagptr_tags(void);
0029 
0030 extern void __compiletime_error("bad tagptr type")
0031     __bad_tagptr_type(void);
0032 
0033 /* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
0034 #define __tagptr_mask_1(ptr, n) \
0035     __builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
0036         (1UL << (n)) - 1 :
0037 
0038 #define __tagptr_mask(ptr)  (\
0039     __tagptr_mask_1(ptr, 1) ( \
0040     __tagptr_mask_1(ptr, 2) ( \
0041     __tagptr_mask_1(ptr, 3) ( \
0042     __tagptr_mask_1(ptr, 4) ( \
0043     __bad_tagptr_type(), 0)))))
0044 
0045 /* generate a tagged pointer from a raw value */
0046 #define tagptr_init(type, val) \
0047     ((typeof(type)){ .v = (uintptr_t)(val) })
0048 
0049 /*
0050  * directly cast a tagged pointer to the native pointer type, which
0051  * could be used for backward compatibility of existing code.
0052  */
0053 #define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
0054 
0055 /* encode tagged pointers */
0056 #define tagptr_fold(type, ptr, _tags) ({ \
0057     const typeof(_tags) tags = (_tags); \
0058     if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
0059         __bad_tagptr_tags(); \
0060 tagptr_init(type, (uintptr_t)(ptr) | tags); })
0061 
0062 /* decode tagged pointers */
0063 #define tagptr_unfold_ptr(tptr) \
0064     ((void *)((tptr).v & ~__tagptr_mask(tptr)))
0065 
0066 #define tagptr_unfold_tags(tptr) \
0067     ((tptr).v & __tagptr_mask(tptr))
0068 
0069 /* operations for the tagger pointer */
0070 #define tagptr_eq(_tptr1, _tptr2) ({ \
0071     typeof(_tptr1) tptr1 = (_tptr1); \
0072     typeof(_tptr2) tptr2 = (_tptr2); \
0073     (void)(&tptr1 == &tptr2); \
0074 (tptr1).v == (tptr2).v; })
0075 
0076 /* lock-free CAS operation */
0077 #define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
0078     typeof(_ptptr) ptptr = (_ptptr); \
0079     typeof(_o) o = (_o); \
0080     typeof(_n) n = (_n); \
0081     (void)(&o == &n); \
0082     (void)(&o == ptptr); \
0083 tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
0084 
0085 /* wrap WRITE_ONCE if atomic update is needed */
0086 #define tagptr_replace_tags(_ptptr, tags) ({ \
0087     typeof(_ptptr) ptptr = (_ptptr); \
0088     *ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
0089 *ptptr; })
0090 
0091 #define tagptr_set_tags(_ptptr, _tags) ({ \
0092     typeof(_ptptr) ptptr = (_ptptr); \
0093     const typeof(_tags) tags = (_tags); \
0094     if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
0095         __bad_tagptr_tags(); \
0096     ptptr->v |= tags; \
0097 *ptptr; })
0098 
0099 #define tagptr_clear_tags(_ptptr, _tags) ({ \
0100     typeof(_ptptr) ptptr = (_ptptr); \
0101     const typeof(_tags) tags = (_tags); \
0102     if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
0103         __bad_tagptr_tags(); \
0104     ptptr->v &= ~tags; \
0105 *ptptr; })
0106 
0107 #endif  /* __EROFS_FS_TAGPTR_H */