€•¡Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”(hhŒparent”hubaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ!/translations/zh_CN/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”(hhhh2ubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ!/translations/zh_TW/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”(hhhhFubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ!/translations/it_IT/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”(hhhhZubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ!/translations/ja_JP/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”(hhhhnubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ!/translations/ko_KR/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”(hhhh‚ubah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ!/translations/sp_SP/core-api/kref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒ3Adding reference counters (krefs) to kernel objects”h]”hŒ3Adding reference counters (krefs) to kernel objects”…””}”(hhªhh¨hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hh£hžhhŸŒ;/var/lib/git/docbuild/linux/Documentation/core-api/kref.rst”h KubhŒ field_list”“”)”}”(hhh]”(hŒfield”“”)”}”(hhh]”(hŒ field_name”“”)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hhÅhhÃhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhh¾hŸh¶h KubhŒ field_body”“”)”}”(hŒCorey Minyard ”h]”hŒ paragraph”“”)”}”(hhÕh]”(hŒCorey Minyard <”…””}”(hŒCorey Minyard <”hhÙhžhhŸNh NubhŒ reference”“”)”}”(hŒminyard@acm.org”h]”hŒminyard@acm.org”…””}”(hhhhãhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œmailto:minyard@acm.org”uh1háhhÙubhŒ>”…””}”(hŒ>”hhÙhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KhhÓubah}”(h]”h ]”h"]”h$]”h&]”uh1hÑhh¾ubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hŸh¶h Khh¹hžhubh½)”}”(hhh]”(hÂ)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hjhj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj hŸh¶h KubhÒ)”}”(hŒ)Thomas Hellstrom ”h]”hØ)”}”(hŒ(Thomas Hellstrom ”h]”(hŒThomas Hellstrom <”…””}”(hŒThomas Hellstrom <”hjhžhhŸNh Nubhâ)”}”(hŒthellstrom@vmware.com”h]”hŒthellstrom@vmware.com”…””}”(hhhj(hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œmailto:thellstrom@vmware.com”uh1háhjubhŒ>”…””}”(hh÷hjhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1hÑhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hŸh¶h Khh¹hžhubeh}”(h]”h ]”h"]”h$]”h&]”uh1h·hh£hžhhŸh¶h KubhØ)”}”(hŒsA lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and presentation on krefs, which can be found at:”h]”hŒuA lot of this was lifted from Greg Kroah-Hartman’s 2004 OLS paper and presentation on krefs, which can be found at:”…””}”(hjVhjThžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Khh£hžhubhŒ block_quote”“”)”}”(hhh]”hŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒVhttp://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf”h]”hØ)”}”(hjph]”hâ)”}”(hjph]”hŒVhttp://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf”…””}”(hhhjuhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”jpuh1háhjrubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K hjnubah}”(h]”h ]”h"]”h$]”h&]”uh1jlhjiubjm)”}”(hŒ5http://www.kroah.com/linux/talks/ols_2004_kref_talk/ ”h]”hØ)”}”(hŒ4http://www.kroah.com/linux/talks/ols_2004_kref_talk/”h]”hâ)”}”(hj•h]”hŒ4http://www.kroah.com/linux/talks/ols_2004_kref_talk/”…””}”(hhhj—hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”j•uh1háhj“ubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jlhjiubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1jghŸh¶h K hjdubah}”(h]”h ]”h"]”h$]”h&]”uh1jbhh£hžhhŸNh Nubh¢)”}”(hhh]”(h§)”}”(hŒ Introduction”h]”hŒ Introduction”…””}”(hjÄhjÂhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj¿hžhhŸh¶h KubhØ)”}”(hŒøkrefs 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]”hŒúkrefs 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.”…””}”(hjÒhjÐhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Khj¿hžhubhØ)”}”(hŒ5To use a kref, add one to your data structures like::”h]”hŒ4To use a kref, add one to your data structures like:”…””}”(hŒ4To use a kref, add one to your data structures like:”hjÞhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Khj¿hžhubhŒ literal_block”“”)”}”(hŒEstruct my_data { . . struct kref refcount; . . };”h]”hŒEstruct my_data { . . struct kref refcount; . . };”…””}”(hhhjïubah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1jíhŸh¶h Khj¿hžhubhØ)”}”(hŒ6The kref can occur anywhere within the data structure.”h]”hŒ6The kref can occur anywhere within the data structure.”…””}”(hjhjÿhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K!hj¿hžhubeh}”(h]”Œ introduction”ah ]”h"]”Œ introduction”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Kubh¢)”}”(hhh]”(h§)”}”(hŒInitialization”h]”hŒInitialization”…””}”(hjhjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjhžhhŸh¶h K$ubhØ)”}”(hŒWYou must initialize the kref after you allocate it. To do this, call kref_init as so::”h]”hŒVYou must initialize the kref after you allocate it. To do this, call kref_init as so:”…””}”(hŒVYou must initialize the kref after you allocate it. To do this, call kref_init as so:”hj&hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K&hjhžhubjî)”}”(hŒstruct my_data *data; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount);”h]”hŒstruct my_data *data; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; kref_init(&data->refcount);”…””}”(hhhj5ubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h K)hjhžhubhØ)”}”(hŒ(This sets the refcount in the kref to 1.”h]”hŒ(This sets the refcount in the kref to 1.”…””}”(hjEhjChžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K0hjhžhubeh}”(h]”Œinitialization”ah ]”h"]”Œinitialization”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K$ubh¢)”}”(hhh]”(h§)”}”(hŒ Kref rules”h]”hŒ Kref rules”…””}”(hj^hj\hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjYhžhhŸh¶h K3ubhØ)”}”(hŒGOnce you have an initialized kref, you must follow the following rules:”h]”hŒGOnce you have an initialized kref, you must follow the following rules:”…””}”(hjlhjjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K5hjYhžhubhŒenumerated_list”“”)”}”(hhh]”(jm)”}”(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Ø)”}”(hŒµIf 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]”hŒ´If 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Œ´If 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:”hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K8hj}ubjî)”}”(hŒkref_get(&data->refcount);”h]”hŒkref_get(&data->refcount);”…””}”(hhhjubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h Khj}ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jlhjzhžhhŸh¶h Nubjm)”}”(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Ø)”}”(hŒrefcount, data_release);”h]”hŒ(kref_put(&data->refcount, data_release);”…””}”(hhhjÅubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KChj²ubhØ)”}”(hŒç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Œç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.”…””}”(hjÕhjÓhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KEhj²ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jlhjzhžhhŸh¶h Nubjm)”}”(hŒôIf 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Ø)”}”(hŒóIf 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ŒóIf 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().”…””}”(hjíhjëhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KKhjçubah}”(h]”h ]”h"]”h$]”h&]”uh1jlhjzhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ)”uh1jxhjYhžhhŸh¶h K8ubhØ)”}”(hŒVFor example, if you allocate some data and then pass it to another thread to process::”h]”hŒUFor example, if you allocate some data and then pass it to another thread to process:”…””}”(hŒUFor example, if you allocate some data and then pass it to another thread to process:”hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KPhjYhžhubjî)”}”(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; }”…””}”(hhhjubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KShjYhžhubhØ)”}”(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)hj'hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K|hjYhžhubhØ)”}”(hŒ½In 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]”hŒ½In 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().”…””}”(hj7hj5hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KƒhjYhžhubhØ)”}”(hŒYNote 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:”…””}”(hŒXNote that the "before" in rule 1 is very important. You should never do something like:”hjChžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K‡hjYhžhubjî)”}”(hŒêtask = 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]”hŒêtask = 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);”…””}”(hhhjRubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KŠhjYhžhubhØ)”}”(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.”…””}”(hjbhj`hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K’hjYhžhubhØ)”}”(hŒåThere 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]”hŒäThere 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ŒäThere 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:”hjnhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K™hjYhžhubjî)”}”(hŒb/* Silly extra get and put */ kref_get(&obj->ref); enqueue(obj); kref_put(&obj->ref, obj_cleanup);”h]”hŒb/* Silly extra get and put */ kref_get(&obj->ref); enqueue(obj); kref_put(&obj->ref, obj_cleanup);”…””}”(hhhj}ubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KžhjYhžhubhØ)”}”(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:”…””}”(hŒ=Just do the enqueue. A comment about this is always welcome:”hj‹hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K£hjYhžhubjî)”}”(hŒsenqueue(obj); /* We are done with obj, so we pass our refcount off to the queue. DON'T TOUCH obj AFTER HERE! */”h]”hŒsenqueue(obj); /* We are done with obj, so we pass our refcount off to the queue. DON'T TOUCH obj AFTER HERE! */”…””}”(hhhjšubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h K¥hjYhžhubhØ)”}”(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:”…””}”(hXeThe 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:”hj¨hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K©hjYhžhubjî)”}”(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); }”…””}”(hhhj·ubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h K°hjYhžhubhØ)”}”(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:”…””}”(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:”hjÅhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÓhjYhžhubjî)”}”(hX˜static 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]”hX˜static 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); }”…””}”(hhhjÔubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KØhjYhžhubhØ)”}”(hŒöThis 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]”hŒöThis 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.”…””}”(hjähjâhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KèhjYhžhubhØ)”}”(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:”…””}”(hŒ\The above example could also be optimized using kref_get_unless_zero() in the following way:”hjðhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KíhjYhžhubjî)”}”(hXÀ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); 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]”hXÀ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); 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); }”…””}”(hhhjÿubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h KðhjYhžhubhØ)”}”(hXãWhich 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]”hXåWhich 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.”…””}”(hjhj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M hjYhžhubeh}”(h]”Œ kref-rules”ah ]”h"]”Œ kref rules”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K3ubh¢)”}”(hhh]”(h§)”}”(hŒ Krefs and RCU”h]”hŒ Krefs and RCU”…””}”(hj(hj&hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj#hžhhŸh¶h MubhØ)”}”(hŒnThe function kref_get_unless_zero also makes it possible to use rcu locking for lookups in the above example::”h]”hŒmThe function kref_get_unless_zero also makes it possible to use rcu locking for lookups in the above example:”…””}”(hŒmThe function kref_get_unless_zero also makes it possible to use rcu locking for lookups in the above example:”hj4hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Mhj#hžhubjî)”}”(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); }”…””}”(hhhjCubah}”(h]”h ]”h"]”h$]”h&]”jýjþuh1jíhŸh¶h Mhj#hžhubhØ)”}”(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.”…””}”(hjShjQhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M?hj#hžhubeh}”(h]”Œ krefs-and-rcu”ah ]”h"]”Œ krefs and rcu”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Mubeh}”(h]”Œ1adding-reference-counters-krefs-to-kernel-objects”ah ]”h"]”Œ3adding reference counters (krefs) to kernel objects”ah$]”h&]”uh1h¡hhhžhhŸh¶h Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”h¶uh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(h¦NŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j’Œerror_encoding”ŒUTF-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”h¶Œ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œ embed_images”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jljijjjVjSj jjdjauŒ nametypes”}”(jlNjNjVNj NjdNuh}”(jih£jj¿jSjjjYjaj#uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nhžhub.