Blame view

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