Branch data Line data Source code
1 : : /*
2 : : * kref.h - library routines for handling generic reference counted objects
3 : : *
4 : : * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
5 : : * Copyright (C) 2004 IBM Corp.
6 : : *
7 : : * based on kobject.h which was:
8 : : * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
9 : : * Copyright (C) 2002-2003 Open Source Development Labs
10 : : *
11 : : * This file is released under the GPLv2.
12 : : *
13 : : */
14 : :
15 : : #ifndef _KREF_H_
16 : : #define _KREF_H_
17 : :
18 : : #include <linux/bug.h>
19 : : #include <linux/atomic.h>
20 : : #include <linux/kernel.h>
21 : : #include <linux/mutex.h>
22 : : #include <linux/spinlock.h>
23 : :
24 : : struct kref {
25 : : atomic_t refcount;
26 : : };
27 : :
28 : : /**
29 : : * kref_init - initialize object.
30 : : * @kref: object in question.
31 : : */
32 : : static inline void kref_init(struct kref *kref)
33 : : {
34 : 1306430 : atomic_set(&kref->refcount, 1);
35 : : }
36 : :
37 : : /**
38 : : * kref_get - increment refcount for object.
39 : : * @kref: object.
40 : : */
41 : : static inline void kref_get(struct kref *kref)
42 : : {
43 : : /* If refcount was 0 before incrementing then we have a race
44 : : * condition when this kref is freeing by some other thread right now.
45 : : * In this case one should use kref_get_unless_zero()
46 : : */
47 [ - + ][ # # ]: 6553382 : WARN_ON_ONCE(atomic_inc_return(&kref->refcount) < 2);
[ # # ][ - + ]
[ # # ][ # # ]
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
48 : : }
49 : :
50 : : /**
51 : : * kref_sub - subtract a number of refcounts for object.
52 : : * @kref: object.
53 : : * @count: Number of recounts to subtract.
54 : : * @release: pointer to the function that will clean up the object when the
55 : : * last reference to the object is released.
56 : : * This pointer is required, and it is not acceptable to pass kfree
57 : : * in as this function. If the caller does pass kfree to this
58 : : * function, you will be publicly mocked mercilessly by the kref
59 : : * maintainer, and anyone else who happens to notice it. You have
60 : : * been warned.
61 : : *
62 : : * Subtract @count from the refcount, and if 0, call release().
63 : : * Return 1 if the object was removed, otherwise return 0. Beware, if this
64 : : * function returns 0, you still can not count on the kref from remaining in
65 : : * memory. Only use the return value if you want to see if the kref is now
66 : : * gone, not present.
67 : : */
68 : : static inline int kref_sub(struct kref *kref, unsigned int count,
69 : : void (*release)(struct kref *kref))
70 : : {
71 [ - + ][ - + ]: 7856560 : WARN_ON(release == NULL);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ - + ]
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
72 : :
73 [ + + + + : 7858512 : if (atomic_sub_and_test((int) count, &kref->refcount)) {
# # # # #
# # # # #
# # # # -
+ # # - +
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
74 : 1306150 : release(kref);
75 : : return 1;
76 : : }
77 : : return 0;
78 : : }
79 : :
80 : : /**
81 : : * kref_put - decrement refcount for object.
82 : : * @kref: object.
83 : : * @release: pointer to the function that will clean up the object when the
84 : : * last reference to the object is released.
85 : : * This pointer is required, and it is not acceptable to pass kfree
86 : : * in as this function. If the caller does pass kfree to this
87 : : * function, you will be publicly mocked mercilessly by the kref
88 : : * maintainer, and anyone else who happens to notice it. You have
89 : : * been warned.
90 : : *
91 : : * Decrement the refcount, and if 0, call release().
92 : : * Return 1 if the object was removed, otherwise return 0. Beware, if this
93 : : * function returns 0, you still can not count on the kref from remaining in
94 : : * memory. Only use the return value if you want to see if the kref is now
95 : : * gone, not present.
96 : : */
97 : : static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
98 : : {
99 : : return kref_sub(kref, 1, release);
100 : : }
101 : :
102 : : /**
103 : : * kref_put_spinlock_irqsave - decrement refcount for object.
104 : : * @kref: object.
105 : : * @release: pointer to the function that will clean up the object when the
106 : : * last reference to the object is released.
107 : : * This pointer is required, and it is not acceptable to pass kfree
108 : : * in as this function.
109 : : * @lock: lock to take in release case
110 : : *
111 : : * Behaves identical to kref_put with one exception. If the reference count
112 : : * drops to zero, the lock will be taken atomically wrt dropping the reference
113 : : * count. The release function has to call spin_unlock() without _irqrestore.
114 : : */
115 : : static inline int kref_put_spinlock_irqsave(struct kref *kref,
116 : : void (*release)(struct kref *kref),
117 : : spinlock_t *lock)
118 : : {
119 : : unsigned long flags;
120 : :
121 : : WARN_ON(release == NULL);
122 : : if (atomic_add_unless(&kref->refcount, -1, 1))
123 : : return 0;
124 : : spin_lock_irqsave(lock, flags);
125 : : if (atomic_dec_and_test(&kref->refcount)) {
126 : : release(kref);
127 : : local_irq_restore(flags);
128 : : return 1;
129 : : }
130 : : spin_unlock_irqrestore(lock, flags);
131 : : return 0;
132 : : }
133 : :
134 : : static inline int kref_put_mutex(struct kref *kref,
135 : : void (*release)(struct kref *kref),
136 : : struct mutex *lock)
137 : : {
138 [ # # ]: 0 : WARN_ON(release == NULL);
139 [ # # ]: 0 : if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
140 : 0 : mutex_lock(lock);
141 [ # # ]: 0 : if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
142 : 0 : mutex_unlock(lock);
143 : : return 0;
144 : : }
145 : 0 : release(kref);
146 : : return 1;
147 : : }
148 : : return 0;
149 : : }
150 : :
151 : : /**
152 : : * kref_get_unless_zero - Increment refcount for object unless it is zero.
153 : : * @kref: object.
154 : : *
155 : : * Return non-zero if the increment succeeded. Otherwise return 0.
156 : : *
157 : : * This function is intended to simplify locking around refcounting for
158 : : * objects that can be looked up from a lookup structure, and which are
159 : : * removed from that lookup structure in the object destructor.
160 : : * Operations on such objects require at least a read lock around
161 : : * lookup + kref_get, and a write lock around kref_put + remove from lookup
162 : : * structure. Furthermore, RCU implementations become extremely tricky.
163 : : * With a lookup followed by a kref_get_unless_zero *with return value check*
164 : : * locking in the kref_put path can be deferred to the actual removal from
165 : : * the lookup structure and RCU lookups become trivial.
166 : : */
167 : : static inline int __must_check kref_get_unless_zero(struct kref *kref)
168 : : {
169 : 0 : return atomic_add_unless(&kref->refcount, 1, 0);
170 : : }
171 : : #endif /* _KREF_H_ */
|