Commit c5beb07e authored by Matthew Wilcox's avatar Matthew Wilcox
Browse files

XArray: Unify xa_cmpxchg and __xa_cmpxchg



xa_cmpxchg() was one of the largest functions in the xarray
implementation.  By turning it into a wrapper and having the callers
take the lock (like several other functions), we save 160 bytes on a
tinyconfig build and reduce the duplication in xarray.c.

Signed-off-by: default avatarMatthew Wilcox <willy@infradead.org>
parent 4c0608f4
Loading
Loading
Loading
Loading
+69 −44
Original line number Diff line number Diff line
@@ -289,8 +289,6 @@ struct xarray {
void xa_init_flags(struct xarray *, gfp_t flags);
void *xa_load(struct xarray *, unsigned long index);
void *xa_store(struct xarray *, unsigned long index, void *entry, gfp_t);
void *xa_cmpxchg(struct xarray *, unsigned long index,
			void *old, void *entry, gfp_t);
void *xa_store_range(struct xarray *, unsigned long first, unsigned long last,
			void *entry, gfp_t);
bool xa_get_mark(struct xarray *, unsigned long index, xa_mark_t);
@@ -359,48 +357,6 @@ static inline void *xa_erase(struct xarray *xa, unsigned long index)
	return xa_store(xa, index, NULL, 0);
}

/**
 * xa_insert() - Store this entry in the XArray unless another entry is
 *			already present.
 * @xa: XArray.
 * @index: Index into array.
 * @entry: New entry.
 * @gfp: Memory allocation flags.
 *
 * If you would rather see the existing entry in the array, use xa_cmpxchg().
 * This function is for users who don't care what the entry is, only that
 * one is present.
 *
 * Context: Process context.  Takes and releases the xa_lock.
 *	    May sleep if the @gfp flags permit.
 * Return: 0 if the store succeeded.  -EEXIST if another entry was present.
 * -ENOMEM if memory could not be allocated.
 */
static inline int xa_insert(struct xarray *xa, unsigned long index,
		void *entry, gfp_t gfp)
{
	void *curr = xa_cmpxchg(xa, index, NULL, entry, gfp);
	if (!curr)
		return 0;
	if (xa_is_err(curr))
		return xa_err(curr);
	return -EEXIST;
}

/**
 * xa_release() - Release a reserved entry.
 * @xa: XArray.
 * @index: Index of entry.
 *
 * After calling xa_reserve(), you can call this function to release the
 * reservation.  If the entry at @index has been stored to, this function
 * will do nothing.
 */
static inline void xa_release(struct xarray *xa, unsigned long index)
{
	xa_cmpxchg(xa, index, NULL, NULL, 0);
}

/**
 * xa_for_each() - Iterate over a portion of an XArray.
 * @xa: XArray.
@@ -534,6 +490,61 @@ static inline void *xa_erase_irq(struct xarray *xa, unsigned long index)
	return entry;
}

/**
 * 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.
 *
 * 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.  Takes and releases the xa_lock.  May sleep
 * if the @gfp flags permit.
 * Return: The old value at this index or xa_err() if an error happened.
 */
static inline void *xa_cmpxchg(struct xarray *xa, unsigned long index,
			void *old, void *entry, gfp_t gfp)
{
	void *curr;

	xa_lock(xa);
	curr = __xa_cmpxchg(xa, index, old, entry, gfp);
	xa_unlock(xa);

	return curr;
}

/**
 * xa_insert() - Store this entry in the XArray unless another entry is
 *			already present.
 * @xa: XArray.
 * @index: Index into array.
 * @entry: New entry.
 * @gfp: Memory allocation flags.
 *
 * If you would rather see the existing entry in the array, use xa_cmpxchg().
 * This function is for users who don't care what the entry is, only that
 * one is present.
 *
 * Context: Process context.  Takes and releases the xa_lock.
 *	    May sleep if the @gfp flags permit.
 * Return: 0 if the store succeeded.  -EEXIST if another entry was present.
 * -ENOMEM if memory could not be allocated.
 */
static inline int xa_insert(struct xarray *xa, unsigned long index,
		void *entry, gfp_t gfp)
{
	void *curr = xa_cmpxchg(xa, index, NULL, entry, gfp);
	if (!curr)
		return 0;
	if (xa_is_err(curr))
		return xa_err(curr);
	return -EEXIST;
}

/**
 * xa_alloc() - Find somewhere to store this entry in the XArray.
 * @xa: XArray.
@@ -699,6 +710,20 @@ int xa_reserve_irq(struct xarray *xa, unsigned long index, gfp_t gfp)
	return ret;
}

/**
 * xa_release() - Release a reserved entry.
 * @xa: XArray.
 * @index: Index of entry.
 *
 * After calling xa_reserve(), you can call this function to release the
 * reservation.  If the entry at @index has been stored to, this function
 * will do nothing.
 */
static inline void xa_release(struct xarray *xa, unsigned long index)
{
	xa_cmpxchg(xa, index, NULL, NULL, 0);
}

/* Everything below here is the Advanced API.  Proceed with caution. */

/*
+0 −41
Original line number Diff line number Diff line
@@ -1406,47 +1406,6 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
}
EXPORT_SYMBOL(__xa_store);

/**
 * 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.
 *
 * 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: Process context.  Takes and releases the xa_lock.  May sleep
 * if the @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)
{
	XA_STATE(xas, xa, index);
	void *curr;

	if (WARN_ON_ONCE(xa_is_internal(entry)))
		return XA_ERROR(-EINVAL);

	do {
		xas_lock(&xas);
		curr = xas_load(&xas);
		if (curr == XA_ZERO_ENTRY)
			curr = NULL;
		if (curr == old) {
			xas_store(&xas, entry);
			if (xa_track_free(xa) && entry)
				xas_clear_mark(&xas, XA_FREE_MARK);
		}
		xas_unlock(&xas);
	} while (xas_nomem(&xas, gfp));

	return xas_result(&xas, curr);
}
EXPORT_SYMBOL(xa_cmpxchg);

/**
 * __xa_cmpxchg() - Store this entry in the XArray.
 * @xa: XArray.