sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextChinese (Simplified)}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget!/translations/zh_CN/core-api/krefmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/zh_TW/core-api/krefmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/it_IT/core-api/krefmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/ja_JP/core-api/krefmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/ko_KR/core-api/krefmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget!/translations/sp_SP/core-api/krefmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageEnglishuh1h hh _documenthsourceNlineNubhsection)}(hhh](htitle)}(h3Adding reference counters (krefs) to kernel objectsh]h3Adding reference counters (krefs) to kernel objects}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhh;/var/lib/git/docbuild/linux/Documentation/core-api/kref.rsthKubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hAuthorh]hAuthor}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(hCorey Minyard h]h paragraph)}(hhh](hCorey Minyard <}(hhhhhNhNubh reference)}(hminyard@acm.orgh]hminyard@acm.org}(hhhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:minyard@acm.orguh1hhhubh>}(hhhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(hAuthorh]hAuthor}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(h5Thomas Hellström h]h)}(h4Thomas Hellström h](hThomas Hellström <}(hjhhhNhNubh)}(h thomas.hellstrom@linux.intel.comh]h thomas.hellstrom@linux.intel.com}(hj%hhhNhNubah}(h]h ]h"]h$]h&]refuri'mailto:thomas.hellstrom@linux.intel.comuh1hhjubh>}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(hsA lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and presentation on krefs, which can be found at:h]huA lot of this was lifted from Greg Kroah-Hartman’s 2004 OLS paper and presentation on krefs, which can be found at:}(hjQhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh block_quote)}(h- http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf - http://www.kroah.com/linux/talks/ols_2004_kref_talk/ h]h bullet_list)}(hhh](h list_item)}(hVhttp://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdfh]h)}(hjnh]h)}(hjnh]hVhttp://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf}(hjshhhNhNubah}(h]h ]h"]h$]h&]refurijnuh1hhjpubah}(h]h ]h"]h$]h&]uh1hhhhK hjlubah}(h]h ]h"]h$]h&]uh1jjhjgubjk)}(h5http://www.kroah.com/linux/talks/ols_2004_kref_talk/ h]h)}(h4http://www.kroah.com/linux/talks/ols_2004_kref_talk/h]h)}(hjh]h4http://www.kroah.com/linux/talks/ols_2004_kref_talk/}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurijuh1hhjubah}(h]h ]h"]h$]h&]uh1hhhhK hjubah}(h]h ]h"]h$]h&]uh1jjhjgubeh}(h]h ]h"]h$]h&]bullet-uh1jehhhK hjaubah}(h]h ]h"]h$]h&]uh1j_hhhK hhhhubh)}(hhh](h)}(h Introductionh]h Introduction}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubh)}(hkrefs allow you to add reference counters to your objects. If you have objects that are used in multiple places and passed around, and you don't have refcounts, your code is almost certainly broken. If you want refcounts, krefs are the way to go.h]hkrefs allow you to add reference counters to your objects. If you have objects that are used in multiple places and passed around, and you don’t have refcounts, your code is almost certainly broken. If you want refcounts, krefs are the way to go.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(h5To use a kref, add one to your data structures like::h]h4To use a kref, add one to your data structures like:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh literal_block)}(hEstruct my_data { . . struct kref refcount; . . };h]hEstruct my_data { . . struct kref refcount; . . };}hjsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1jhhhKhjhhubh)}(h6The kref can occur anywhere within the data structure.h]h6The kref can occur anywhere within the data structure.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hjhhubeh}(h] introductionah ]h"] introductionah$]h&]uh1hhhhhhhhKubh)}(hhh](h)}(hInitializationh]hInitialization}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhK$ubh)}(hWYou must initialize the kref after you allocate it. To do this, call kref_init as so::h]hVYou must initialize the kref after you allocate it. To do this, call kref_init as so:}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK&hjhhubj)}(hstruct my_data *data; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount);h]hstruct my_data *data; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount);}hj1sbah}(h]h ]h"]h$]h&]jjuh1jhhhK)hjhhubh)}(h(This sets the refcount in the kref to 1.h]h(This sets the refcount in the kref to 1.}(hj?hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK0hjhhubeh}(h]initializationah ]h"]initializationah$]h&]uh1hhhhhhhhK$ubh)}(hhh](h)}(h Kref rulesh]h Kref rules}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjUhhhhhK3ubh)}(hGOnce you have an initialized kref, you must follow the following rules:h]hGOnce you have an initialized kref, you must follow the following rules:}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK5hjUhhubhenumerated_list)}(hhh](jk)}(hXSIf you make a non-temporary copy of a pointer, especially if it can be passed to another thread of execution, you must increment the refcount with kref_get() before passing it off:: kref_get(&data->refcount); If you already have a valid pointer to a kref-ed structure (the refcount cannot go to zero) you may do this without a lock. h](h)}(hIf you make a non-temporary copy of a pointer, especially if it can be passed to another thread of execution, you must increment the refcount with kref_get() before passing it off::h]hIf you make a non-temporary copy of a pointer, especially if it can be passed to another thread of execution, you must increment the refcount with kref_get() before passing it off:}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK8hjyubj)}(hkref_get(&data->refcount);h]hkref_get(&data->refcount);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjyubeh}(h]h ]h"]h$]h&]uh1jjhjvhhhhhNubjk)}(hXTWhen you are done with a pointer, you must call kref_put():: kref_put(&data->refcount, data_release); If this is the last reference to the pointer, the release routine will be called. If the code never tries to get a valid pointer to a kref-ed structure without already holding a valid pointer, it is safe to do this without a lock. h](h)}(hrefcount, data_release);h]h(kref_put(&data->refcount, data_release);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKChjubh)}(hIf this is the last reference to the pointer, the release routine will be called. If the code never tries to get a valid pointer to a kref-ed structure without already holding a valid pointer, it is safe to do this without a lock.h]hIf this is the last reference to the pointer, the release routine will be called. If the code never tries to get a valid pointer to a kref-ed structure without already holding a valid pointer, it is safe to do this without a lock.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKEhjubeh}(h]h ]h"]h$]h&]uh1jjhjvhhhhhNubjk)}(hIf the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get(). h]h)}(hIf the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get().h]hIf the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get().}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKKhjubah}(h]h ]h"]h$]h&]uh1jjhjvhhhhhNubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix)uh1jthjUhhhhhK8ubh)}(hVFor example, if you allocate some data and then pass it to another thread to process::h]hUFor example, if you allocate some data and then pass it to another thread to process:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKPhjUhhubj)}(hXkvoid data_release(struct kref *ref) { struct my_data *data = container_of(ref, struct my_data, refcount); kfree(data); } void more_data_handling(void *cb_data) { struct my_data *data = cb_data; . . do stuff with data here . kref_put(&data->refcount, data_release); } int my_data_handler(void) { int rv = 0; struct my_data *data; struct task_struct *task; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount); kref_get(&data->refcount); task = kthread_run(more_data_handling, data, "more_data_handling"); if (task == ERR_PTR(-ENOMEM)) { rv = -ENOMEM; kref_put(&data->refcount, data_release); goto out; } . . do stuff with data here . out: kref_put(&data->refcount, data_release); return rv; }h]hXkvoid data_release(struct kref *ref) { struct my_data *data = container_of(ref, struct my_data, refcount); kfree(data); } void more_data_handling(void *cb_data) { struct my_data *data = cb_data; . . do stuff with data here . kref_put(&data->refcount, data_release); } int my_data_handler(void) { int rv = 0; struct my_data *data; struct task_struct *task; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount); kref_get(&data->refcount); task = kthread_run(more_data_handling, data, "more_data_handling"); if (task == ERR_PTR(-ENOMEM)) { rv = -ENOMEM; kref_put(&data->refcount, data_release); goto out; } . . do stuff with data here . out: kref_put(&data->refcount, data_release); return rv; }}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKShjUhhubh)}(hXlThis way, it doesn't matter what order the two threads handle the data, the kref_put() handles knowing when the data is not referenced any more and releasing it. The kref_get() does not require a lock, since we already have a valid pointer that we own a refcount for. The put needs no lock because nothing tries to get the data without already holding a pointer.h]hXnThis way, it doesn’t matter what order the two threads handle the data, the kref_put() handles knowing when the data is not referenced any more and releasing it. The kref_get() does not require a lock, since we already have a valid pointer that we own a refcount for. The put needs no lock because nothing tries to get the data without already holding a pointer.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK|hjUhhubh)}(hIn the above example, kref_put() will be called 2 times in both success and error paths. This is necessary because the reference count got incremented 2 times by kref_init() and kref_get().h]hIn the above example, kref_put() will be called 2 times in both success and error paths. This is necessary because the reference count got incremented 2 times by kref_init() and kref_get().}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubh)}(hYNote that the "before" in rule 1 is very important. You should never do something like::h]h\Note that the “before” in rule 1 is very important. You should never do something like:}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(htask = kthread_run(more_data_handling, data, "more_data_handling"); if (task == ERR_PTR(-ENOMEM)) { rv = -ENOMEM; goto out; } else /* BAD BAD BAD - get is after the handoff */ kref_get(&data->refcount);h]htask = kthread_run(more_data_handling, data, "more_data_handling"); if (task == ERR_PTR(-ENOMEM)) { rv = -ENOMEM; goto out; } else /* BAD BAD BAD - get is after the handoff */ kref_get(&data->refcount);}hjJsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(hXoDon't assume you know what you are doing and use the above construct. First of all, you may not know what you are doing. Second, you may know what you are doing (there are some situations where locking is involved where the above may be legal) but someone else who doesn't know what they are doing may change the code or copy the code. It's bad style. Don't do it.h]hXwDon’t assume you know what you are doing and use the above construct. First of all, you may not know what you are doing. Second, you may know what you are doing (there are some situations where locking is involved where the above may be legal) but someone else who doesn’t know what they are doing may change the code or copy the code. It’s bad style. Don’t do it.}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubh)}(hThere are some situations where you can optimize the gets and puts. For instance, if you are done with an object and enqueuing it for something else or passing it off to something else, there is no reason to do a get then a put::h]hThere are some situations where you can optimize the gets and puts. For instance, if you are done with an object and enqueuing it for something else or passing it off to something else, there is no reason to do a get then a put:}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(hb/* Silly extra get and put */ kref_get(&obj->ref); enqueue(obj); kref_put(&obj->ref, obj_cleanup);h]hb/* Silly extra get and put */ kref_get(&obj->ref); enqueue(obj); kref_put(&obj->ref, obj_cleanup);}hjtsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(h>Just do the enqueue. A comment about this is always welcome::h]h=Just do the enqueue. A comment about this is always welcome:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(hsenqueue(obj); /* We are done with obj, so we pass our refcount off to the queue. DON'T TOUCH obj AFTER HERE! */h]hsenqueue(obj); /* We are done with obj, so we pass our refcount off to the queue. DON'T TOUCH obj AFTER HERE! */}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(hXfThe last rule (rule 3) is the nastiest one to handle. Say, for instance, you have a list of items that are each kref-ed, and you wish to get the first one. You can't just pull the first item off the list and kref_get() it. That violates rule 3 because you are not already holding a valid pointer. You must add a mutex (or some other lock). For instance::h]hXgThe last rule (rule 3) is the nastiest one to handle. Say, for instance, you have a list of items that are each kref-ed, and you wish to get the first one. You can’t just pull the first item off the list and kref_get() it. That violates rule 3 because you are not already holding a valid pointer. You must add a mutex (or some other lock). For instance:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(hXstatic DEFINE_MUTEX(mutex); static LIST_HEAD(q); struct my_data { struct kref refcount; struct list_head link; }; static struct my_data *get_entry() { struct my_data *entry = NULL; mutex_lock(&mutex); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); kref_get(&entry->refcount); } mutex_unlock(&mutex); return entry; } static void release_entry(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); list_del(&entry->link); kfree(entry); } static void put_entry(struct my_data *entry) { mutex_lock(&mutex); kref_put(&entry->refcount, release_entry); mutex_unlock(&mutex); }h]hXstatic DEFINE_MUTEX(mutex); static LIST_HEAD(q); struct my_data { struct kref refcount; struct list_head link; }; static struct my_data *get_entry() { struct my_data *entry = NULL; mutex_lock(&mutex); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); kref_get(&entry->refcount); } mutex_unlock(&mutex); return entry; } static void release_entry(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); list_del(&entry->link); kfree(entry); } static void put_entry(struct my_data *entry) { mutex_lock(&mutex); kref_put(&entry->refcount, release_entry); mutex_unlock(&mutex); }}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(hX The kref_put() return value is useful if you do not want to hold the lock during the whole release operation. Say you didn't want to call kfree() with the lock held in the example above (since it is kind of pointless to do so). You could use kref_put() as follows::h]hX The kref_put() return value is useful if you do not want to hold the lock during the whole release operation. Say you didn’t want to call kfree() with the lock held in the example above (since it is kind of pointless to do so). You could use kref_put() as follows:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(hXstatic void release_entry(struct kref *ref) { /* All work is done after the return from kref_put(). */ } static void put_entry(struct my_data *entry) { mutex_lock(&mutex); if (kref_put(&entry->refcount, release_entry)) { list_del(&entry->link); mutex_unlock(&mutex); kfree(entry); } else mutex_unlock(&mutex); }h]hXstatic void release_entry(struct kref *ref) { /* All work is done after the return from kref_put(). */ } static void put_entry(struct my_data *entry) { mutex_lock(&mutex); if (kref_put(&entry->refcount, release_entry)) { list_del(&entry->link); mutex_unlock(&mutex); kfree(entry); } else mutex_unlock(&mutex); }}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(hThis is really more useful if you have to call other routines as part of the free operations that could take a long time or might claim the same lock. Note that doing everything in the release routine is still preferred as it is a little neater.h]hThis is really more useful if you have to call other routines as part of the free operations that could take a long time or might claim the same lock. Note that doing everything in the release routine is still preferred as it is a little neater.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubh)}(h]The above example could also be optimized using kref_get_unless_zero() in the following way::h]h\The above example could also be optimized using kref_get_unless_zero() in the following way:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjUhhubj)}(hXstatic struct my_data *get_entry() { struct my_data *entry = NULL; mutex_lock(&mutex); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); if (!kref_get_unless_zero(&entry->refcount)) entry = NULL; } mutex_unlock(&mutex); return entry; } static void release_entry(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); mutex_lock(&mutex); list_del(&entry->link); mutex_unlock(&mutex); kfree(entry); } static void put_entry(struct my_data *entry) { kref_put(&entry->refcount, release_entry); }h]hXstatic struct my_data *get_entry() { struct my_data *entry = NULL; mutex_lock(&mutex); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); if (!kref_get_unless_zero(&entry->refcount)) entry = NULL; } mutex_unlock(&mutex); return entry; } static void release_entry(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); mutex_lock(&mutex); list_del(&entry->link); mutex_unlock(&mutex); kfree(entry); } static void put_entry(struct my_data *entry) { kref_put(&entry->refcount, release_entry); }}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKhjUhhubh)}(hXWhich is useful to remove the mutex lock around kref_put() in put_entry(), but it's important that kref_get_unless_zero is enclosed in the same critical section that finds the entry in the lookup table, otherwise kref_get_unless_zero may reference already freed memory. Note that it is illegal to use kref_get_unless_zero without checking its return value. If you are sure (by already having a valid pointer) that kref_get_unless_zero() will return true, then use kref_get() instead.h]hXWhich is useful to remove the mutex lock around kref_put() in put_entry(), but it’s important that kref_get_unless_zero is enclosed in the same critical section that finds the entry in the lookup table, otherwise kref_get_unless_zero may reference already freed memory. Note that it is illegal to use kref_get_unless_zero without checking its return value. If you are sure (by already having a valid pointer) that kref_get_unless_zero() will return true, then use kref_get() instead.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hjUhhubeh}(h] kref-rulesah ]h"] kref rulesah$]h&]uh1hhhhhhhhK3ubh)}(hhh](h)}(h Krefs and RCUh]h Krefs and RCU}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhhhMubh)}(hnThe function kref_get_unless_zero also makes it possible to use rcu locking for lookups in the above example::h]hmThe function kref_get_unless_zero also makes it possible to use rcu locking for lookups in the above example:}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(hXEstruct my_data { struct rcu_head rhead; . struct kref refcount; . . }; static struct my_data *get_entry_rcu() { struct my_data *entry = NULL; rcu_read_lock(); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); if (!kref_get_unless_zero(&entry->refcount)) entry = NULL; } rcu_read_unlock(); return entry; } static void release_entry_rcu(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); mutex_lock(&mutex); list_del_rcu(&entry->link); mutex_unlock(&mutex); kfree_rcu(entry, rhead); } static void put_entry(struct my_data *entry) { kref_put(&entry->refcount, release_entry_rcu); }h]hXEstruct my_data { struct rcu_head rhead; . struct kref refcount; . . }; static struct my_data *get_entry_rcu() { struct my_data *entry = NULL; rcu_read_lock(); if (!list_empty(&q)) { entry = container_of(q.next, struct my_data, link); if (!kref_get_unless_zero(&entry->refcount)) entry = NULL; } rcu_read_unlock(); return entry; } static void release_entry_rcu(struct kref *ref) { struct my_data *entry = container_of(ref, struct my_data, refcount); mutex_lock(&mutex); list_del_rcu(&entry->link); mutex_unlock(&mutex); kfree_rcu(entry, rhead); } static void put_entry(struct my_data *entry) { kref_put(&entry->refcount, release_entry_rcu); }}hj5sbah}(h]h ]h"]h$]h&]jjuh1jhhhMhjhhubh)}(hXHBut note that the struct kref member needs to remain in valid memory for a rcu grace period after release_entry_rcu was called. That can be accomplished by using kfree_rcu(entry, rhead) as done above, or by calling synchronize_rcu() before using kfree, but note that synchronize_rcu() may sleep for a substantial amount of time.h]hXHBut note that the struct kref member needs to remain in valid memory for a rcu grace period after release_entry_rcu was called. That can be accomplished by using kfree_rcu(entry, rhead) as done above, or by calling synchronize_rcu() before using kfree, but note that synchronize_rcu() may sleep for a substantial amount of time.}(hjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM?hjhhubeh}(h] krefs-and-rcuah ]h"] krefs and rcuah$]h&]uh1hhhhhhhhMubh)}(hhh](h)}(hFunctions and structuresh]hFunctions and structures}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjYhhhhhMFubhindex)}(hhh]h}(h]h ]h"]h$]h&]entries](singlekref_init (C function) c.kref_inithNtauh1jjhjYhhhNhNubhdesc)}(hhh](hdesc_signature)}(h"void kref_init (struct kref *kref)h]hdesc_signature_line)}(h!void kref_init(struct kref *kref)h](hdesc_sig_keyword_type)}(hvoidh]hvoid}(hjhhhNhNubah}(h]h ]ktah"]h$]h&]uh1jhjhhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKubhdesc_sig_space)}(h h]h }(hjhhhNhNubah}(h]h ]wah"]h$]h&]uh1jhjhhhjhKubh desc_name)}(h kref_inith]h desc_sig_name)}(h kref_inith]h kref_init}(hjhhhNhNubah}(h]h ]nah"]h$]h&]uh1jhjubah}(h]h ](sig-namedescnameeh"]h$]h&]jjuh1jhjhhhjhKubhdesc_parameterlist)}(h(struct kref *kref)h]hdesc_parameter)}(hstruct kref *krefh](hdesc_sig_keyword)}(hstructh]hstruct}(hjhhhNhNubah}(h]h ]kah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomaincreftype identifier reftargetjmodnameN classnameN c:parent_keysphinx.domains.c LookupKey)}data]j ASTIdentifier)}jjsb c.kref_initasbuh1hhjubj)}(h h]h }(hj%hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubhdesc_sig_punctuation)}(h*h]h*}(hj5hhhNhNubah}(h]h ]pah"]h$]h&]uh1j3hjubj)}(hkrefh]hkref}(hjDhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]noemphjjuh1jhjubah}(h]h ]h"]h$]h&]jjuh1jhjhhhjhKubeh}(h]h ]h"]h$]h&]jj add_permalinkuh1jsphinx_line_type declaratorhjhhhjhKubah}(h]jyah ](sig sig-objecteh"]h$]h&] is_multiline _toc_parts) _toc_namehuh1jhjhKhj}hhubh desc_content)}(hhh]h)}(hinitialize object.h]hinitialize object.}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKhjuhhubah}(h]h ]h"]h$]h&]uh1jshj}hhhjhKubeh}(h]h ](jfunctioneh"]h$]h&]domainjobjtypejdesctypejnoindex noindexentrynocontentsentryuh1j{hhhjYhNhNubh container)}(h;**Parameters** ``struct kref *kref`` object in question.h](h)}(h**Parameters**h]hstrong)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKhjubhdefinition_list)}(hhh]hdefinition_list_item)}(h)``struct kref *kref`` object in question.h](hterm)}(h``struct kref *kref``h]hliteral)}(hjh]hstruct kref *kref}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK hjubh definition)}(hhh]h)}(hobject in question.h]hobject in question.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhjhK hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubjk)}(hhh]h}(h]h ]h"]h$]h&]entries](jwkref_get (C function) c.kref_gethNtauh1jjhjYhhhNhNubj|)}(hhh](j)}(h!void kref_get (struct kref *kref)h]j)}(h void kref_get(struct kref *kref)h](j)}(hvoidh]hvoid}(hj'hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj#hhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK+ubj)}(h h]h }(hj6hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj#hhhj5hK+ubj)}(hkref_geth]j)}(hkref_geth]hkref_get}(hjHhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjDubah}(h]h ](jjeh"]h$]h&]jjuh1jhj#hhhj5hK+ubj)}(h(struct kref *kref)h]j)}(hstruct kref *krefh](j)}(hjh]hstruct}(hjdhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj`ubj)}(h h]h }(hjqhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj`ubh)}(hhh]j)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j )}jjJsb c.kref_getasbuh1hhj`ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj`ubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj`ubj)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj`ubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj\ubah}(h]h ]h"]h$]h&]jjuh1jhj#hhhj5hK+ubeh}(h]h ]h"]h$]h&]jjjeuh1jjfjghjhhhj5hK+ubah}(h]jah ](jkjleh"]h$]h&]jpjq)jrhuh1jhj5hK+hjhhubjt)}(hhh]h)}(hincrement refcount for object.h]hincrement refcount for object.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK(hjhhubah}(h]h ]h"]h$]h&]uh1jshjhhhj5hK+ubeh}(h]h ](jfunctioneh"]h$]h&]jjjjjjjjjuh1j{hhhjYhNhNubj)}(h/**Parameters** ``struct kref *kref`` object.h](h)}(h**Parameters**h]j)}(hj h]h Parameters}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK,hjubj)}(hhh]j)}(h``struct kref *kref`` object.h](j)}(h``struct kref *kref``h]j)}(hj(h]hstruct kref *kref}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj&ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK.hj"ubj)}(hhh]h)}(hobject.h]hobject.}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK)hj>ubah}(h]h ]h"]h$]h&]uh1jhj"ubeh}(h]h ]h"]h$]h&]uh1jhj=hK.hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubjk)}(hhh]h}(h]h ]h"]h$]h&]entries](jwkref_put (C function) c.kref_puthNtauh1jjhjYhhhNhNubj|)}(hhh](j)}(hDint kref_put (struct kref *kref, void (*release)(struct kref *kref))h]j)}(hCint kref_put(struct kref *kref, void (*release)(struct kref *kref))h](j)}(hinth]hint}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj~hhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK>ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj~hhhjhK>ubj)}(hkref_puth]j)}(hkref_puth]hkref_put}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ](jjeh"]h$]h&]jjuh1jhj~hhhjhK>ubj)}(h7(struct kref *kref, void (*release)(struct kref *kref))h](j)}(hstruct kref *krefh](j)}(hjh]hstruct}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j )}jjsb c.kref_putasbuh1hhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj4)}(hj7h]h*}(hj hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjubj)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]noemphjjuh1jhjubj)}(h"void (*release)(struct kref *kref)h](j)}(hvoidh]hvoid}(hj1hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj)}(h h]h }(hj?hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj4)}(h(h]h(}(hjMhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubj4)}(hj7h]h*}(hj[hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubj)}(hreleaseh]hrelease}(hjhhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj4)}(hjh]h)}(hjvhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubj4)}(hjOh]h(}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubj)}(hjh]hstruct}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubh)}(hhh]j)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j c.kref_putasbuh1hhj-ubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubj)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj-ubj4)}(hjh]h)}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj-ubeh}(h]h ]h"]h$]h&]noemphjjuh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhj~hhhjhK>ubeh}(h]h ]h"]h$]h&]jjjeuh1jjfjghjzhhhjhK>ubah}(h]juah ](jkjleh"]h$]h&]jpjq)jrhuh1jhjhK>hjwhhubjt)}(hhh]h)}(hDecrement refcount for objecth]hDecrement refcount for object}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK1hj hhubah}(h]h ]h"]h$]h&]uh1jshjwhhhjhK>ubeh}(h]h ](jfunctioneh"]h$]h&]jjjj6 jj6 jjjuh1j{hhhjYhNhNubj)}(hX]**Parameters** ``struct kref *kref`` Object ``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. **Description** Decrement the refcount, and if 0, call **release**. The caller may not pass NULL or kfree() as the release function. **Return** 1 if this call removed the object, otherwise return 0. Beware, if this function returns 0, another caller may have removed the object by the time this function returns. The return value is only certain if you want to see if the object is definitely released.h](h)}(h**Parameters**h]j)}(hj@ h]h Parameters}(hjB hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj> ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK5hj: ubj)}(hhh](j)}(h``struct kref *kref`` Object h](j)}(h``struct kref *kref``h]j)}(hj_ h]hstruct kref *kref}(hja hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj] ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK2hjY ubj)}(hhh]h)}(hObjecth]hObject}(hjx hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjt hK2hju ubah}(h]h ]h"]h$]h&]uh1jhjY ubeh}(h]h ]h"]h$]h&]uh1jhjt hK2hjV ubj)}(h``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. h](j)}(h&``void (*release)(struct kref *kref)``h]j)}(hj h]h"void (*release)(struct kref *kref)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK4hj ubj)}(hhh]h)}(hhPointer to the function that will clean up the object when the last reference to the object is released.h]hhPointer to the function that will clean up the object when the last reference to the object is released.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK3hj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hK4hjV ubeh}(h]h ]h"]h$]h&]uh1jhj: ubh)}(h**Description**h]j)}(hj h]h Description}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK6hj: ubh)}(huDecrement the refcount, and if 0, call **release**. The caller may not pass NULL or kfree() as the release function.h](h'Decrement the refcount, and if 0, call }(hj hhhNhNubj)}(h **release**h]hrelease}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhC. The caller may not pass NULL or kfree() as the release function.}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK6hj: ubh)}(h **Return**h]j)}(hj h]hReturn}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK9hj: ubh)}(hX1 if this call removed the object, otherwise return 0. Beware, if this function returns 0, another caller may have removed the object by the time this function returns. The return value is only certain if you want to see if the object is definitely released.h]hX1 if this call removed the object, otherwise return 0. Beware, if this function returns 0, another caller may have removed the object by the time this function returns. The return value is only certain if you want to see if the object is definitely released.}(hj# hhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK9hj: ubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubjk)}(hhh]h}(h]h ]h"]h$]h&]entries](jwkref_put_mutex (C function)c.kref_put_mutexhNtauh1jjhjYhhhNhNubj|)}(hhh](j)}(h_int kref_put_mutex (struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex)h]j)}(h^int kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex)h](j)}(hinth]hint}(hjR hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjN hhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKQubj)}(h h]h }(hja hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjN hhhj` hKQubj)}(hkref_put_mutexh]j)}(hkref_put_mutexh]hkref_put_mutex}(hjs hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjo ubah}(h]h ](jjeh"]h$]h&]jjuh1jhjN hhhj` hKQubj)}(hL(struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex)h](j)}(hstruct kref *krefh](j)}(hjh]hstruct}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubh)}(hhh]j)}(hkrefh]hkref}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]j )}jju sbc.kref_put_mutexasbuh1hhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hj7h]h*}(hj hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj)}(hkrefh]hkref}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubj)}(h"void (*release)(struct kref *kref)h](j)}(hvoidh]hvoid}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hjOh]h(}(hj hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj4)}(hj7h]h*}(hj* hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj)}(hreleaseh]hrelease}(hj7 hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hjh]h)}(hjE hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj4)}(hjOh]h(}(hjR hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj)}(hjh]hstruct}(hj_ hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(h h]h }(hjl hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubh)}(hhh]j)}(hkrefh]hkref}(hj} hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjz ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]j c.kref_put_mutexasbuh1hhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hj7h]h*}(hj hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj)}(hkrefh]hkref}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hjh]h)}(hj hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubj)}(hstruct mutex *mutexh](j)}(hjh]hstruct}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubh)}(hhh]j)}(hmutexh]hmutex}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj modnameN classnameNjj)}j]j c.kref_put_mutexasbuh1hhj ubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubj4)}(hj7h]h*}(hj& hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hj ubj)}(hmutexh]hmutex}(hj3 hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubeh}(h]h ]h"]h$]h&]jjuh1jhjN hhhj` hKQubeh}(h]h ]h"]h$]h&]jjjeuh1jjfjghjJ hhhj` hKQubah}(h]jE ah ](jkjleh"]h$]h&]jpjq)jrhuh1jhj` hKQhjG hhubjt)}(hhh]h)}(hDecrement refcount for objecth]hDecrement refcount for object}(hj] hhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKHhjZ hhubah}(h]h ]h"]h$]h&]uh1jshjG hhhj` hKQubeh}(h]h ](jfunctioneh"]h$]h&]jjjju jju jjjuh1j{hhhjYhNhNubj)}(hX**Parameters** ``struct kref *kref`` Object ``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. ``struct mutex *mutex`` Mutex which protects the release function. **Description** This variant of kref_lock() calls the **release** function with the **mutex** held. The **release** function will release the mutex.h](h)}(h**Parameters**h]j)}(hj h]h Parameters}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj} ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKLhjy ubj)}(hhh](j)}(h``struct kref *kref`` Object h](j)}(h``struct kref *kref``h]j)}(hj h]hstruct kref *kref}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKIhj ubj)}(hhh]h)}(hObjecth]hObject}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hKIhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hKIhj ubj)}(h``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. h](j)}(h&``void (*release)(struct kref *kref)``h]j)}(hj h]h"void (*release)(struct kref *kref)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKKhj ubj)}(hhh]h)}(hhPointer to the function that will clean up the object when the last reference to the object is released.h]hhPointer to the function that will clean up the object when the last reference to the object is released.}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKJhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj hKKhj ubj)}(hC``struct mutex *mutex`` Mutex which protects the release function. h](j)}(h``struct mutex *mutex``h]j)}(hj h]hstruct mutex *mutex}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKLhj ubj)}(hhh]h)}(h*Mutex which protects the release function.h]h*Mutex which protects the release function.}(hj* hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj& hKLhj' ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhj& hKLhj ubeh}(h]h ]h"]h$]h&]uh1jhjy ubh)}(h**Description**h]j)}(hjL h]h Description}(hjN hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjJ ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKNhjy ubh)}(hThis variant of kref_lock() calls the **release** function with the **mutex** held. The **release** function will release the mutex.h](h&This variant of kref_lock() calls the }(hjb hhhNhNubj)}(h **release**h]hrelease}(hjj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjb ubh function with the }(hjb hhhNhNubj)}(h **mutex**h]hmutex}(hj| hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjb ubh held. The }(hjb hhhNhNubj)}(h **release**h]hrelease}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjb ubh! function will release the mutex.}(hjb hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKNhjy ubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubjk)}(hhh]h}(h]h ]h"]h$]h&]entries](jwkref_put_lock (C function)c.kref_put_lockhNtauh1jjhjYhhhNhNubj|)}(hhh](j)}(h[int kref_put_lock (struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock)h]j)}(hZint kref_put_lock(struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock)h](j)}(hinth]hint}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj hhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKfubj)}(h h]h }(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj hhhj hKfubj)}(h kref_put_lockh]j)}(h kref_put_lockh]h kref_put_lock}(hj hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj ubah}(h]h ](jjeh"]h$]h&]jjuh1jhj hhhj hKfubj)}(hI(struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock)h](j)}(hstruct kref *krefh](j)}(hjh]hstruct}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubh)}(hhh]j)}(hkrefh]hkref}(hj"hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj$modnameN classnameNjj)}j]j )}jj sbc.kref_put_lockasbuh1hhjubj)}(h h]h }(hjBhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubj4)}(hj7h]h*}(hjPhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjubj)}(hkrefh]hkref}(hj]hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubj)}(h"void (*release)(struct kref *kref)h](j)}(hvoidh]hvoid}(hjvhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj4)}(hjOh]h(}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubj)}(hreleaseh]hrelease}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj4)}(hjh]h)}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubj4)}(hjOh]h(}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubj)}(hjh]hstruct}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubh)}(hhh]j)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjmodnameN classnameNjj)}j]j>c.kref_put_lockasbuh1hhjrubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubj)}(hkrefh]hkref}(hj+hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjrubj4)}(hjh]h)}(hj9hhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjrubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubj)}(hspinlock_t *lockh](h)}(hhh]j)}(h spinlock_th]h spinlock_t}(hjThhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjQubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetjVmodnameN classnameNjj)}j]j>c.kref_put_lockasbuh1hhjMubj)}(h h]h }(hjrhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjMubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjMubj)}(hlockh]hlock}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjMubeh}(h]h ]h"]h$]h&]noemphjjuh1jhj ubeh}(h]h ]h"]h$]h&]jjuh1jhj hhhj hKfubeh}(h]h ]h"]h$]h&]jjjeuh1jjfjghj hhhj hKfubah}(h]j ah ](jkjleh"]h$]h&]jpjq)jrhuh1jhj hKfhj hhubjt)}(hhh]h)}(hDecrement refcount for objecth]hDecrement refcount for object}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK]hjhhubah}(h]h ]h"]h$]h&]uh1jshj hhhj hKfubeh}(h]h ](jfunctioneh"]h$]h&]jjjjjjjjjuh1j{hhhjYhNhNubj)}(hX**Parameters** ``struct kref *kref`` Object ``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. ``spinlock_t *lock`` Spinlock which protects the release function. **Description** This variant of kref_lock() calls the **release** function with the **lock** held. The **release** function will release the lock.h](h)}(h**Parameters**h]j)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKahjubj)}(hhh](j)}(h``struct kref *kref`` Object h](j)}(h``struct kref *kref``h]j)}(hjh]hstruct kref *kref}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK^hjubj)}(hhh]h)}(hObjecth]hObject}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hK^hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhj hK^hjubj)}(h``void (*release)(struct kref *kref)`` Pointer to the function that will clean up the object when the last reference to the object is released. h](j)}(h&``void (*release)(struct kref *kref)``h]j)}(hj1h]h"void (*release)(struct kref *kref)}(hj3hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj/ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK`hj+ubj)}(hhh]h)}(hhPointer to the function that will clean up the object when the last reference to the object is released.h]hhPointer to the function that will clean up the object when the last reference to the object is released.}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhK_hjGubah}(h]h ]h"]h$]h&]uh1jhj+ubeh}(h]h ]h"]h$]h&]uh1jhjFhK`hjubj)}(hC``spinlock_t *lock`` Spinlock which protects the release function. h](j)}(h``spinlock_t *lock``h]j)}(hjkh]hspinlock_t *lock}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjiubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKahjeubj)}(hhh]h)}(h-Spinlock which protects the release function.h]h-Spinlock which protects the release function.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhKahjubah}(h]h ]h"]h$]h&]uh1jhjeubeh}(h]h ]h"]h$]h&]uh1jhjhKahjubeh}(h]h ]h"]h$]h&]uh1jhjubh)}(h**Description**h]j)}(hjh]h Description}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKchjubh)}(hThis variant of kref_lock() calls the **release** function with the **lock** held. The **release** function will release the lock.h](h&This variant of kref_lock() calls the }(hjhhhNhNubj)}(h **release**h]hrelease}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh function with the }(hjhhhNhNubj)}(h**lock**h]hlock}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh held. The }(hjhhhNhNubj)}(h **release**h]hrelease}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh function will release the lock.}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKchjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubjk)}(hhh]h}(h]h ]h"]h$]h&]entries](jw!kref_get_unless_zero (C function)c.kref_get_unless_zerohNtauh1jjhjYhhhNhNubj|)}(hhh](j)}(h,int kref_get_unless_zero (struct kref *kref)h]j)}(h+int kref_get_unless_zero(struct kref *kref)h](j)}(hinth]hint}(hj!hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjhhhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKubj)}(h h]h }(hj0hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjhhhj/hKubj)}(hkref_get_unless_zeroh]j)}(hkref_get_unless_zeroh]hkref_get_unless_zero}(hjBhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhj>ubah}(h]h ](jjeh"]h$]h&]jjuh1jhjhhhj/hKubj)}(h(struct kref *kref)h]j)}(hstruct kref *krefh](j)}(hjh]hstruct}(hj^hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjZubj)}(h h]h }(hjkhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjZubh)}(hhh]j)}(hkrefh]hkref}(hj|hhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjyubah}(h]h ]h"]h$]h&] refdomainjreftypej reftargetj~modnameN classnameNjj)}j]j )}jjDsbc.kref_get_unless_zeroasbuh1hhjZubj)}(h h]h }(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhrjZubj4)}(hj7h]h*}(hjhhhNhNubah}(h]h ]j@ah"]h$]h&]uh1j3hjZubj)}(hkrefh]hkref}(hjhhhNhNubah}(h]h ]jah"]h$]h&]uh1jhjZubeh}(h]h ]h"]h$]h&]noemphjjuh1jhjVubah}(h]h ]h"]h$]h&]jjuh1jhjhhhj/hKubeh}(h]h ]h"]h$]h&]jjjeuh1jjfjghjhhhj/hKubah}(h]jah ](jkjleh"]h$]h&]jpjq)jrhuh1jhj/hKhjhhubjt)}(hhh]h)}(h0Increment refcount for object unless it is zero.h]h0Increment refcount for object unless it is zero.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKrhjhhubah}(h]h ]h"]h$]h&]uh1jshjhhhj/hKubeh}(h]h ](jfunctioneh"]h$]h&]jjjjjjjjjuh1j{hhhjYhNhNubj)}(hX**Parameters** ``struct kref *kref`` object. **Description** This function is intended to simplify locking around refcounting for objects that can be looked up from a lookup structure, and which are removed from that lookup structure in the object destructor. Operations on such objects require at least a read lock around lookup + kref_get, and a write lock around kref_put + remove from lookup structure. Furthermore, RCU implementations become extremely tricky. With a lookup followed by a kref_get_unless_zero *with return value check* locking in the kref_put path can be deferred to the actual removal from the lookup structure and RCU lookups become trivial. **Return** non-zero if the increment succeeded. Otherwise return 0.h](h)}(h**Parameters**h]j)}(hjh]h Parameters}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKvhjubj)}(hhh]j)}(h``struct kref *kref`` object. h](j)}(h``struct kref *kref``h]j)}(hj"h]hstruct kref *kref}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKshjubj)}(hhh]h)}(hobject.h]hobject.}(hj;hhhNhNubah}(h]h ]h"]h$]h&]uh1hhj7hKshj8ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhj7hKshjubah}(h]h ]h"]h$]h&]uh1jhjubh)}(h**Description**h]j)}(hj]h]h Description}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj[ubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKuhjubh)}(hX[This function is intended to simplify locking around refcounting for objects that can be looked up from a lookup structure, and which are removed from that lookup structure in the object destructor. Operations on such objects require at least a read lock around lookup + kref_get, and a write lock around kref_put + remove from lookup structure. Furthermore, RCU implementations become extremely tricky. With a lookup followed by a kref_get_unless_zero *with return value check* locking in the kref_put path can be deferred to the actual removal from the lookup structure and RCU lookups become trivial.h](hXThis function is intended to simplify locking around refcounting for objects that can be looked up from a lookup structure, and which are removed from that lookup structure in the object destructor. Operations on such objects require at least a read lock around lookup + kref_get, and a write lock around kref_put + remove from lookup structure. Furthermore, RCU implementations become extremely tricky. With a lookup followed by a kref_get_unless_zero }(hjshhhNhNubhemphasis)}(h*with return value check*h]hwith return value check}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1j{hjsubh} locking in the kref_put path can be deferred to the actual removal from the lookup structure and RCU lookups become trivial.}(hjshhhNhNubeh}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKuhjubh)}(h **Return**h]j)}(hjh]hReturn}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKhjubh)}(h8non-zero if the increment succeeded. Otherwise return 0.h]h8non-zero if the increment succeeded. Otherwise return 0.}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhS/var/lib/git/docbuild/linux/Documentation/core-api/kref:328: ./include/linux/kref.hhKhjubeh}(h]h ] kernelindentah"]h$]h&]uh1jhjYhhhNhNubeh}(h]functions-and-structuresah ]h"]functions and structuresah$]h&]uh1hhhhhhhhMFubeh}(h]1adding-reference-counters-krefs-to-kernel-objectsah ]h"]3adding reference counters (krefs) to kernel objectsah$]h&]uh1hhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(hN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(jjjj jRjOjjjVjSjju nametypes}(jjjRjjVjuh}(jhj jjOjjjUjSjjjYjyjjjjujzjE jJ j j jju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}Rparse_messages]transform_messages] transformerN include_log] decorationNhhub.