2481 lines · 63.7 KB · C
RawDownload
		if (xas.xa_node == XAS_RESTART)			xas_set_err(&xas, -EBUSY);		else			*id = xas.xa_index;		xas_store(&xas, entry);		xas_clear_mark(&xas, XA_FREE_MARK);	} while (__xas_nomem(&xas, gfp)); 	return xas_error(&xas);}EXPORT_SYMBOL(__xa_alloc); /** * __xa_alloc_cyclic() - Find somewhere to store this entry in the XArray. * @xa: XArray. * @id: Pointer to ID. * @entry: New entry. * @limit: Range of allocated ID. * @next: Pointer to next ID to allocate. * @gfp: Memory allocation flags. * * Finds an empty entry in @xa between @limit.min and @limit.max, * stores the index into the @id pointer, then stores the entry at * that index.  A concurrent lookup will not see an uninitialised @id. * The search for an empty entry will start at @next and will wrap * around if necessary. * * Must only be operated on an xarray initialized with flag XA_FLAGS_ALLOC set * in xa_init_flags(). * * Context: Any context.  Expects xa_lock to be held on entry.  May * release and reacquire xa_lock if @gfp flags permit. * Return: 0 if the allocation succeeded without wrapping.  1 if the * allocation succeeded after wrapping, -ENOMEM if memory could not be * allocated or -EBUSY if there are no free entries in @limit. */int __xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry,		struct xa_limit limit, u32 *next, gfp_t gfp){	u32 min = limit.min;	int ret; 	limit.min = max(min, *next);	ret = __xa_alloc(xa, id, entry, limit, gfp);	if ((xa->xa_flags & XA_FLAGS_ALLOC_WRAPPED) && ret == 0) {		xa->xa_flags &= ~XA_FLAGS_ALLOC_WRAPPED;		ret = 1;	} 	if (ret < 0 && limit.min > min) {		limit.min = min;		ret = __xa_alloc(xa, id, entry, limit, gfp);		if (ret == 0)			ret = 1;	} 	if (ret >= 0) {		*next = *id + 1;		if (*next == 0)			xa->xa_flags |= XA_FLAGS_ALLOC_WRAPPED;	}	return ret;}EXPORT_SYMBOL(__xa_alloc_cyclic); /** * __xa_set_mark() - Set this mark on this entry while locked. * @xa: XArray. * @index: Index of entry. * @mark: Mark number. * * Attempting to set a mark on a %NULL entry does not succeed. * * Context: Any context.  Expects xa_lock to be held on entry. */void __xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark){	XA_STATE(xas, xa, index);	void *entry = xas_load(&xas); 	if (entry)		xas_set_mark(&xas, mark);}EXPORT_SYMBOL(__xa_set_mark); /** * __xa_clear_mark() - Clear this mark on this entry while locked. * @xa: XArray. * @index: Index of entry. * @mark: Mark number. * * Context: Any context.  Expects xa_lock to be held on entry. */void __xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark){	XA_STATE(xas, xa, index);	void *entry = xas_load(&xas); 	if (entry)		xas_clear_mark(&xas, mark);}EXPORT_SYMBOL(__xa_clear_mark); /** * xa_get_mark() - Inquire whether this mark is set on this entry. * @xa: XArray. * @index: Index of entry. * @mark: Mark number. * * This function uses the RCU read lock, so the result may be out of date * by the time it returns.  If you need the result to be stable, use a lock. * * Context: Any context.  Takes and releases the RCU lock. * Return: True if the entry at @index has this mark set, false if it doesn't. */bool xa_get_mark(struct xarray *xa, unsigned long index, xa_mark_t mark){	XA_STATE(xas, xa, index);	void *entry; 	rcu_read_lock();	entry = xas_start(&xas);	while (xas_get_mark(&xas, mark)) {		if (!xa_is_node(entry))			goto found;		entry = xas_descend(&xas, xa_to_node(entry));	}	rcu_read_unlock();	return false; found:	rcu_read_unlock();	return true;}EXPORT_SYMBOL(xa_get_mark); /** * xa_set_mark() - Set this mark on this entry. * @xa: XArray. * @index: Index of entry. * @mark: Mark number. * * Attempting to set a mark on a %NULL entry does not succeed. * * Context: Process context.  Takes and releases the xa_lock. */void xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark){	xa_lock(xa);	__xa_set_mark(xa, index, mark);	xa_unlock(xa);}EXPORT_SYMBOL(xa_set_mark); /** * xa_clear_mark() - Clear this mark on this entry. * @xa: XArray. * @index: Index of entry. * @mark: Mark number. * * Clearing a mark always succeeds. * * Context: Process context.  Takes and releases the xa_lock. */void xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark){	xa_lock(xa);	__xa_clear_mark(xa, index, mark);	xa_unlock(xa);}EXPORT_SYMBOL(xa_clear_mark); /** * xa_find() - Search the XArray for an entry. * @xa: XArray. * @indexp: Pointer to an index. * @max: Maximum index to search to. * @filter: Selection criterion. * * Finds the entry in @xa which matches the @filter, and has the lowest * index that is at least @indexp and no more than @max. * If an entry is found, @indexp is updated to be the index of the entry. * This function is protected by the RCU read lock, so it may not find * entries which are being simultaneously added.  It will not return an * %XA_RETRY_ENTRY; if you need to see retry entries, use xas_find(). * * Context: Any context.  Takes and releases the RCU lock. * Return: The entry, if found, otherwise %NULL. */void *xa_find(struct xarray *xa, unsigned long *indexp,			unsigned long max, xa_mark_t filter){	XA_STATE(xas, xa, *indexp);	void *entry; 	rcu_read_lock();	do {		if ((__force unsigned int)filter < XA_MAX_MARKS)			entry = xas_find_marked(&xas, max, filter);		else			entry = xas_find(&xas, max);	} while (xas_retry(&xas, entry));	rcu_read_unlock(); 	if (entry)		*indexp = xas.xa_index;	return entry;}EXPORT_SYMBOL(xa_find); static bool xas_sibling(struct xa_state *xas){	struct xa_node *node = xas->xa_node;	unsigned long mask; 	if (!IS_ENABLED(CONFIG_XARRAY_MULTI) || !node)		return false;	mask = (XA_CHUNK_SIZE << node->shift) - 1;	return (xas->xa_index & mask) >		((unsigned long)xas->xa_offset << node->shift);} /** * xa_find_after() - Search the XArray for a present entry. * @xa: XArray. * @indexp: Pointer to an index. * @max: Maximum index to search to. * @filter: Selection criterion. * * Finds the entry in @xa which matches the @filter and has the lowest * index that is above @indexp and no more than @max. * If an entry is found, @indexp is updated to be the index of the entry. * This function is protected by the RCU read lock, so it may miss entries * which are being simultaneously added.  It will not return an * %XA_RETRY_ENTRY; if you need to see retry entries, use xas_find(). * * Context: Any context.  Takes and releases the RCU lock. * Return: The pointer, if found, otherwise %NULL. */void *xa_find_after(struct xarray *xa, unsigned long *indexp,			unsigned long max, xa_mark_t filter){	XA_STATE(xas, xa, *indexp + 1);	void *entry; 	if (xas.xa_index == 0)		return NULL; 	rcu_read_lock();	for (;;) {		if ((__force unsigned int)filter < XA_MAX_MARKS)			entry = xas_find_marked(&xas, max, filter);		else			entry = xas_find(&xas, max); 		if (xas_invalid(&xas))			break;		if (xas_sibling(&xas))			continue;		if (!xas_retry(&xas, entry))			break;	}	rcu_read_unlock(); 	if (entry)		*indexp = xas.xa_index;	return entry;}EXPORT_SYMBOL(xa_find_after); static unsigned int xas_extract_present(struct xa_state *xas, void **dst,			unsigned long max, unsigned int n){	void *entry;	unsigned int i = 0; 	rcu_read_lock();	xas_for_each(xas, entry, max) {		if (xas_retry(xas, entry))			continue;		dst[i++] = entry;		if (i == n)			break;	}	rcu_read_unlock(); 	return i;} static unsigned int xas_extract_marked(struct xa_state *xas, void **dst,			unsigned long max, unsigned int n, xa_mark_t mark){	void *entry;	unsigned int i = 0; 	rcu_read_lock();	xas_for_each_marked(xas, entry, max, mark) {		if (xas_retry(xas, entry))			continue;		dst[i++] = entry;		if (i == n)			break;	}	rcu_read_unlock(); 	return i;} /** * xa_extract() - Copy selected entries from the XArray into a normal array. * @xa: The source XArray to copy from. * @dst: The buffer to copy entries into. * @start: The first index in the XArray eligible to be selected. * @max: The last index in the XArray eligible to be selected. * @n: The maximum number of entries to copy. * @filter: Selection criterion. * * Copies up to @n entries that match @filter from the XArray.  The * copied entries will have indices between @start and @max, inclusive. * * The @filter may be an XArray mark value, in which case entries which are * marked with that mark will be copied.  It may also be %XA_PRESENT, in * which case all entries which are not %NULL will be copied. * * The entries returned may not represent a snapshot of the XArray at a * moment in time.  For example, if another thread stores to index 5, then * index 10, calling xa_extract() may return the old contents of index 5 * and the new contents of index 10.  Indices not modified while this * function is running will not be skipped. * * If you need stronger guarantees, holding the xa_lock across calls to this * function will prevent concurrent modification. * * Context: Any context.  Takes and releases the RCU lock. * Return: The number of entries copied. */unsigned int xa_extract(struct xarray *xa, void **dst, unsigned long start,			unsigned long max, unsigned int n, xa_mark_t filter){	XA_STATE(xas, xa, start); 	if (!n)		return 0; 	if ((__force unsigned int)filter < XA_MAX_MARKS)		return xas_extract_marked(&xas, dst, max, n, filter);	return xas_extract_present(&xas, dst, max, n);}EXPORT_SYMBOL(xa_extract); /** * xa_delete_node() - Private interface for workingset code. * @node: Node to be removed from the tree. * @update: Function to call to update ancestor nodes. * * Context: xa_lock must be held on entry and will not be released. */void xa_delete_node(struct xa_node *node, xa_update_node_t update){	struct xa_state xas = {		.xa = node->array,		.xa_index = (unsigned long)node->offset <<				(node->shift + XA_CHUNK_SHIFT),		.xa_shift = node->shift + XA_CHUNK_SHIFT,		.xa_offset = node->offset,		.xa_node = xa_parent_locked(node->array, node),		.xa_update = update,	}; 	xas_store(&xas, NULL);}EXPORT_SYMBOL_GPL(xa_delete_node);	/* For the benefit of the test suite */ /** * xa_destroy() - Free all internal data structures. * @xa: XArray. * * After calling this function, the XArray is empty and has freed all memory * allocated for its internal data structures.  You are responsible for * freeing the objects referenced by the XArray. * * Context: Any context.  Takes and releases the xa_lock, interrupt-safe. */void xa_destroy(struct xarray *xa){	XA_STATE(xas, xa, 0);	unsigned long flags;	void *entry; 	xas.xa_node = NULL;	xas_lock_irqsave(&xas, flags);	entry = xa_head_locked(xa);	RCU_INIT_POINTER(xa->xa_head, NULL);	xas_init_marks(&xas);	if (xa_zero_busy(xa))		xa_mark_clear(xa, XA_FREE_MARK);	/* lockdep checks we're still holding the lock in xas_free_nodes() */	if (xa_is_node(entry))		xas_free_nodes(&xas, xa_to_node(entry));	xas_unlock_irqrestore(&xas, flags);}EXPORT_SYMBOL(xa_destroy); #ifdef XA_DEBUGvoid xa_dump_node(const struct xa_node *node){	unsigned i, j; 	if (!node)		return;	if ((unsigned long)node & 3) {		pr_cont("node %px\n", node);		return;	} 	pr_cont("node %px %s %d parent %px shift %d count %d values %d "		"array %px list %px %px marks",		node, node->parent ? "offset" : "max", node->offset,		node->parent, node->shift, node->count, node->nr_values,		node->array, node->private_list.prev, node->private_list.next);	for (i = 0; i < XA_MAX_MARKS; i++)		for (j = 0; j < XA_MARK_LONGS; j++)			pr_cont(" %lx", node->marks[i][j]);	pr_cont("\n");} void xa_dump_index(unsigned long index, unsigned int shift){	if (!shift)		pr_info("%lu: ", index);	else if (shift >= BITS_PER_LONG)		pr_info("0-%lu: ", ~0UL);	else		pr_info("%lu-%lu: ", index, index | ((1UL << shift) - 1));} void xa_dump_entry(const void *entry, unsigned long index, unsigned long shift){	if (!entry)		return; 	xa_dump_index(index, shift); 	if (xa_is_node(entry)) {		if (shift == 0) {			pr_cont("%px\n", entry);		} else {			unsigned long i;			struct xa_node *node = xa_to_node(entry);			xa_dump_node(node);			for (i = 0; i < XA_CHUNK_SIZE; i++)				xa_dump_entry(node->slots[i],				      index + (i << node->shift), node->shift);		}	} else if (xa_is_value(entry))		pr_cont("value %ld (0x%lx) [%px]\n", xa_to_value(entry),						xa_to_value(entry), entry);	else if (!xa_is_internal(entry))		pr_cont("%px\n", entry);	else if (xa_is_retry(entry))		pr_cont("retry (%ld)\n", xa_to_internal(entry));	else if (xa_is_sibling(entry))		pr_cont("sibling (slot %ld)\n", xa_to_sibling(entry));	else if (xa_is_zero(entry))		pr_cont("zero (%ld)\n", xa_to_internal(entry));	else		pr_cont("UNKNOWN ENTRY (%px)\n", entry);} void xa_dump(const struct xarray *xa){	void *entry = xa->xa_head;	unsigned int shift = 0; 	pr_info("xarray: %px head %px flags %x marks %d %d %d\n", xa, entry,			xa->xa_flags, xa_marked(xa, XA_MARK_0),			xa_marked(xa, XA_MARK_1), xa_marked(xa, XA_MARK_2));	if (xa_is_node(entry))		shift = xa_to_node(entry)->shift + XA_CHUNK_SHIFT;	xa_dump_entry(entry, 0, shift);}#endif

Lines 2001–2481 of 2481. Previous lines