aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig10
-rw-r--r--lib/Makefile1
-rw-r--r--lib/lockref.c127
3 files changed, 138 insertions, 0 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 71d9f81f6eed..65561716c16c 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -48,6 +48,16 @@ config STMP_DEVICE
48config PERCPU_RWSEM 48config PERCPU_RWSEM
49 boolean 49 boolean
50 50
51config ARCH_USE_CMPXCHG_LOCKREF
52 bool
53
54config CMPXCHG_LOCKREF
55 def_bool y if ARCH_USE_CMPXCHG_LOCKREF
56 depends on SMP
57 depends on !GENERIC_LOCKBREAK
58 depends on !DEBUG_SPINLOCK
59 depends on !DEBUG_LOCK_ALLOC
60
51config CRC_CCITT 61config CRC_CCITT
52 tristate "CRC-CCITT functions" 62 tristate "CRC-CCITT functions"
53 help 63 help
diff --git a/lib/Makefile b/lib/Makefile
index 7baccfd8a4e9..f2cb3082697c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,6 +20,7 @@ lib-$(CONFIG_MMU) += ioremap.o
20lib-$(CONFIG_SMP) += cpumask.o 20lib-$(CONFIG_SMP) += cpumask.o
21 21
22lib-y += kobject.o klist.o 22lib-y += kobject.o klist.o
23obj-y += lockref.o
23 24
24obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ 25obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
25 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ 26 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
diff --git a/lib/lockref.c b/lib/lockref.c
new file mode 100644
index 000000000000..7819c2d1d315
--- /dev/null
+++ b/lib/lockref.c
@@ -0,0 +1,127 @@
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 */
38void 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}
50EXPORT_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 */
57int 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}
78EXPORT_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 */
86int 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}
103EXPORT_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 */
110int 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}
127EXPORT_SYMBOL(lockref_put_or_lock);