question about kref API
Jeff Haran
Jeff.Haran at citrix.com
Mon Jul 21 20:27:20 EDT 2014
Hi,
I've been reading Documentation/kref.txt in order to understand the usage of this API. There is part of this documentation that I am having difficulty understanding and was hoping somebody on this list could clarify this. One of my assumptions in reading this is that the expected usage of this API is that for a given object embedding a kref, once the object has been initialized the number of calls to "put" a given instance of an object should never exceed the number of calls to "get" that same instance. Maybe that's the root of my misunderstanding, but my assumption is that calls to kref_get() and kref_put() are expected to be made in pairs for a given instance of struct kref. If this is wrong, please let me know.
Kref.txt includes some sample code that discusses using a mutex to serialize the execution of its get_entry() and put_entry() functions:
146 static DEFINE_MUTEX(mutex);
147 static LIST_HEAD(q);
148 struct my_data
149 {
150 struct kref refcount;
151 struct list_head link;
152 };
153
154 static struct my_data *get_entry()
155 {
156 struct my_data *entry = NULL;
157 mutex_lock(&mutex);
158 if (!list_empty(&q)) {
159 entry = container_of(q.next, struct my_data, link);
160 kref_get(&entry->refcount);
161 }
162 mutex_unlock(&mutex);
163 return entry;
164 }
165
166 static void release_entry(struct kref *ref)
167 {
168 struct my_data *entry = container_of(ref, struct my_data, refcount);
169
170 list_del(&entry->link);
171 kfree(entry);
172 }
173
174 static void put_entry(struct my_data *entry)
175 {
176 mutex_lock(&mutex);
177 kref_put(&entry->refcount, release_entry);
178 mutex_unlock(&mutex);
179 }
The sample code does not show the creation of the link list headed by q, so it is unclear to me what the value of the reference counts in these my_data structures are at the time they are enqueued to the list. Put another way, it's not clear to me from reading this whether kref_init(&(entry->refcount)) was called before the instances of struct my_data were put into the list.
So I have two interpretations of what is being illustrated with this sample code and neither makes much sense to me.
1) The krefs are initialized before they go into the list.
If the krefs in the instances of struct my_data are initialized by kref_init() before they go into the list and thus start off with a 1, then it would seem to me that the mutex would not be necessary so long as the number of calls to put_entry() never exceeds the number of calls to get_entry(). However in this case, (so long as the number of calls to put_entry() never exceeds the number of calls to get_entry()), the release function would never get called and the entries would remain in the list because the reference count would never get down to 0. So this doesn't seem like a correct interpretation to me unless the assumption is that what is being illustrated is a case where the number of calls to put_entry() equals the number of calls to get_entry() plus 1, the final call to put_entry() being the one that causes the deletion of the entry from the list and its freeing, in which case the mutex is clearly necessary. But this usage (# of puts == # of gets + 1) seems somewhat artificial and contrary to my initial assumption.
2) The krefs are not initialized before they go into the list.
On the other hand, if the krefs are not initialized by kref_init() before they go into the list and thus contain 0, then the first call to kref_get() to retrieve a given entry at line 160 would seem problematic since in recent kernels (going back at least 4 years near as I can tell), doing that would generate a warning:
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 WARN_ON_ONCE(atomic_inc_return(&kref->refcount) < 2);
48 }
It doesn't seem reasonable to me that sample code like this would be written such that it generated warnings when executed. So this doesn't seem like a valid interpretation either.
If someone knowledgeable of this interface could explain whether in this sample code the krefs are initialized via kref_init() before they are put into the list, I think it would help a lot in my attempt to understand it.
Thanks,
Jeff Haran
More information about the Kernelnewbies
mailing list