.. SPDX-License-Identifier: GPL-2.0+ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/xarray.rst :翻译: 司延腾 Yanteng Si <siyanteng@loongson.cn> 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn> :ć ˇčŻ‘: .. _cn_core-api_xarray: ====== XArray ====== :作者: Matthew Wilcox ć¦‚č§ ==== XArrayćŻä¸€ä¸ŞćŠ˝č±ˇçš„ć•°ćŤ®ç±»ĺž‹ďĽŚĺ®çš„行为就ĺŹä¸€ä¸Şéťžĺ¸¸ĺ¤§çš„指é’数组。ĺ®ć»ˇč¶łäş†č®¸ĺ¤šä¸Žĺ“ 希ć–äĽ ç»źĺŹŻč°ć•´ĺ¤§ĺ°Źçš„数组相ĺŚçš„需求。与ĺ“希不ĺŚçš„ćŻďĽŚĺ®ĺ…č®¸ä˝ ä»Ąä¸€ç§Ťé«ć•的缓ĺć–ą 式ĺç†ĺś°č˝¬ĺ°ä¸‹ä¸€ä¸Şć–上一个条目。与可č°ć•´ĺ¤§ĺ°Źçš„数组相比,不需č¦ĺ¤Ťĺ¶ć•°ćŤ®ć–改ĺŹMMU çš„ć ĺ°„ćťĄĺ˘žĺŠ ć•°ç»„ă€‚ä¸ŽĺŹŚé“ľčˇ¨ç›¸ćŻ”ďĽŚĺ®çš„内ĺć•率更é«ďĽŚĺŹŻĺą¶čˇŚďĽŚĺŻąçĽ“ĺ更友好。ĺ®ĺ©ç”¨ RCUçš„äĽĺŠżćťĄć‰§čˇŚćźĄć‰ľč€Śä¸Ťéś€č¦é”定。 当使用的索引ćŻĺ݆集čšé›†çš„时候,XArray的实现ćŻćś‰ć•的;而ĺ“希对象并使用ĺ“希作为索引 将不会有好的表现。XArray对小的索引进行了äĽĺŚ–ďĽŚä¸Ťčż‡ĺŻąĺ¤§çš„ç´˘ĺĽ•ä»Ťćś‰č‰ŻĺĄ˝çš„ć€§č˝ă€‚如果 ä˝ çš„ç´˘ĺĽ•ĺŹŻä»Ąĺ¤§äşŽ ``ULONG_MAX`` ,那äąXArray就不适ĺä˝ çš„ć•°ćŤ®ç±»ĺž‹ă€‚XArrayćś€é‡Ťč¦ çš„ç”¨ć·ćŻéˇµéť˘é«é€źçĽ“ĺ。 普通指é’可以直接ĺ储在XArrayä¸ă€‚ĺ®ä»¬ĺż…须ćŻ4ĺ—节对é˝çš„,这对任何从kmalloc()ĺ’Ś alloc_page()返回的指é’来说é˝ćŻĺ¦‚ć¤ă€‚这对任意的用ć·ç©şé—´ćڇé’和函数指é’来说é˝ä¸ŤćŻ çśźçš„ă€‚ä˝ ĺŹŻä»Ąĺ储指ĺ‘éť™ć€ĺ†é…ŤĺŻąč±ˇçš„ćŚ‡é’,只č¦čż™äş›ĺŻąč±ˇçš„ĺŻąé˝ć–ąĺĽŹč‡łĺ°‘ćŻ4ďĽĺ—节)。 ä˝ äąźĺŹŻä»Ąĺś¨XArrayä¸ĺ储0ĺ° ``LONG_MAX`` äą‹é—´çš„ć•´ć•°ă€‚ä˝ ĺż…éˇ»é¦–ĺ…使用xa_mk_value() ĺ°†ĺ…¶č˝¬ćŤ˘ä¸şä¸€ä¸Şćťˇç›®ă€‚ĺ˝“ä˝ ä»ŽXArrayä¸ćŁ€ç´˘ä¸€ä¸Şćťˇç›®ć—¶ďĽŚä˝ ĺŹŻä»Ąé€ščż‡č°ç”¨xa_is_value()检 查ĺ®ćŻĺ¦ćŻä¸€ä¸Şĺ€Ľćťˇç›®ďĽŚĺą¶é€ščż‡č°ç”¨xa_to_value()ĺ°†ĺ®č˝¬ćŤ˘ĺ›žä¸€ä¸Şć•´ć•°ă€‚ 一些用ć·ĺ¸Śćś›ĺŻąä»–ä»¬ĺ储在XArrayä¸çš„指é’čż›čˇŚć ‡č®°ă€‚ä˝ ĺŹŻä»Ąč°ç”¨xa_tag_pointer()来ĺ›ĺ»ş ä¸€ä¸Şĺ¸¦ćś‰ć ‡çľçš„条目,xa_untag_pointer()ĺ°†ä¸€ä¸Şćś‰ć ‡çľçš„ćťˇç›®č˝¬ĺ›žä¸€ä¸Şć— ć ‡çľçš„指é’, xa_pointer_tag()ćťĄćŁ€ç´˘ä¸€ä¸Şćťˇç›®çš„ć ‡çľă€‚ć ‡çľćڇé’使用相ĺŚçš„位,用于区ĺ†ĺ€Ľćťˇç›®ĺ’Ść™®é€š 指é’ďĽŚć‰€ä»Ąä˝ ĺż…éˇ»ĺ†łĺ®šä»–ä»¬ćŻĺ¦č¦ĺś¨ä»»ä˝•特定的XArrayä¸ĺ储值条目ć–ć ‡çľćڇé’。 XArray不支ćŚĺ储IS_ERR()指é’ďĽŚĺ› ä¸şćś‰äş›ćŚ‡é’与值条目ć–内é¨ćťˇç›®ĺ†˛çŞă€‚ XArray的一个不寻常的特点ćŻč˝ĺ¤źĺ›ĺ»şĺŤ 据一系ĺ—索引的条目。一旦ĺ储ĺ°ĺ…¶ä¸ďĽŚćźĄčŻ˘čŻĄčŚĺ›´ 内的任何索引将返回与查询该čŚĺ›´ĺ†…任何其他索引相ĺŚçš„条目。ĺ储ĺ°ä»»ä˝•索引é˝äĽšĺ储所有 的索引条目。多索引条目可以ćŽçˇ®ĺś°ĺ†ĺ‰˛ć更小的条目,ć–者将其ĺ储 ``NULL`` ĺ°ä»»ä˝•ćťˇç›®ä¸ é˝äĽšä˝żXArrayĺżč®°čŚĺ›´ă€‚ 普通API ======= 首ĺ…ĺťĺ§‹ĺŚ–ä¸€ä¸ŞXArray,对于静ć€ĺ†é…Ťçš„XArray可以用DEFINE_XARRAY(),对于动ć€ĺ†é…Ťçš„ XArray可以用xa_init()。一个新ĺťĺ§‹ĺŚ–çš„XArray在每个索引处é˝ĺŚ…ĺ«ä¸€ä¸Ş ``NULL`` 指é’。 ç„¶ĺŽä˝ 可以用xa_store()来设置条目,用xa_load()来获取条目。xa_store将用新的条目覆盖任 何条目,并返回ĺĺ‚¨ĺś¨čŻĄç´˘ĺĽ•çš„ä¸Šä¸€ä¸Şćťˇç›®ă€‚ä˝ ĺŹŻä»Ąä˝żç”¨xa_erase()来代替č°ç”¨xa_store()çš„ ``NULL`` 条目。一个从未被ĺ储过的条目ă€ä¸€ä¸Şč˘«ć“¦é™¤çš„条目和一个最近被ĺ储过 ``NULL`` çš„ 条目之间没有区ĺ«ă€‚ ä˝ ĺŹŻä»Ąé€ščż‡ä˝żç”¨xa_cmpxchg()有条件地替换一个索引ä¸çš„条目。和cmpxchg()ä¸€ć ·ďĽŚĺ®ĺŹŞćś‰ĺś¨čŻĄç´˘ 引的条目有 â€ć—§â€ 值时才会ć功。ĺ®äąźäĽščż”回该索引上的条目;如果ĺ®čż”ĺ›žä¸ŽäĽ é€’çš„ â€ć—§â€ 相ĺŚçš„条 目,那äąxa_cmpxchg()ĺ°±ć功了。 ĺ¦‚ćžśä˝ ĺŹŞćłĺś¨ćźä¸Şç´˘ĺĽ•的当前条目为 ``NULL`` 时将一个新条目ĺ储ĺ°čŻĄç´˘ĺĽ•ďĽŚä˝ ĺŹŻä»Ąä˝żç”¨xa_insert(), 如果该条目不ćŻç©şçš„,ĺ™čż”回 ``-EBUSY`` 。 ä˝ ĺŹŻä»Ąé€ščż‡č°ç”¨xa_extract()将条目从XArrayä¸ĺ¤Ťĺ¶ĺ°ä¸€ä¸Şć™®é€šć•°ç»„ä¸ă€‚ć–č€…ä˝ ĺŹŻä»Ąé€ščż‡č°ç”¨ xa_for_each()ă€xa_for_each_start()ć–xa_for_each_range()来éŤĺކXArrayä¸çš„çŽ°ćś‰ćťˇç›®ă€‚ä˝ ĺŹŻč˝ć›´ĺ–ść¬˘ä˝żç”¨xa_find()ć–xa_find_after()来移动ĺ°XArrayä¸çš„下一个当前条目。 č°ç”¨xa_store_range()可以在一个索引čŚĺ›´ĺ†…ĺ储ĺŚä¸€ä¸Şćťˇç›®ă€‚ĺ¦‚ćžśä˝ čż™ć ·ĺšďĽŚĺ…¶ä»–的一些操作将以 ä¸€ç§Ťç¨Ťĺľ®ĺĄ‡ć€Şçš„ć–ąĺĽŹčż›čˇŚă€‚äľ‹ĺ¦‚ďĽŚĺś¨ä¸€ä¸Şç´˘ĺĽ•ä¸Šć ‡č®°ćťˇç›®ĺŹŻč˝äĽšĺŻĽč‡´čŻĄćťˇç›®ĺś¨ä¸€äş›ďĽŚä˝†ä¸ŤćŻć‰€ćś‰ĺ…¶ä»–ç´˘ ĺĽ•ä¸Šč˘«ć ‡č®°ă€‚ĺ‚¨ĺĺ°ä¸€ä¸Şç´˘ĺĽ•ä¸ĺŹŻč˝äĽšĺŻĽč‡´ç”±ä¸€äş›ďĽŚä˝†ä¸ŤćŻć‰€ćś‰ĺ…¶ä»–索引检索的条目发生ĺŹĺŚ–ă€‚ ćś‰ć—¶ä˝ éś€č¦çˇ®äżťĺŻąxa_store()çš„ĺŽç»č°ç”¨ĺ°†ä¸Ťéś€č¦ĺ†é…Ťĺ†…ĺ。xa_reserve()函数将在指定索引处ĺ储 一个保留条目。普通API的用ć·ĺ°†çś‹ĺ°čż™ä¸Şćťˇç›®ĺŚ…ĺ« ``NULL`` ă€‚ĺ¦‚ćžśä˝ ä¸Ťéś€č¦ä˝żç”¨äżťç•™çš„ćťˇç›®ďĽŚä˝ ĺŹŻ 以č°ç”¨xa_release()来ĺ 除这个未使用的条目。如果在ć¤ćśźé—´ćś‰ĺ…¶ä»–用ć·ĺ储ĺ°čŻĄćťˇç›®ďĽŚxa_release() 将不ĺšä»»ä˝•äş‹ć…ďĽ›ç›¸ĺŹŤďĽŚĺ¦‚ćžśä˝ ćłč®©čŻĄćťˇç›®ĺŹć ``NULL`` ďĽŚä˝ ĺş”čŻĄä˝żç”¨xa_erase()。在一个保留的条 目上使用xa_insert()将会失败。 如果数组ä¸çš„所有条目é˝ćŻ ``NULL`` ,xa_empty()函数将返回 ``true`` 。 最ĺŽďĽŚä˝ 可以通过č°ç”¨xa_destroy()ĺ 除XArrayä¸çš„所有条目。如果XArray的条目ćŻćڇé’ďĽŚä˝ ĺŹŻč˝ĺ¸Śćś› ĺ…é‡Šć”ľčż™äş›ćťˇç›®ă€‚ä˝ ĺŹŻä»Ąé€ščż‡ä˝żç”¨xa_for_each()čżä»Łĺ™¨éŤĺކXArrayä¸ć‰€ćś‰ĺ在的条目来实现这一目的。 ćśç´˘ć ‡č®° -------- 数组ä¸çš„每个条目é˝ćś‰ä¸‰ä¸Şä¸Žäą‹ç›¸ĺ…łçš„ä˝ŤďĽŚç§°ä¸şć ‡č®°ă€‚ćŻŹä¸Şć ‡č®°ĺŹŻä»Ąç‹¬ç«‹äşŽĺ…¶ä»–ć ‡č®°č˘«č®ľç˝®ć–ć¸…é™¤ă€‚ä˝ ĺŹŻä»Ą 通过使用xa_for_each_marked()čżä»Łĺ™¨ćťĄčżä»Łćś‰ć ‡č®°çš„条目。 ä˝ ĺŹŻä»Ąé€ščż‡ä˝żç”¨xa_get_mark()来查询ćźä¸Şćťˇç›®ćŻĺ¦č®ľç˝®äş†ć ‡č®°ă€‚ĺ¦‚ćžśčŻĄćťˇç›®ä¸ŤćŻ ``NULL`` ďĽŚä˝ ĺŹŻä»Ąé€ščż‡ 使用xa_set_mark()ćťĄč®ľç˝®ä¸€ä¸Şć ‡č®°ďĽŚĺą¶é€ščż‡č°ç”¨xa_clear_mark()来ĺ é™¤ćťˇç›®ä¸Šçš„ć ‡č®°ă€‚ä˝ ĺŹŻä»Ąé€ščż‡č°ç”¨ xa_marked()来询问XArrayä¸çš„任何条目ćŻĺ¦ćś‰ä¸€ä¸Şç‰ąĺ®šçš„ć ‡č®°č˘«č®ľç˝®ă€‚ä»ŽXArrayä¸ĺ 除一个条目会导致与 čŻĄćťˇç›®ç›¸ĺ…łçš„ć‰€ćś‰ć ‡č®°č˘«ć¸…é™¤ă€‚ 在一个多索引条目的任何索引上设置ć–ć¸…é™¤ć ‡č®°ĺ°†ĺ˝±ĺ“ŤčŻĄćťˇç›®ć‰€ć¶µç›–çš„ć‰€ćś‰ç´˘ĺĽ•ă€‚ćźĄčŻ˘ä»»ä˝•ç´˘ĺĽ•ä¸Šçš„ć ‡č®°ĺ°†čż” 回相ĺŚçš„结果。 ć˛ˇćś‰ĺŠžćł•ĺŻąć˛ˇćś‰ć ‡č®°çš„ćťˇç›®čż›čˇŚčżä»ŁďĽ›ć•°ćŤ®ç»“构不ĺ…许有ć•地实现这一点。目前没有čżä»Łĺ™¨ćťĄćśç´˘ćŻ”ç‰ąçš„é€»čľ‘ 组ĺďĽäľ‹ĺ¦‚čżä»Łć‰€ćś‰ĺŚć—¶č®ľç˝®äş† ``XA_MARK_1`` ĺ’Ś ``XA_MARK_2`` 的条目,ć–者čżä»Łć‰€ćś‰č®ľç˝®äş† ``XA_MARK_0`` ć– ``XA_MARK_2`` 的条目)。如果有用ć·éś€č¦ďĽŚĺŹŻä»Ąĺ˘žĺŠ čż™äş›ĺ†…ĺ®ąă€‚ ĺ†é…ŤXArrays ----------- ĺ¦‚ćžśä˝ ä˝żç”¨DEFINE_XARRAY_ALLOC()来定义XArray,ć–者通过ĺ‘xa_init_flags()äĽ é€’ ``XA_FLAGS_ALLOC`` 来ĺťĺ§‹ĺŚ–ĺ®ďĽŚXArray会改ĺŹä»Ąč·źč¸Şćťˇç›®ćŻĺ¦č˘«ä˝żç”¨ă€‚ ä˝ ĺŹŻä»Ąč°ç”¨xa_alloc()将条目ĺ储在XArrayä¸ä¸€ä¸ŞćśŞä˝żç”¨çš„ç´˘ĺĽ•ä¸Šă€‚ĺ¦‚ćžśä˝ éś€č¦ä»Žä¸ć–上下文ä¸äż®ć”ąć•°ç»„ďĽŚä˝ ĺŹŻä»Ąä˝żç”¨xa_alloc_bh()ć–xa_alloc_irq(),在ĺ†é…ŤIDçš„ĺŚć—¶ç¦ç”¨ä¸ć–。 使用xa_store()ă€xa_cmpxchg()ć–xa_insert()äąźĺ°†ć ‡č®°čŻĄćťˇç›®ä¸şćŁĺś¨ĺ†é…Ťă€‚与普通的XArray不ĺŚďĽŚĺ储 ``NULL`` ĺ°†ć ‡č®°čŻĄćťˇç›®ä¸şćŁĺś¨ä˝żç”¨ä¸ďĽŚĺ°±ĺŹxa_reserve()。č¦é‡Šć”ľä¸€ä¸Şćťˇç›®ďĽŚčŻ·ä˝żç”¨xa_erase()ďĽć–者xa_release(), ĺ¦‚ćžśä˝ ĺŹŞćłé‡Šć”ľä¸€ä¸Ş ``NULL`` 的条目)。 é»č®¤ć…况下,最低的空闲条目从0开始ĺ†é…Ťă€‚ĺ¦‚ćžśä˝ ćłä»Ž1开始ĺ†é…Ťćťˇç›®ďĽŚä˝żç”¨DEFINE_XARRAY_ALLOC1()ć– ``XA_FLAGS_ALLOC1`` 会更有ć•ă€‚ĺ¦‚ćžśä˝ ćłĺ†é…ŤIDĺ°ä¸€ä¸Şćś€ĺ¤§ĺ€ĽďĽŚç„¶ĺŽç»•回最低的空闲IDďĽŚä˝ ĺŹŻä»Ąä˝żç”¨ xa_alloc_cyclic()。 ä˝ ä¸Ťč˝ĺś¨ĺ†é…Ťçš„XArrayä¸ä˝żç”¨ ``XA_MARK_0`` ďĽŚĺ› ä¸şčż™ä¸Şć ‡č®°ćŻç”¨ćťĄč·źč¸Şä¸€ä¸Şćťˇç›®ćŻĺ¦ćŻç©şé—˛çš„。其他的 ć ‡č®°ĺŹŻä»Ąäľ›ä˝ ä˝żç”¨ă€‚ 内ĺĺ†é…Ť -------- xa_store(), xa_cmpxchg(), xa_alloc(), xa_reserve()ĺ’Śxa_insert()函数接受一个gfp_t参数,以 é˛XArray需č¦ĺ†é…Ťĺ†…ĺ来ĺ储这个条目。如果该条目被ĺ 除,ĺ™ä¸Ťéś€č¦čż›čˇŚĺ†…ĺĺ†é…ŤďĽŚćŚ‡ĺ®šçš„GFPć ‡ĺż—ĺ°†č˘«ĺż˝ 略。 没有内ĺ可供ĺ†é…ŤćŻĺŹŻč˝çš„,特ĺ«ćŻĺ¦‚ćžśä˝ äĽ é€’äş†ä¸€ç»„é™ĺ¶ć€§çš„GFPć ‡ĺż—ă€‚ĺś¨čż™ç§Ťć…况下,这些函数会返回一 个特殊的值,可以用xa_err()把ĺ®ĺŹćä¸€ä¸Şé”™čŻŻĺ€Ľă€‚ĺ¦‚ćžśä˝ ä¸Ťéś€č¦çˇ®ĺ‡ĺś°çźĄé“哪个错误发生,使用xa_is_err() 会更有ć•一些。 é” -- 当使用普通APIć—¶ďĽŚä˝ ä¸Ťĺż…ć‹…ĺżé”的问é˘ă€‚XArray使用RCU和一个内é¨č‡Şć—‹é”来ĺŚćĄč®żé—®: 不需č¦é”: * xa_empty() * xa_marked() 采取RCU读é”: * xa_load() * xa_for_each() * xa_for_each_start() * xa_for_each_range() * xa_find() * xa_find_after() * xa_extract() * xa_get_mark() 内é¨ä˝żç”¨xa_lock: * xa_store() * xa_store_bh() * xa_store_irq() * xa_insert() * xa_insert_bh() * xa_insert_irq() * xa_erase() * xa_erase_bh() * xa_erase_irq() * xa_cmpxchg() * xa_cmpxchg_bh() * xa_cmpxchg_irq() * xa_store_range() * xa_alloc() * xa_alloc_bh() * xa_alloc_irq() * xa_reserve() * xa_reserve_bh() * xa_reserve_irq() * xa_destroy() * xa_set_mark() * xa_clear_mark() ĺ‡č®ľčż›ĺ…Ąć—¶ćŚćś‰xa_lock: * __xa_store() * __xa_insert() * __xa_erase() * __xa_cmpxchg() * __xa_alloc() * __xa_set_mark() * __xa_clear_mark() ĺ¦‚ćžśä˝ ćłĺ©ç”¨é”ćťĄäżťćŠ¤ä˝ ĺ储在XArrayä¸çš„ć•°ćŤ®ç»“ćž„ďĽŚä˝ ĺŹŻä»Ąĺś¨č°ç”¨xa_load()之前č°ç”¨xa_lock(),然ĺŽĺś¨ č°ç”¨xa_unlock()äą‹ĺ‰ŤĺŻąä˝ ć‰ľĺ°çš„对象进行一个引用计数。这将é˛ć˘ĺĺ‚¨ć“Ťä˝śĺś¨ćźĄć‰ľĺŻąč±ˇĺ’Śĺ˘žĺŠ refcountćśźé—´ 从数组ä¸ĺ é™¤ĺŻąč±ˇă€‚ä˝ äąźĺŹŻä»Ąä˝żç”¨RCU来éżĺ…Ťč§Łé™¤ĺŻąĺ·˛é‡Šć”ľĺ†…ĺçš„ĺĽ•ç”¨ďĽŚä˝†ĺŻąčż™ä¸€ç‚ąçš„č§Łé‡Šĺ·˛ç»Źč¶…ĺ‡şäş†ćś¬ć–‡çš„čŚ ĺ›´ă€‚ 在修改数组时,XArray不会ç¦ç”¨ä¸ć–ć–softirqs。从ä¸ć–ć–softirq上下文ä¸čŻ»ĺŹ–XArrayćŻĺ®‰ĺ…¨çš„ďĽŚĺ› ä¸şRCUé” ćŹäľ›äş†č¶łĺ¤źçš„保护。 äľ‹ĺ¦‚ďĽŚĺ¦‚ćžśä˝ ćłĺś¨čż›ç¨‹ä¸Šä¸‹ć–‡ä¸ĺ储XArrayä¸çš„条目,然ĺŽĺś¨softirq上下文ä¸ć“¦é™¤ĺ®ä»¬ďĽŚä˝ ĺŹŻä»Ąčż™ć ·ĺš:: void foo_init(struct foo *foo) { xa_init_flags(&foo->array, XA_FLAGS_LOCK_BH); } int foo_store(struct foo *foo, unsigned long index, void *entry) { int err; xa_lock_bh(&foo->array); err = xa_err(__xa_store(&foo->array, index, entry, GFP_KERNEL)); if (!err) foo->count++; xa_unlock_bh(&foo->array); return err; } /* foo_erase()只在软ä¸ć–上下文ä¸č°ç”¨ */ void foo_erase(struct foo *foo, unsigned long index) { xa_lock(&foo->array); __xa_erase(&foo->array, index); foo->count--; xa_unlock(&foo->array); } ĺ¦‚ćžśä˝ č¦ä»Žä¸ć–ć–softirq上下文ä¸äż®ć”ąXArrayďĽŚä˝ éś€č¦ä˝żç”¨xa_init_flags()ĺťĺ§‹ĺŚ–ć•°ç»„ďĽŚäĽ é€’ ``XA_FLAGS_LOCK_IRQ`` ć– ``XA_FLAGS_LOCK_BH`` ďĽĺŹ‚ć•°ďĽ‰ă€‚ 上面的例ĺčżćľç¤şäş†ä¸€ä¸Şĺ¸¸č§çš„模式,即希望在ĺ储端扩展xa_lock的覆盖čŚĺ›´ďĽŚä»ĄäżťćŠ¤ä¸Žć•°ç»„ç›¸ĺ…łçš„ä¸€äş›ç»źč®ˇ 数据。 与ä¸ć–上下文共享XArrayäąźćŻĺŹŻč˝çš„,可以在ä¸ć–处ç†ç¨‹ĺşŹĺ’Śčż›ç¨‹ä¸Šä¸‹ć–‡ä¸é˝ä˝żç”¨xa_lock_irqsave(),ć–者 在进程上下文ä¸ä˝żç”¨xa_lock_irq(),在ä¸ć–处ç†ç¨‹ĺşŹä¸ä˝żç”¨xa_lock()。一些更常č§çš„模式有一些辅助函数, 如xa_store_bh()ă€xa_store_irq()ă€xa_erase_bh()ă€xa_erase_irq()ă€xa_cmpxchg_bh() ĺ’Śxa_cmpxchg_irq()。 ćś‰ć—¶ä˝ éś€č¦ç”¨ä¸€ä¸Şmutex来保护对XArrayçš„č®żé—®ďĽŚĺ› ä¸şčż™ä¸Şé”在é”的层次结构ä¸ä˝ŤäşŽĺŹ¦ä¸€ä¸Şmutex之上。这并不 ć„Źĺ‘łçť€ä˝ ćś‰ćťä˝żç”¨ĺŹ__xa_erase()čż™ć ·çš„ĺ‡˝ć•°č€Śä¸ŤĺŤ ç”¨xa_lock;xa_lockćŻç”¨ćťĄčż›čˇŚlockdep验čŻçš„,将来也 会用于其他用途。 __xa_set_mark() ĺ’Ś __xa_clear_mark() ĺ‡˝ć•°äąźé€‚ç”¨äşŽä˝ ćźĄć‰ľä¸€ä¸Şćťˇç›®ĺą¶ćłĺŽźĺ化地设置ć–ć¸…é™¤ä¸€ä¸Şć ‡č®°çš„ ć…况。在这种ć…况下,使用é«çş§API可č˝ć›´ćś‰ć•ďĽŚĺ› ä¸şĺ®ĺ°†ä˝żä˝ ĺ…ŤäşŽčµ°ä¸¤ć¬ˇć ‘ă€‚ é«çş§API ======= é«çş§APIćŹäľ›äş†ć›´ĺ¤šçš„çµć´»ć€§ĺ’Ść›´ĺĄ˝çš„性č˝ďĽŚä˝†ä»Łä»·ćŻćŽĄĺŹŁĺŹŻč˝ć›´éšľä˝żç”¨ďĽŚäżťéšśćŽŞć–˝ć›´ĺ°‘ă€‚é«çş§APIć˛ˇćś‰ä¸şä˝ ĺŠ é”, ä˝ éś€č¦ĺś¨äż®ć”ąć•°ç»„的时候使用xa_lockă€‚ĺś¨ĺŻąć•°ç»„čż›čˇŚĺŹŞčŻ»ć“Ťä˝ść—¶ďĽŚä˝ ĺŹŻä»Ąé€‰ć‹©ä˝żç”¨xa_lockć–RCUé”ă€‚ä˝ ĺŹŻä»Ąĺś¨ ĺŚä¸€ä¸Şć•°ç»„上混ĺ使用é«çş§ĺ’Ść™®é€šć“Ťä˝śďĽ›äş‹ĺ®žä¸ŠďĽŚć™®é€šAPIćŻä»Ąé«çş§API的形式实现的。é«çş§API只对具有GPL兼容 许可čŻçš„模块可用。 é«çş§APIćŻĺźşäşŽxa_state的。这ćŻä¸€ä¸Şä¸Ťé€ŹćŽçš„ć•°ćŤ®ç»“ćž„ďĽŚä˝ ä˝żç”¨XA_STATE()ĺ®Źĺś¨ĺ †ć ä¸ĺٰćŽă€‚这个宏ĺťĺ§‹ĺŚ–äş† xa_state,准备开始在XArray上移动。ĺ®č˘«ç”¨ä˝śä¸€ä¸Şć¸¸ć ‡ćťĄäżťćŚĺś¨XArrayä¸çš„ä˝Ťç˝®ďĽŚĺą¶č®©ä˝ ćŠŠĺ„种操作组ĺ在一 起,而不必每次é˝ä»Žĺ¤´ĺĽ€ĺ§‹ă€‚xa_state的内容受rcu_read_lock()ć–xas_lock()的保护。如果需č¦ĺ é™¤äżťćŠ¤çŠ¶ć€ ĺ’Ść ‘çš„čż™äş›é”ä¸çš„ä»»ä˝•ä¸€ä¸ŞďĽŚä˝ ĺż…éˇ»č°ç”¨xas_pause()以便将来的č°ç”¨ä¸ŤäĽšäľťčµ–于状ć€ä¸ćśŞĺŹ—äżťćŠ¤çš„é¨ĺ†ă€‚ xa_state也被用来ĺ储错误(store errors)ă€‚ä˝ ĺŹŻä»Ąč°ç”¨xas_error()ćťĄćŁ€ç´˘é”™čŻŻă€‚ć‰€ćś‰çš„ć“Ťä˝śĺś¨čż›čˇŚäą‹ĺ‰Ťé˝ äĽšćŁ€ćźĄxa_statećŻĺ¦ĺ¤„于错误状ć€ďĽŚć‰€ä»Ąä˝ 没有必č¦ĺś¨ćŻŹć¬ˇč°ç”¨äą‹ĺŽćŁ€ćźĄé”™čŻŻďĽ›ä˝ ĺŹŻä»Ąčżžç»čż›čˇŚĺ¤šć¬ˇč°ç”¨ďĽŚĺŹŞĺś¨ 方便的时候检查。目前XArray代ç 本身产生的错误只有 ``ENOMEM`` ĺ’Ś ``EINVAL`` ,但ĺ®ć”ŻćŚä»»ć„Źçš„错误, 以é˛ä˝ ćłč‡Şĺ·±č°ç”¨xas_set_err()。 如果xa_statećŚćś‰ ``ENOMEM`` 错误,č°ç”¨xas_nomem()将尝试使用指定的gfpć ‡ĺż—ĺ†é…Ťć›´ĺ¤šçš„内ĺ,并将其缓 ĺ在xa_stateä¸äľ›ä¸‹ä¸€ć¬ˇĺ°ťčŻ•ă€‚čż™ä¸Şćłćł•ćŻďĽŚä˝ 拿着xa_lock,尝试操作,然ĺŽć”ľĺĽé”。该操作试图在ćŚćś‰é”çš„ć… ĺ†µä¸‹ĺ†é…Ťĺ†…ĺ,但ĺ®ć›´ćś‰ĺŹŻč˝ĺ¤±č´Ąă€‚ä¸€ć—¦ä˝ ć”ľĺĽäş†é”,xas_nomem()可以更努力地尝试ĺ†é…Ťć›´ĺ¤šĺ†…ĺ。如果值得重 试该操作,ĺ®ĺ°†čż”回 ``true`` ďĽĺŤłĺ‡şçŽ°äş†ĺ†…ĺ错误,ĺ†é…Ťäş†ć›´ĺ¤šçš„内ĺ)。如果ĺ®äą‹ĺ‰Ťĺ·˛ç»Źĺ†é…Ťäş†ĺ†…ĺ,并且 该内ĺ没有被使用,也没有错误ďĽć–č€…ä¸€äş›ä¸ŤćŻ ``ENOMEM`` 的错误),那äąĺ®ĺ°†é‡Šć”ľäą‹ĺ‰Ťĺ†é…Ťçš„内ĺ。 内é¨ćťˇç›® -------- XArray为ĺ®č‡Şĺ·±çš„目的保留了一些条目。这些条目从未通过ćŁĺ¸¸çš„API暴露出来,但ćŻĺ˝“使用é«çş§API时,有可č˝çś‹ ĺ°ĺ®ä»¬ă€‚通常,处ç†ĺ®ä»¬çš„最好方法ćŻćŠŠĺ®ä»¬äĽ 递给xas_retry(),如果ĺ®čż”回 ``true`` ,就重试操作。 .. flat-table:: :widths: 1 1 6 * - ĺŤç§° - 检测 - 用途 * - Node - xa_is_node() - 一个XArray节点。 在使用多索引xa_state时可č˝ćŻĺŹŻč§çš„。 * - Sibling - xa_is_sibling() - 一个多索引条目的非典型条目。该值表示该节点ä¸çš„哪个槽有典型条目。 * - Retry - xa_is_retry() - 这个条目目前ćŁĺś¨č˘«ä¸€ä¸Şć‹Ąćś‰xa_lock的线程修改。在这个RCU周期结束时,包ĺ«čŻĄćťˇç›®çš„čŠ‚ç‚ąĺŹŻč˝äĽšč˘«é‡Šć”ľă€‚ ä˝ ĺş”čŻĄä»Žć•°ç»„çš„ĺ¤´é¨é‡Ťć–°ĺĽ€ĺ§‹ćźĄć‰ľă€‚ * - Zero - xa_is_zero() - Zero条目通过普通APIćľç¤şä¸ş ``NULL`` ,但在XArrayä¸ĺŤ ćś‰ä¸€ä¸Şćťˇç›®ďĽŚĺŹŻç”¨äşŽäżťç•™ç´˘ĺĽ•äľ›ĺ°†ćťĄä˝żç”¨ă€‚čż™ćŻ é€ščż‡ä¸şĺ†é…Ťçš„条目ĺ†é…ŤXArraysćťĄä˝żç”¨çš„ďĽŚčż™äş›ćťˇç›®ćŻ ``NULL`` 。 其他内é¨ćťˇç›®ĺŹŻč˝äĽšĺś¨ćśŞćťĄč˘«ć·»ĺŠ ă€‚ĺś¨ĺŹŻč˝çš„ć…况下,ĺ®ä»¬ĺ°†ç”±xas_retry()处ç†ă€‚ é™„ĺŠ ĺ‡˝ć•° -------- xas_create_range()函数ĺ†é…Ťäş†ć‰€ćś‰ĺż…č¦çš„内ĺ来ĺ储一个čŚĺ›´ĺ†…的每一个条目。如果ĺ®ä¸Ťč˝ĺ†é…Ťĺ†…ĺ,ĺ®ĺ°†ĺś¨ xa_stateä¸č®ľç˝®ENOMEM。 ä˝ ĺŹŻä»Ąä˝żç”¨xas_init_marks()ĺ°†ä¸€ä¸Şćťˇç›®ä¸Šçš„ć ‡č®°é‡Ťç˝®ä¸şé»č®¤çжć€ă€‚这通常ćŻć¸…ç©şć‰€ćś‰ć ‡č®°ďĽŚé™¤éťžXArrayč˘«ć ‡č®° 为 ``XA_FLAGS_TRACK_FREE`` ,在这种ć…ĺ†µä¸‹ďĽŚć ‡č®°0č˘«č®ľç˝®ďĽŚć‰€ćś‰ĺ…¶ä»–ć ‡č®°č˘«ć¸…ç©şă€‚ä˝żç”¨xas_store()将一个 ćťˇç›®ć›żćŤ˘ä¸şĺŹ¦ä¸€ä¸Şćťˇç›®ä¸ŤäĽšé‡Ťç˝®čŻĄćťˇç›®ä¸Šçš„ć ‡č®°ďĽ›ĺ¦‚ćžśä˝ ćłé‡Ťç˝®ć ‡č®°ďĽŚä˝ 应该ćŽçˇ®ĺś°čż™ć ·ĺšă€‚ xas_load()会尽可č˝ĺś°ĺ°†xa_state移动ĺ°čŻĄćťˇç›®é™„čż‘ă€‚ĺ¦‚ćžśä˝ çźĄé“xa_state已经移动ĺ°äş†čŻĄćťˇç›®ďĽŚĺą¶ä¸”éś€č¦ćŁ€ćźĄ 该条目ćŻĺ¦ćś‰ĺŹĺŚ–ďĽŚä˝ ĺŹŻä»Ąä˝żç”¨xas_reload()来保ĺ一个函数č°ç”¨ă€‚ ĺ¦‚ćžśä˝ éś€č¦ç§»ĺЍĺ°XArrayä¸çš„不ĺŚç´˘ĺĽ•,可以č°ç”¨xas_set()ă€‚čż™ĺŹŻä»Ąĺ°†ĺ…‰ć ‡é‡Ťç˝®ĺ°ć ‘的顶端,这通常会使下一个 ć“Ťä˝śĺ°†ĺ…‰ć ‡ç§»ĺŠ¨ĺ°ć ‘ä¸ćłč¦çš„ä˝Ťç˝®ă€‚ĺ¦‚ćžśä˝ ćłç§»ĺЍĺ°ä¸‹ä¸€ä¸Şć–上一个索引,č°ç”¨xas_next()ć–xas_prev()。设置 ç´˘ĺĽ•ä¸ŤäĽšä˝żĺ…‰ć ‡ĺś¨ć•°ç»„ä¸ç§»ĺŠ¨ďĽŚć‰€ä»Ąä¸Ťéś€č¦é”,而移动ĺ°ä¸‹ä¸€ä¸Şć–上一个索引ĺ™éś€č¦é”。 ä˝ ĺŹŻä»Ąä˝żç”¨xas_find()ćśç´˘ä¸‹ä¸€ä¸Şĺ˝“前条目。这相当于xa_find()ĺ’Śxa_find_after()ďĽ›ĺ¦‚ćžśĺ…‰ć ‡ĺ·˛ç»Źç§»ĺŠ¨ĺ°äş† 一个条目,那äąĺ®ĺ°†ć‰ľĺ°ĺ˝“前引用的条目之ĺŽçš„下一个条目。如果没有,ĺ®ĺ°†čż”回xa_state索引处的条目。使用 xas_next_entry()而不ćŻxas_find()来移动ĺ°ä¸‹ä¸€ä¸Şĺ˝“前条目,在大多数ć…况下会节çśä¸€ä¸Şĺ‡˝ć•°č°ç”¨ďĽŚä˝†ä»Łä»· ćŻĺŹ‘ĺ‡şć›´ĺ¤šĺ†…č”代ç 。 xas_find_marked()函数也ćŻĺ¦‚ć¤ă€‚如果xa_state没有被移动过,ĺ®ĺ°†čż”回xa_stateçš„ç´˘ĺĽ•ĺ¤„çš„ćťˇç›®ďĽŚĺ¦‚ćžśĺ® č˘«ć ‡č®°äş†ă€‚ĺ¦ĺ™ďĽŚĺ®ĺ°†čż”回xa_state所引用的条目之ĺŽçš„ç¬¬ä¸€ä¸Şč˘«ć ‡č®°çš„ćťˇç›®ă€‚xas_next_marked()函数ç‰ĺŚ äşŽxas_next_entry()。 当使用xas_for_each()ć–xas_for_each_marked()在XArrayçš„ćźä¸ŞčŚĺ›´ĺ†…进行čżä»Łć—¶ďĽŚĺŹŻč˝éś€č¦ćš‚ć—¶ĺść˘čżä»Łă€‚ xas_pause()函数的ĺ在就ćŻä¸şäş†čż™ä¸Şç›®çš„ă€‚ĺś¨ä˝ ĺ®Ść了必č¦çš„工作并希望ć˘ĺ¤ŤĺŽďĽŚxa_state处于适当的状ć€ďĽŚĺś¨ ä˝ ćś€ĺŽĺ¤„ç†çš„条目ĺŽç»§ç»čżä»Łă€‚ĺ¦‚ćžśä˝ ĺś¨čżä»Łć—¶ç¦ç”¨äş†ä¸ć–,那äąćš‚ĺśčżä»Łĺą¶ĺś¨ćŻŹä¸€ä¸Ş ``XA_CHECK_SCHED`` 条目 ä¸é‡Ťć–°ĺŻç”¨ä¸ć–ćŻĺľĺĄ˝çš„ĺšćł•。 xas_get_mark(), xas_set_mark()ĺ’Śxas_clear_mark()函数č¦ć±‚xa_stateĺ…‰ć ‡ĺ·˛ç»Źč˘«ç§»ĺŠ¨ĺ°XArrayä¸çš„适当位 ç˝®ďĽ›ĺ¦‚ćžśä˝ ĺś¨äą‹ĺ‰Ťč°ç”¨äş†xas_pause()ć–xas_set(),ĺ®ä»¬ĺ°†ä¸ŤäĽšćś‰ä»»ä˝•作用。 ä˝ ĺŹŻä»Ąč°ç”¨xas_set_update(),让XArray每次更新一个节点时é˝č°ç”¨ä¸€ä¸Şĺ›žč°ĺ‡˝ć•°ă€‚这被页面缓ĺçš„workingset 代ç 用来维护其只包ĺ«é´ĺ˝±éˇąçš„节点ĺ—表。 多索引条目 ---------- XArray有č˝ĺŠ›ĺ°†ĺ¤šä¸Şç´˘ĺĽ•č”çł»ĺś¨ä¸€čµ·ďĽŚĺ› ć¤ĺŻąä¸€ä¸Şç´˘ĺĽ•çš„ć“Ťä˝śäĽšĺ˝±ĺ“Ťĺ°ć‰€ćś‰çš„索引。例如,ĺ储ĺ°ä»»ä˝•ç´˘ĺĽ•ĺ°†ć”ąĺŹ ä»Žä»»ä˝•ç´˘ĺĽ•ćŁ€ç´˘çš„ćťˇç›®çš„ĺ€Ľă€‚ĺś¨ä»»ä˝•ç´˘ĺĽ•ä¸Šč®ľç˝®ć–ć¸…é™¤ä¸€ä¸Şć ‡č®°ďĽŚé˝äĽšĺś¨ćŻŹä¸Şč˘«ç»‘ĺś¨ä¸€čµ·çš„ç´˘ĺĽ•ä¸Šč®ľç˝®ć–ć¸…é™¤čŻĄć ‡ 记。目前的实现只ĺ…许将2的整数倍的čŚĺ›´ç»‘在一起;例如指数64-127可以绑在一起,但2-6不č˝ă€‚这可以节çśĺ¤§é‡Ź 的内ĺ;例如,将512个条目绑在一起可以节çś4kB以上的内ĺ。 ä˝ ĺŹŻä»Ąé€ščż‡ä˝żç”¨XA_STATE_ORDER()ć–xas_set_order(),然ĺŽč°ç”¨xas_store()来ĺ›ĺ»şä¸€ä¸Şĺ¤šç´˘ĺĽ•条目。用一个 多索引的xa_stateč°ç”¨xas_load()会把xa_state移动ĺ°ć ‘ä¸çš„ćŁçˇ®ä˝Ťç˝®ďĽŚä˝†ćŻčż”回值没有意义,有可č˝ćŻä¸€ä¸Şĺ†… é¨ćťˇç›®ć– ``NULL`` ,即使在čŚĺ›´ĺ†…有一个条目ĺ储。č°ç”¨xas_find_conflict()将返回该čŚĺ›´ĺ†…的第一个条目, 如果该čŚĺ›´ĺ†…没有条目,ĺ™čż”回 ``NULL`` 。xas_for_each_conflict()čżä»Łĺ™¨ĺ°†éŤĺŽ†ćŻŹä¸Şä¸ŽćŚ‡ĺ®ščŚĺ›´é‡ŤĺŹ çš„ćťˇç›®ă€‚ 如果xas_load()é‡ĺ°ä¸€ä¸Şĺ¤šç´˘ĺĽ•条目,xa_stateä¸çš„xa_index将不会被改ĺŹă€‚当éŤĺŽ†ä¸€ä¸ŞXArrayć–者č°ç”¨xas_find() 时,如果ĺťĺ§‹ç´˘ĺĽ•在一个多索引条目的ä¸é—´ďĽŚĺ®ĺ°†ä¸ŤäĽšč˘«ć”ąĺŹă€‚随ĺŽçš„č°ç”¨ć–čżä»Łĺ°†ćŠŠç´˘ĺĽ•ç§»ĺ°čŚĺ›´ĺ†…的第一个索引。 每个条目只会被返回一次,不管ĺ®ĺŤ 据了多少个索引。 不支ćŚä˝żç”¨xas_next()ć–xas_prev()来处ç†ä¸€ä¸Şĺ¤šç´˘ĺĽ•çš„xa_state。在一个多索引的条目上使用这两个函数ä¸çš„ä»» 何一个é˝äĽšćľç¤şĺ‡şĺŚçş§çš„条目;这些条目应该被č°ç”¨č€…跳过。 在一个多索引条目的任何一个索引ä¸ĺ储 ``NULL`` ,将把每个索引的条目设置为 ``NULL`` ďĽŚĺą¶č§Łé™¤ç»‘ĺ®šă€‚é€ščż‡č° ç”¨xas_split_alloc(),在没有xa_lockçš„ć…况下,可以将一个多索引条目ĺ†ĺ‰˛ćĺŤ ćŤ®čľĺ°ŹčŚĺ›´çš„条目,然ĺŽĺ†ŤĺŹ–é”ĺą¶ č°ç”¨xas_split()。 函数和结构体 ============ 该APIĺś¨ä»Ąä¸‹ĺ†…ć ¸ä»Łç ä¸: include/linux/xarray.h lib/xarray.c