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