root/fs/erofs/tagptr.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


   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 

/* [<][>][^][v][top][bottom][index][help] */