linux/fs/erofs/tagptr.h
<<
>>
Prefs
   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) \
  18typedef 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
  29extern void __compiletime_error("bad tagptr tags")
  30        __bad_tagptr_tags(void);
  31
  32extern 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(); \
  62tagptr_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); \
  85tagptr_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