Branch data Line data Source code
1 : : #include <linux/export.h>
2 : : #include <linux/lockref.h>
3 : : #include <linux/mutex.h>
4 : :
5 : : #if USE_CMPXCHG_LOCKREF
6 : :
7 : : /*
8 : : * Allow weakly-ordered memory architectures to provide barrier-less
9 : : * cmpxchg semantics for lockref updates.
10 : : */
11 : : #ifndef cmpxchg64_relaxed
12 : : # define cmpxchg64_relaxed cmpxchg64
13 : : #endif
14 : :
15 : : /*
16 : : * Note that the "cmpxchg()" reloads the "old" value for the
17 : : * failure case.
18 : : */
19 : : #define CMPXCHG_LOOP(CODE, SUCCESS) do { \
20 : : struct lockref old; \
21 : : BUILD_BUG_ON(sizeof(old) != 8); \
22 : : old.lock_count = ACCESS_ONCE(lockref->lock_count); \
23 : : while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \
24 : : struct lockref new = old, prev = old; \
25 : : CODE \
26 : : old.lock_count = cmpxchg64_relaxed(&lockref->lock_count, \
27 : : old.lock_count, \
28 : : new.lock_count); \
29 : : if (likely(old.lock_count == prev.lock_count)) { \
30 : : SUCCESS; \
31 : : } \
32 : : arch_mutex_cpu_relax(); \
33 : : } \
34 : : } while (0)
35 : :
36 : : #else
37 : :
38 : : #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
39 : :
40 : : #endif
41 : :
42 : : /**
43 : : * lockref_get - Increments reference count unconditionally
44 : : * @lockref: pointer to lockref structure
45 : : *
46 : : * This operation is only valid if you already hold a reference
47 : : * to the object, so you know the count cannot be zero.
48 : : */
49 : 0 : void lockref_get(struct lockref *lockref)
50 : : {
51 [ + + ][ + + ]: 17514995 : CMPXCHG_LOOP(
52 : : new.count++;
53 : : ,
54 : : return;
55 : : );
56 : :
57 : : spin_lock(&lockref->lock);
58 : 6176 : lockref->count++;
59 : : spin_unlock(&lockref->lock);
60 : : }
61 : : EXPORT_SYMBOL(lockref_get);
62 : :
63 : : /**
64 : : * lockref_get_not_zero - Increments count unless the count is 0
65 : : * @lockref: pointer to lockref structure
66 : : * Return: 1 if count updated successfully or 0 if count was zero
67 : : */
68 : 0 : int lockref_get_not_zero(struct lockref *lockref)
69 : : {
70 : : int retval;
71 : :
72 [ + + + + ]: 725412 : CMPXCHG_LOOP(
[ + + ]
73 : : new.count++;
74 : : if (!old.count)
75 : : return 0;
76 : : ,
77 : : return 1;
78 : : );
79 : :
80 : : spin_lock(&lockref->lock);
81 : : retval = 0;
82 [ + - ]: 19 : if (lockref->count) {
83 : 19 : lockref->count++;
84 : : retval = 1;
85 : : }
86 : : spin_unlock(&lockref->lock);
87 : 19 : return retval;
88 : : }
89 : : EXPORT_SYMBOL(lockref_get_not_zero);
90 : :
91 : : /**
92 : : * lockref_get_or_lock - Increments count unless the count is 0
93 : : * @lockref: pointer to lockref structure
94 : : * Return: 1 if count updated successfully or 0 if count was zero
95 : : * and we got the lock instead.
96 : : */
97 : 0 : int lockref_get_or_lock(struct lockref *lockref)
98 : : {
99 [ # # # # ]: 0 : CMPXCHG_LOOP(
[ # # ]
100 : : new.count++;
101 : : if (!old.count)
102 : : break;
103 : : ,
104 : : return 1;
105 : : );
106 : :
107 : : spin_lock(&lockref->lock);
108 [ # # ]: 0 : if (!lockref->count)
109 : : return 0;
110 : 0 : lockref->count++;
111 : : spin_unlock(&lockref->lock);
112 : 0 : return 1;
113 : : }
114 : : EXPORT_SYMBOL(lockref_get_or_lock);
115 : :
116 : : /**
117 : : * lockref_put_or_lock - decrements count unless count <= 1 before decrement
118 : : * @lockref: pointer to lockref structure
119 : : * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
120 : : */
121 : 0 : int lockref_put_or_lock(struct lockref *lockref)
122 : : {
123 [ + + + + ]: 30464793 : CMPXCHG_LOOP(
[ + + ]
124 : : new.count--;
125 : : if (old.count <= 1)
126 : : break;
127 : : ,
128 : : return 1;
129 : : );
130 : :
131 : : spin_lock(&lockref->lock);
132 [ + + ]: 5533178 : if (lockref->count <= 1)
133 : : return 0;
134 : 3604 : lockref->count--;
135 : : spin_unlock(&lockref->lock);
136 : 3604 : return 1;
137 : : }
138 : : EXPORT_SYMBOL(lockref_put_or_lock);
139 : :
140 : : /**
141 : : * lockref_mark_dead - mark lockref dead
142 : : * @lockref: pointer to lockref structure
143 : : */
144 : 0 : void lockref_mark_dead(struct lockref *lockref)
145 : : {
146 [ - + ]: 2146965 : assert_spin_locked(&lockref->lock);
147 : 2146965 : lockref->count = -128;
148 : 2146965 : }
149 : : EXPORT_SYMBOL(lockref_mark_dead);
150 : :
151 : : /**
152 : : * lockref_get_not_dead - Increments count unless the ref is dead
153 : : * @lockref: pointer to lockref structure
154 : : * Return: 1 if count updated successfully or 0 if lockref was dead
155 : : */
156 : 0 : int lockref_get_not_dead(struct lockref *lockref)
157 : : {
158 : : int retval;
159 : :
160 [ + + + + ]: 10846409 : CMPXCHG_LOOP(
[ + + ]
161 : : new.count++;
162 : : if ((int)old.count < 0)
163 : : return 0;
164 : : ,
165 : : return 1;
166 : : );
167 : :
168 : : spin_lock(&lockref->lock);
169 : : retval = 0;
170 [ + + ]: 17820 : if ((int) lockref->count >= 0) {
171 : 17817 : lockref->count++;
172 : : retval = 1;
173 : : }
174 : : spin_unlock(&lockref->lock);
175 : 17820 : return retval;
176 : : }
177 : : EXPORT_SYMBOL(lockref_get_not_dead);
|