]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - lib/lockref.c
Merge branch 'lockref' (locked reference counts)
[mirror_ubuntu-artful-kernel.git] / lib / lockref.c
1 #include <linux/export.h>
2 #include <linux/lockref.h>
3
4 #ifdef CONFIG_CMPXCHG_LOCKREF
5
6 /*
7 * Note that the "cmpxchg()" reloads the "old" value for the
8 * failure case.
9 */
10 #define CMPXCHG_LOOP(CODE, SUCCESS) do { \
11 struct lockref old; \
12 BUILD_BUG_ON(sizeof(old) != 8); \
13 old.lock_count = ACCESS_ONCE(lockref->lock_count); \
14 while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \
15 struct lockref new = old, prev = old; \
16 CODE \
17 old.lock_count = cmpxchg(&lockref->lock_count, \
18 old.lock_count, new.lock_count); \
19 if (likely(old.lock_count == prev.lock_count)) { \
20 SUCCESS; \
21 } \
22 } \
23 } while (0)
24
25 #else
26
27 #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
28
29 #endif
30
31 /**
32 * lockref_get - Increments reference count unconditionally
33 * @lockcnt: pointer to lockref structure
34 *
35 * This operation is only valid if you already hold a reference
36 * to the object, so you know the count cannot be zero.
37 */
38 void lockref_get(struct lockref *lockref)
39 {
40 CMPXCHG_LOOP(
41 new.count++;
42 ,
43 return;
44 );
45
46 spin_lock(&lockref->lock);
47 lockref->count++;
48 spin_unlock(&lockref->lock);
49 }
50 EXPORT_SYMBOL(lockref_get);
51
52 /**
53 * lockref_get_not_zero - Increments count unless the count is 0
54 * @lockcnt: pointer to lockref structure
55 * Return: 1 if count updated successfully or 0 if count was zero
56 */
57 int lockref_get_not_zero(struct lockref *lockref)
58 {
59 int retval;
60
61 CMPXCHG_LOOP(
62 new.count++;
63 if (!old.count)
64 return 0;
65 ,
66 return 1;
67 );
68
69 spin_lock(&lockref->lock);
70 retval = 0;
71 if (lockref->count) {
72 lockref->count++;
73 retval = 1;
74 }
75 spin_unlock(&lockref->lock);
76 return retval;
77 }
78 EXPORT_SYMBOL(lockref_get_not_zero);
79
80 /**
81 * lockref_get_or_lock - Increments count unless the count is 0
82 * @lockcnt: pointer to lockref structure
83 * Return: 1 if count updated successfully or 0 if count was zero
84 * and we got the lock instead.
85 */
86 int lockref_get_or_lock(struct lockref *lockref)
87 {
88 CMPXCHG_LOOP(
89 new.count++;
90 if (!old.count)
91 break;
92 ,
93 return 1;
94 );
95
96 spin_lock(&lockref->lock);
97 if (!lockref->count)
98 return 0;
99 lockref->count++;
100 spin_unlock(&lockref->lock);
101 return 1;
102 }
103 EXPORT_SYMBOL(lockref_get_or_lock);
104
105 /**
106 * lockref_put_or_lock - decrements count unless count <= 1 before decrement
107 * @lockcnt: pointer to lockref structure
108 * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
109 */
110 int lockref_put_or_lock(struct lockref *lockref)
111 {
112 CMPXCHG_LOOP(
113 new.count--;
114 if (old.count <= 1)
115 break;
116 ,
117 return 1;
118 );
119
120 spin_lock(&lockref->lock);
121 if (lockref->count <= 1)
122 return 0;
123 lockref->count--;
124 spin_unlock(&lockref->lock);
125 return 1;
126 }
127 EXPORT_SYMBOL(lockref_put_or_lock);