tagptr.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. #include <linux/types.h>
  10. #include <linux/build_bug.h>
  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. __MAKE_TAGPTR(1)
  20. __MAKE_TAGPTR(2)
  21. __MAKE_TAGPTR(3)
  22. __MAKE_TAGPTR(4)
  23. #undef __MAKE_TAGPTR
  24. extern void __compiletime_error("bad tagptr tags")
  25. __bad_tagptr_tags(void);
  26. extern void __compiletime_error("bad tagptr type")
  27. __bad_tagptr_type(void);
  28. /* fix the broken usage of "#define tagptr2_t tagptr3_t" by users */
  29. #define __tagptr_mask_1(ptr, n) \
  30. __builtin_types_compatible_p(typeof(ptr), struct __tagptr##n) ? \
  31. (1UL << (n)) - 1 :
  32. #define __tagptr_mask(ptr) (\
  33. __tagptr_mask_1(ptr, 1) ( \
  34. __tagptr_mask_1(ptr, 2) ( \
  35. __tagptr_mask_1(ptr, 3) ( \
  36. __tagptr_mask_1(ptr, 4) ( \
  37. __bad_tagptr_type(), 0)))))
  38. /* generate a tagged pointer from a raw value */
  39. #define tagptr_init(type, val) \
  40. ((typeof(type)){ .v = (uintptr_t)(val) })
  41. /*
  42. * directly cast a tagged pointer to the native pointer type, which
  43. * could be used for backward compatibility of existing code.
  44. */
  45. #define tagptr_cast_ptr(tptr) ((void *)(tptr).v)
  46. /* encode tagged pointers */
  47. #define tagptr_fold(type, ptr, _tags) ({ \
  48. const typeof(_tags) tags = (_tags); \
  49. if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(type))) \
  50. __bad_tagptr_tags(); \
  51. tagptr_init(type, (uintptr_t)(ptr) | tags); })
  52. /* decode tagged pointers */
  53. #define tagptr_unfold_ptr(tptr) \
  54. ((void *)((tptr).v & ~__tagptr_mask(tptr)))
  55. #define tagptr_unfold_tags(tptr) \
  56. ((tptr).v & __tagptr_mask(tptr))
  57. /* operations for the tagger pointer */
  58. #define tagptr_eq(_tptr1, _tptr2) ({ \
  59. typeof(_tptr1) tptr1 = (_tptr1); \
  60. typeof(_tptr2) tptr2 = (_tptr2); \
  61. (void)(&tptr1 == &tptr2); \
  62. (tptr1).v == (tptr2).v; })
  63. /* lock-free CAS operation */
  64. #define tagptr_cmpxchg(_ptptr, _o, _n) ({ \
  65. typeof(_ptptr) ptptr = (_ptptr); \
  66. typeof(_o) o = (_o); \
  67. typeof(_n) n = (_n); \
  68. (void)(&o == &n); \
  69. (void)(&o == ptptr); \
  70. tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
  71. /* wrap WRITE_ONCE if atomic update is needed */
  72. #define tagptr_replace_tags(_ptptr, tags) ({ \
  73. typeof(_ptptr) ptptr = (_ptptr); \
  74. *ptptr = tagptr_fold(*ptptr, tagptr_unfold_ptr(*ptptr), tags); \
  75. *ptptr; })
  76. #define tagptr_set_tags(_ptptr, _tags) ({ \
  77. typeof(_ptptr) ptptr = (_ptptr); \
  78. const typeof(_tags) tags = (_tags); \
  79. if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
  80. __bad_tagptr_tags(); \
  81. ptptr->v |= tags; \
  82. *ptptr; })
  83. #define tagptr_clear_tags(_ptptr, _tags) ({ \
  84. typeof(_ptptr) ptptr = (_ptptr); \
  85. const typeof(_tags) tags = (_tags); \
  86. if (__builtin_constant_p(tags) && (tags & ~__tagptr_mask(*ptptr))) \
  87. __bad_tagptr_tags(); \
  88. ptptr->v &= ~tags; \
  89. *ptptr; })
  90. #endif /* __EROFS_FS_TAGPTR_H */