2481 lines · 63.7 KB · C
RawDownload
 		if (!advance) {			entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset);			if (xa_is_sibling(entry)) {				xas->xa_offset = xa_to_sibling(entry);				xas_move_index(xas, xas->xa_offset);			}		} 		offset = xas_find_chunk(xas, advance, mark);		if (offset > xas->xa_offset) {			advance = false;			xas_move_index(xas, offset);			/* Mind the wrap */			if ((xas->xa_index - 1) >= max)				goto max;			xas->xa_offset = offset;			if (offset == XA_CHUNK_SIZE)				continue;		} 		entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset);		if (!entry && !(xa_track_free(xas->xa) && mark == XA_FREE_MARK))			continue;		if (xa_is_sibling(entry))			continue;		if (!xa_is_node(entry))			return entry;		xas->xa_node = xa_to_node(entry);		xas_set_offset(xas);	} out:	if (xas->xa_index > max)		goto max;	return set_bounds(xas);max:	xas->xa_node = XAS_RESTART;	return NULL;}EXPORT_SYMBOL_GPL(xas_find_marked); /** * xas_find_conflict() - Find the next present entry in a range. * @xas: XArray operation state. * * The @xas describes both a range and a position within that range. * * Context: Any context.  Expects xa_lock to be held. * Return: The next entry in the range covered by @xas or %NULL. */void *xas_find_conflict(struct xa_state *xas){	void *curr; 	if (xas_error(xas))		return NULL; 	if (!xas->xa_node)		return NULL; 	if (xas_top(xas->xa_node)) {		curr = xas_start(xas);		if (!curr)			return NULL;		while (xa_is_node(curr)) {			struct xa_node *node = xa_to_node(curr);			curr = xas_descend(xas, node);		}		if (curr)			return curr;	} 	if (xas->xa_node->shift > xas->xa_shift)		return NULL; 	for (;;) {		if (xas->xa_node->shift == xas->xa_shift) {			if ((xas->xa_offset & xas->xa_sibs) == xas->xa_sibs)				break;		} else if (xas->xa_offset == XA_CHUNK_MASK) {			xas->xa_offset = xas->xa_node->offset;			xas->xa_node = xa_parent_locked(xas->xa, xas->xa_node);			if (!xas->xa_node)				break;			continue;		}		curr = xa_entry_locked(xas->xa, xas->xa_node, ++xas->xa_offset);		if (xa_is_sibling(curr))			continue;		while (xa_is_node(curr)) {			xas->xa_node = xa_to_node(curr);			xas->xa_offset = 0;			curr = xa_entry_locked(xas->xa, xas->xa_node, 0);		}		if (curr)			return curr;	}	xas->xa_offset -= xas->xa_sibs;	return NULL;}EXPORT_SYMBOL_GPL(xas_find_conflict); /** * xa_load() - Load an entry from an XArray. * @xa: XArray. * @index: index into array. * * Context: Any context.  Takes and releases the RCU lock. * Return: The entry at @index in @xa. */void *xa_load(struct xarray *xa, unsigned long index){	XA_STATE(xas, xa, index);	void *entry; 	rcu_read_lock();	do {		entry = xa_zero_to_null(xas_load(&xas));	} while (xas_retry(&xas, entry));	rcu_read_unlock(); 	return entry;}EXPORT_SYMBOL(xa_load); static void *xas_result(struct xa_state *xas, void *curr){	if (xas_error(xas))		curr = xas->xa_node;	return curr;} /** * __xa_erase() - Erase this entry from the XArray while locked. * @xa: XArray. * @index: Index into array. * * After this function returns, loading from @index will return %NULL. * If the index is part of a multi-index entry, all indices will be erased * and none of the entries will be part of a multi-index entry. * * Context: Any context.  Expects xa_lock to be held on entry. * Return: The entry which used to be at this index. */void *__xa_erase(struct xarray *xa, unsigned long index){	XA_STATE(xas, xa, index);	return xas_result(&xas, xa_zero_to_null(xas_store(&xas, NULL)));}EXPORT_SYMBOL(__xa_erase); /** * xa_erase() - Erase this entry from the XArray. * @xa: XArray. * @index: Index of entry. * * After this function returns, loading from @index will return %NULL. * If the index is part of a multi-index entry, all indices will be erased * and none of the entries will be part of a multi-index entry. * * Context: Any context.  Takes and releases the xa_lock. * Return: The entry which used to be at this index. */void *xa_erase(struct xarray *xa, unsigned long index){	void *entry; 	xa_lock(xa);	entry = __xa_erase(xa, index);	xa_unlock(xa); 	return entry;}EXPORT_SYMBOL(xa_erase); /** * __xa_store() - Store this entry in the XArray. * @xa: XArray. * @index: Index into array. * @entry: New entry. * @gfp: Memory allocation flags. * * You must already be holding the xa_lock when calling this function. * It will drop the lock if needed to allocate memory, and then reacquire * it afterwards. * * Context: Any context.  Expects xa_lock to be held on entry.  May * release and reacquire xa_lock if @gfp flags permit. * Return: The old entry at this index or xa_err() if an error happened. */void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp){	XA_STATE(xas, xa, index);	void *curr; 	if (WARN_ON_ONCE(xa_is_advanced(entry)))		return XA_ERROR(-EINVAL);	if (xa_track_free(xa) && !entry)		entry = XA_ZERO_ENTRY; 	do {		curr = xas_store(&xas, entry);		if (xa_track_free(xa))			xas_clear_mark(&xas, XA_FREE_MARK);	} while (__xas_nomem(&xas, gfp)); 	return xas_result(&xas, xa_zero_to_null(curr));}EXPORT_SYMBOL(__xa_store); /** * xa_store() - Store this entry in the XArray. * @xa: XArray. * @index: Index into array. * @entry: New entry. * @gfp: Memory allocation flags. * * After this function returns, loads from this index will return @entry. * Storing into an existing multi-index entry updates the entry of every index. * The marks associated with @index are unaffected unless @entry is %NULL. * * Context: Any context.  Takes and releases the xa_lock. * May sleep if the @gfp flags permit. * Return: The old entry at this index on success, xa_err(-EINVAL) if @entry * cannot be stored in an XArray, or xa_err(-ENOMEM) if memory allocation * failed. */void *xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp){	void *curr; 	xa_lock(xa);	curr = __xa_store(xa, index, entry, gfp);	xa_unlock(xa); 	return curr;}EXPORT_SYMBOL(xa_store); static inline void *__xa_cmpxchg_raw(struct xarray *xa, unsigned long index,			void *old, void *entry, gfp_t gfp); /** * __xa_cmpxchg() - Conditionally replace an entry in the XArray. * @xa: XArray. * @index: Index into array. * @old: Old value to test against. * @entry: New value to place in array. * @gfp: Memory allocation flags. * * You must already be holding the xa_lock when calling this function. * It will drop the lock if needed to allocate memory, and then reacquire * it afterwards. * * If the entry at @index is the same as @old, replace it with @entry. * If the return value is equal to @old, then the exchange was successful. * * Context: Any context.  Expects xa_lock to be held on entry.  May * release and reacquire xa_lock if @gfp flags permit. * Return: The old value at this index or xa_err() if an error happened. */void *__xa_cmpxchg(struct xarray *xa, unsigned long index,			void *old, void *entry, gfp_t gfp){	return xa_zero_to_null(__xa_cmpxchg_raw(xa, index, old, entry, gfp));}EXPORT_SYMBOL(__xa_cmpxchg); static inline void *__xa_cmpxchg_raw(struct xarray *xa, unsigned long index,			void *old, void *entry, gfp_t gfp){	XA_STATE(xas, xa, index);	void *curr; 	if (WARN_ON_ONCE(xa_is_advanced(entry)))		return XA_ERROR(-EINVAL); 	do {		curr = xas_load(&xas);		if (curr == old) {			xas_store(&xas, entry);			if (xa_track_free(xa) && entry && !curr)				xas_clear_mark(&xas, XA_FREE_MARK);		}	} while (__xas_nomem(&xas, gfp)); 	return xas_result(&xas, curr);} /** * __xa_insert() - Store this entry in the XArray if no entry is present. * @xa: XArray. * @index: Index into array. * @entry: New entry. * @gfp: Memory allocation flags. * * Inserting a NULL entry will store a reserved entry (like xa_reserve()) * if no entry is present.  Inserting will fail if a reserved entry is * present, even though loading from this index will return NULL. * * 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 store succeeded.  -EBUSY if another entry was present. * -ENOMEM if memory could not be allocated. */int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp){	void *curr;	int errno; 	if (!entry)		entry = XA_ZERO_ENTRY;	curr = __xa_cmpxchg_raw(xa, index, NULL, entry, gfp);	errno = xa_err(curr);	if (errno)		return errno;	return (curr != NULL) ? -EBUSY : 0;}EXPORT_SYMBOL(__xa_insert); #ifdef CONFIG_XARRAY_MULTIstatic void xas_set_range(struct xa_state *xas, unsigned long first,		unsigned long last){	unsigned int shift = 0;	unsigned long sibs = last - first;	unsigned int offset = XA_CHUNK_MASK; 	xas_set(xas, first); 	while ((first & XA_CHUNK_MASK) == 0) {		if (sibs < XA_CHUNK_MASK)			break;		if ((sibs == XA_CHUNK_MASK) && (offset < XA_CHUNK_MASK))			break;		shift += XA_CHUNK_SHIFT;		if (offset == XA_CHUNK_MASK)			offset = sibs & XA_CHUNK_MASK;		sibs >>= XA_CHUNK_SHIFT;		first >>= XA_CHUNK_SHIFT;	} 	offset = first & XA_CHUNK_MASK;	if (offset + sibs > XA_CHUNK_MASK)		sibs = XA_CHUNK_MASK - offset;	if ((((first + sibs + 1) << shift) - 1) > last)		sibs -= 1; 	xas->xa_shift = shift;	xas->xa_sibs = sibs;} /** * xa_store_range() - Store this entry at a range of indices in the XArray. * @xa: XArray. * @first: First index to affect. * @last: Last index to affect. * @entry: New entry. * @gfp: Memory allocation flags. * * After this function returns, loads from any index between @first and @last, * inclusive will return @entry. * Storing into an existing multi-index entry updates the entry of every index. * The marks associated with @index are unaffected unless @entry is %NULL. * * Context: Process context.  Takes and releases the xa_lock.  May sleep * if the @gfp flags permit. * Return: %NULL on success, xa_err(-EINVAL) if @entry cannot be stored in * an XArray, or xa_err(-ENOMEM) if memory allocation failed. */void *xa_store_range(struct xarray *xa, unsigned long first,		unsigned long last, void *entry, gfp_t gfp){	XA_STATE(xas, xa, 0); 	if (WARN_ON_ONCE(xa_is_internal(entry)))		return XA_ERROR(-EINVAL);	if (last < first)		return XA_ERROR(-EINVAL); 	do {		xas_lock(&xas);		if (entry) {			unsigned int order = BITS_PER_LONG;			if (last + 1)				order = __ffs(last + 1);			xas_set_order(&xas, last, order);			xas_create(&xas, true);			if (xas_error(&xas))				goto unlock;		}		do {			xas_set_range(&xas, first, last);			xas_store(&xas, entry);			if (xas_error(&xas))				goto unlock;			first += xas_size(&xas);		} while (first <= last);unlock:		xas_unlock(&xas);	} while (xas_nomem(&xas, gfp)); 	return xas_result(&xas, NULL);}EXPORT_SYMBOL(xa_store_range); /** * xas_get_order() - Get the order of an entry. * @xas: XArray operation state. * * Called after xas_load, the xas should not be in an error state. * The xas should not be pointing to a sibling entry. * * Return: A number between 0 and 63 indicating the order of the entry. */int xas_get_order(struct xa_state *xas){	int order = 0; 	if (!xas->xa_node)		return 0; 	XA_NODE_BUG_ON(xas->xa_node, xa_is_sibling(xa_entry(xas->xa,		       xas->xa_node, xas->xa_offset)));	for (;;) {		unsigned int slot = xas->xa_offset + (1 << order); 		if (slot >= XA_CHUNK_SIZE)			break;		if (!xa_is_sibling(xa_entry(xas->xa, xas->xa_node, slot)))			break;		order++;	} 	order += xas->xa_node->shift;	return order;}EXPORT_SYMBOL_GPL(xas_get_order); /** * xa_get_order() - Get the order of an entry. * @xa: XArray. * @index: Index of the entry. * * Return: A number between 0 and 63 indicating the order of the entry. */int xa_get_order(struct xarray *xa, unsigned long index){	XA_STATE(xas, xa, index);	int order = 0;	void *entry; 	rcu_read_lock();	entry = xas_load(&xas);	if (entry)		order = xas_get_order(&xas);	rcu_read_unlock(); 	return order;}EXPORT_SYMBOL(xa_get_order);#endif /* CONFIG_XARRAY_MULTI */ /** * __xa_alloc() - Find somewhere to store this entry in the XArray. * @xa: XArray. * @id: Pointer to ID. * @limit: Range for allocated ID. * @entry: New entry. * @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. * * 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 on success, -ENOMEM if memory could not be allocated or * -EBUSY if there are no free entries in @limit. */int __xa_alloc(struct xarray *xa, u32 *id, void *entry,		struct xa_limit limit, gfp_t gfp){	XA_STATE(xas, xa, 0); 	if (WARN_ON_ONCE(xa_is_advanced(entry)))		return -EINVAL;	if (WARN_ON_ONCE(!xa_track_free(xa)))		return -EINVAL; 	if (!entry)		entry = XA_ZERO_ENTRY; 	do {		xas.xa_index = limit.min;		xas_find_marked(&xas, limit.max, XA_FREE_MARK);

Lines 1501–2000 of 2481. Previous lines