/** * xas_reload() - 从xarray中重新获取一个条目。 * @xas: XArray operation state. * * Use this function to check that a previously loaded entry still has * the same value. This is useful for the lockless pagecache lookup where * we walk the array with only the RCU lock to protect us, lock the page, * then check that the page hasn't moved since we looked it up. * * The caller guarantees that @xas is still valid. If it may be in an * error or restart state, call xas_load() instead. * * Return: The entry at this location in the xarray. */ staticinlinevoid *xas_reload(struct xa_state *xas) { structxa_node *node = xas->xa_node; void *entry; char offset;
/** * xas_store() - 将此条目存储在 XArray 中。 * @xas: XArray operation state. * @entry: New entry. * * 如果 @xas 在多重索引条目上操作,则该函数返回的条目基本上是毫无意义的(它可能是内部条目,或者可能是 %NULL,即使在范围覆盖的某些索引中有非 NULL 条目)。这对当前用户没有问题,如果需要可以进行更改。 * * Return: The old entry at this index. */ void *xas_store(struct xa_state *xas, void *entry) { structxa_node *node; void __rcu **slot = &xas->xa->xa_head; unsignedint offset, max; int count = 0; int values = 0; void *first, *next; bool value = xa_is_value(entry);
/* 如果 entry 非空,调用 xas_create 创建必要的节点或结构以存储条目 */ if (entry) { bool allow_root = !xa_is_node(entry) && !xa_is_zero(entry); first = xas_create(xas, allow_root); } else { first = xas_load(xas); }-+
if (xas_invalid(xas)) return first; node = xas->xa_node; if (node && (xas->xa_shift < node->shift)) xas->xa_sibs = 0; if ((first == entry) && !xas->xa_sibs) return first;
next = first; offset = xas->xa_offset; max = xas->xa_offset + xas->xa_sibs; if (node) { slot = &node->slots[offset]; if (xas->xa_sibs) xas_squash_marks(xas); } if (!entry) xas_init_marks(xas);
for (;;) { /* * Must clear the marks before setting the entry to NULL, * otherwise xas_for_each_marked may find a NULL entry and * stop early. rcu_assign_pointer contains a release barrier * so the mark clearing will appear to happen before the * entry is set to NULL. */ rcu_assign_pointer(*slot, entry); if (xa_is_node(next) && (!node || node->shift)) xas_free_nodes(xas, xa_to_node(next)); if (!node) break; count += !next - !entry; values += !xa_is_value(first) - !value; if (entry) { if (offset == max) break; if (!xa_is_sibling(entry)) entry = xa_mk_sibling(xas->xa_offset); } else { if (offset == XA_CHUNK_MASK) break; } next = xa_entry_locked(xas->xa, node, ++offset); if (!xa_is_sibling(next)) { if (!entry && (offset > max)) break; first = next; } slot++; }
/** * xas_find_marked() - Find the next marked entry in the XArray. * @xas: XArray operation state. * @max: Highest index to return. * @mark: Mark number to search for. * * If the @xas has not yet been walked to an entry, return the marked entry * which has an index >= xas.xa_index. If it has been walked, the entry * currently being pointed at has been processed, and so we return the * first marked entry with an index > xas.xa_index. * * If no marked entry is found and the array is smaller than @max, @xas is * set to the bounds state and xas->xa_index is set to the smallest index * not yet in the array. This allows @xas to be immediately passed to * xas_store(). * * If no entry is found before @max is reached, @xas is set to the restart * state. * * Return: The entry, if found, otherwise %NULL. */ void *xas_find_marked(struct xa_state *xas, unsignedlong max, xa_mark_t mark) { bool advance = true; unsignedint offset; void *entry;
if (xas_error(xas)) returnNULL; if (xas->xa_index > max) goto max;