€•WLŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ/translations/zh_CN/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/zh_TW/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/it_IT/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/ja_JP/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/ko_KR/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/pt_BR/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/sp_SP/RCU/rcuref”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…””}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³Œ8/var/lib/git/docbuild/linux/Documentation/RCU/rcuref.rst”h´KubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒDReference-count design for elements of lists/arrays protected by RCU”h]”hŒDReference-count design for elements of lists/arrays protected by RCU”…””}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´KubhŒ paragraph”“”)”}”(hXPlease note that the percpu-ref feature is likely your first stop if you need to combine reference counts and RCU. Please see include/linux/percpu-refcount.h for more information. However, in those unusual cases where percpu-ref would consume too much memory, please read on.”h]”hXPlease note that the percpu-ref feature is likely your first stop if you need to combine reference counts and RCU. Please see include/linux/percpu-refcount.h for more information. However, in those unusual cases where percpu-ref would consume too much memory, please read on.”…””}”(hhßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhŒ transition”“”)”}”(hŒH------------------------------------------------------------------------”h]”h}”(h]”h ]”h"]”h$]”h&]”uh1híh³hÇh´KhhÊh²hubhÞ)”}”(hŒ…Reference counting on elements of lists which are protected by traditional reader/writer spinlocks or semaphores are straightforward:”h]”hŒ…Reference counting on elements of lists which are protected by traditional reader/writer spinlocks or semaphores are straightforward:”…””}”(hhùh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒCODE LISTING A::”h]”hŒCODE LISTING A:”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhŒ literal_block”“”)”}”(hXÉ1. 2. add() search_and_reference() { { alloc_object read_lock(&list_lock); ... search_for_element atomic_set(&el->rc, 1); atomic_inc(&el->rc); write_lock(&list_lock); ... add_element read_unlock(&list_lock); ... ... write_unlock(&list_lock); } } 3. 4. release_referenced() delete() { { ... write_lock(&list_lock); if(atomic_dec_and_test(&el->rc)) ... kfree(el); ... remove_element } write_unlock(&list_lock); ... if (atomic_dec_and_test(&el->rc)) kfree(el); ... }”h]”hXÉ1. 2. add() search_and_reference() { { alloc_object read_lock(&list_lock); ... search_for_element atomic_set(&el->rc, 1); atomic_inc(&el->rc); write_lock(&list_lock); ... add_element read_unlock(&list_lock); ... ... write_unlock(&list_lock); } } 3. 4. release_referenced() delete() { { ... write_lock(&list_lock); if(atomic_dec_and_test(&el->rc)) ... kfree(el); ... remove_element } write_unlock(&list_lock); ... if (atomic_dec_and_test(&el->rc)) kfree(el); ... }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jh³hÇh´KhhÊh²hubhÞ)”}”(hX€If this list/array is made lock free using RCU as in changing the write_lock() in add() and delete() to spin_lock() and changing read_lock() in search_and_reference() to rcu_read_lock(), the atomic_inc() in search_and_reference() could potentially hold reference to an element which has already been deleted from the list/array. Use atomic_inc_not_zero() in this scenario as follows:”h]”hX€If this list/array is made lock free using RCU as in changing the write_lock() in add() and delete() to spin_lock() and changing read_lock() in search_and_reference() to rcu_read_lock(), the atomic_inc() in search_and_reference() could potentially hold reference to an element which has already been deleted from the list/array. Use atomic_inc_not_zero() in this scenario as follows:”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K/hhÊh²hubhÞ)”}”(hŒCODE LISTING B::”h]”hŒCODE LISTING B:”…””}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K6hhÊh²hubj)”}”(hXF1. 2. add() search_and_reference() { { alloc_object rcu_read_lock(); ... search_for_element atomic_set(&el->rc, 1); if (!atomic_inc_not_zero(&el->rc)) { spin_lock(&list_lock); rcu_read_unlock(); return FAIL; add_element } ... ... spin_unlock(&list_lock); rcu_read_unlock(); } } 3. 4. release_referenced() delete() { { ... spin_lock(&list_lock); if (atomic_dec_and_test(&el->rc)) ... call_rcu(&el->head, el_free); remove_element ... spin_unlock(&list_lock); } ... if (atomic_dec_and_test(&el->rc)) call_rcu(&el->head, el_free); ... }”h]”hXF1. 2. add() search_and_reference() { { alloc_object rcu_read_lock(); ... search_for_element atomic_set(&el->rc, 1); if (!atomic_inc_not_zero(&el->rc)) { spin_lock(&list_lock); rcu_read_unlock(); return FAIL; add_element } ... ... spin_unlock(&list_lock); rcu_read_unlock(); } } 3. 4. release_referenced() delete() { { ... spin_lock(&list_lock); if (atomic_dec_and_test(&el->rc)) ... call_rcu(&el->head, el_free); remove_element ... spin_unlock(&list_lock); } ... if (atomic_dec_and_test(&el->rc)) call_rcu(&el->head, el_free); ... }”…””}”hjAsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jh³hÇh´K8hhÊh²hubhÞ)”}”(hŒìSometimes, a reference to the element needs to be obtained in the update (write) stream. In such cases, atomic_inc_not_zero() might be overkill, since we hold the update-side spinlock. One might instead use atomic_inc() in such cases.”h]”hŒìSometimes, a reference to the element needs to be obtained in the update (write) stream. In such cases, atomic_inc_not_zero() might be overkill, since we hold the update-side spinlock. One might instead use atomic_inc() in such cases.”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KQhhÊh²hubhÞ)”}”(hŒ¶It is not always convenient to deal with "FAIL" in the search_and_reference() code path. In such cases, the atomic_dec_and_test() may be moved from delete() to el_free() as follows:”h]”hŒºIt is not always convenient to deal with “FAIL†in the search_and_reference() code path. In such cases, the atomic_dec_and_test() may be moved from delete() to el_free() as follows:”…””}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KVhhÊh²hubhÞ)”}”(hŒCODE LISTING C::”h]”hŒCODE LISTING C:”…””}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K[hhÊh²hubj)”}”(hXx1. 2. add() search_and_reference() { { alloc_object rcu_read_lock(); ... search_for_element atomic_set(&el->rc, 1); atomic_inc(&el->rc); spin_lock(&list_lock); ... add_element rcu_read_unlock(); ... } spin_unlock(&list_lock); 4. } delete() 3. { release_referenced() spin_lock(&list_lock); { ... ... remove_element if (atomic_dec_and_test(&el->rc)) spin_unlock(&list_lock); kfree(el); ... ... call_rcu(&el->head, el_free); } ... 5. } void el_free(struct rcu_head *rhp) { release_referenced(); }”h]”hXx1. 2. add() search_and_reference() { { alloc_object rcu_read_lock(); ... search_for_element atomic_set(&el->rc, 1); atomic_inc(&el->rc); spin_lock(&list_lock); ... add_element rcu_read_unlock(); ... } spin_unlock(&list_lock); 4. } delete() 3. { release_referenced() spin_lock(&list_lock); { ... ... remove_element if (atomic_dec_and_test(&el->rc)) spin_unlock(&list_lock); kfree(el); ... ... call_rcu(&el->head, el_free); } ... 5. } void el_free(struct rcu_head *rhp) { release_referenced(); }”…””}”hjysbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jh³hÇh´K]hhÊh²hubhÞ)”}”(hX0The key point is that the initial reference added by add() is not removed until after a grace period has elapsed following removal. This means that search_and_reference() cannot find this element, which means that the value of el->rc cannot increase. Thus, once it reaches zero, there are no readers that can or ever will be able to reference the element. The element can therefore safely be freed. This in turn guarantees that if any reader finds the element, that reader may safely acquire a reference without checking the value of the reference counter.”h]”hX0The key point is that the initial reference added by add() is not removed until after a grace period has elapsed following removal. This means that search_and_reference() cannot find this element, which means that the value of el->rc cannot increase. Thus, once it reaches zero, there are no readers that can or ever will be able to reference the element. The element can therefore safely be freed. This in turn guarantees that if any reader finds the element, that reader may safely acquire a reference without checking the value of the reference counter.”…””}”(hj‡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KwhhÊh²hubhÞ)”}”(hX¤A clear advantage of the RCU-based pattern in listing C over the one in listing B is that any call to search_and_reference() that locates a given object will succeed in obtaining a reference to that object, even given a concurrent invocation of delete() for that same object. Similarly, a clear advantage of both listings B and C over listing A is that a call to delete() is not delayed even if there are an arbitrarily large number of calls to search_and_reference() searching for the same object that delete() was invoked on. Instead, all that is delayed is the eventual invocation of kfree(), which is usually not a problem on modern computer systems, even the small ones.”h]”hX¤A clear advantage of the RCU-based pattern in listing C over the one in listing B is that any call to search_and_reference() that locates a given object will succeed in obtaining a reference to that object, even given a concurrent invocation of delete() for that same object. Similarly, a clear advantage of both listings B and C over listing A is that a call to delete() is not delayed even if there are an arbitrarily large number of calls to search_and_reference() searching for the same object that delete() was invoked on. Instead, all that is delayed is the eventual invocation of kfree(), which is usually not a problem on modern computer systems, even the small ones.”…””}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K€hhÊh²hubhÞ)”}”(hŒŒIn cases where delete() can sleep, synchronize_rcu() can be called from delete(), so that el_free() can be subsumed into delete as follows::”h]”hŒ‹In cases where delete() can sleep, synchronize_rcu() can be called from delete(), so that el_free() can be subsumed into delete as follows:”…””}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K‹hhÊh²hubj)”}”(hŒÂ4. delete() { spin_lock(&list_lock); ... remove_element spin_unlock(&list_lock); ... synchronize_rcu(); if (atomic_dec_and_test(&el->rc)) kfree(el); ... }”h]”hŒÂ4. delete() { spin_lock(&list_lock); ... remove_element spin_unlock(&list_lock); ... synchronize_rcu(); if (atomic_dec_and_test(&el->rc)) kfree(el); ... }”…””}”hj±sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jh³hÇh´KŽhhÊh²hubhÞ)”}”(hŒ§As additional examples in the kernel, the pattern in listing C is used by reference counting of struct pid, while the pattern in listing B is used by struct posix_acl.”h]”hŒ§As additional examples in the kernel, the pattern in listing C is used by reference counting of struct pid, while the pattern in listing B is used by struct posix_acl.”…””}”(hj¿h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KœhhÊh²hubeh}”(h]”ŒDreference-count-design-for-elements-of-lists-arrays-protected-by-rcu”ah ]”h"]”ŒDreference-count design for elements of lists/arrays protected by rcu”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Œfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œ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”‰Œ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”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”jÒjÏsŒ nametypes”}”jÒ‰sh}”jÏhÊsŒ 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.