aboutsummaryrefslogtreecommitdiffstats
path: root/lib/xarray.c
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@infradead.org>2017-11-10 15:34:55 -0500
committerMatthew Wilcox <willy@infradead.org>2018-10-21 10:45:58 -0400
commit41aec91f55985e7f14ee75fe2f6e7bcfff0d0fae (patch)
tree4efdedeabd066e15a542b28f21a47731c5323b5b /lib/xarray.c
parent58d6ea3085f2e53714810a513c61629f6d2be0a6 (diff)
xarray: Add XArray conditional store operations
Like cmpxchg(), xa_cmpxchg will only store to the index if the current entry matches the old entry. It returns the current entry, which is usually more useful than the errno returned by radix_tree_insert(). For the users who really only want the errno, the xa_insert() wrapper provides a more convenient calling convention. Signed-off-by: Matthew Wilcox <willy@infradead.org>
Diffstat (limited to 'lib/xarray.c')
-rw-r--r--lib/xarray.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/lib/xarray.c b/lib/xarray.c
index 4596a95ed9cd..2ba5a98ec618 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -976,6 +976,77 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
976EXPORT_SYMBOL(__xa_store); 976EXPORT_SYMBOL(__xa_store);
977 977
978/** 978/**
979 * xa_cmpxchg() - Conditionally replace an entry in the XArray.
980 * @xa: XArray.
981 * @index: Index into array.
982 * @old: Old value to test against.
983 * @entry: New value to place in array.
984 * @gfp: Memory allocation flags.
985 *
986 * If the entry at @index is the same as @old, replace it with @entry.
987 * If the return value is equal to @old, then the exchange was successful.
988 *
989 * Context: Process context. Takes and releases the xa_lock. May sleep
990 * if the @gfp flags permit.
991 * Return: The old value at this index or xa_err() if an error happened.
992 */
993void *xa_cmpxchg(struct xarray *xa, unsigned long index,
994 void *old, void *entry, gfp_t gfp)
995{
996 XA_STATE(xas, xa, index);
997 void *curr;
998
999 if (WARN_ON_ONCE(xa_is_internal(entry)))
1000 return XA_ERROR(-EINVAL);
1001
1002 do {
1003 xas_lock(&xas);
1004 curr = xas_load(&xas);
1005 if (curr == old)
1006 xas_store(&xas, entry);
1007 xas_unlock(&xas);
1008 } while (xas_nomem(&xas, gfp));
1009
1010 return xas_result(&xas, curr);
1011}
1012EXPORT_SYMBOL(xa_cmpxchg);
1013
1014/**
1015 * __xa_cmpxchg() - Store this entry in the XArray.
1016 * @xa: XArray.
1017 * @index: Index into array.
1018 * @old: Old value to test against.
1019 * @entry: New entry.
1020 * @gfp: Memory allocation flags.
1021 *
1022 * You must already be holding the xa_lock when calling this function.
1023 * It will drop the lock if needed to allocate memory, and then reacquire
1024 * it afterwards.
1025 *
1026 * Context: Any context. Expects xa_lock to be held on entry. May
1027 * release and reacquire xa_lock if @gfp flags permit.
1028 * Return: The old entry at this index or xa_err() if an error happened.
1029 */
1030void *__xa_cmpxchg(struct xarray *xa, unsigned long index,
1031 void *old, void *entry, gfp_t gfp)
1032{
1033 XA_STATE(xas, xa, index);
1034 void *curr;
1035
1036 if (WARN_ON_ONCE(xa_is_internal(entry)))
1037 return XA_ERROR(-EINVAL);
1038
1039 do {
1040 curr = xas_load(&xas);
1041 if (curr == old)
1042 xas_store(&xas, entry);
1043 } while (__xas_nomem(&xas, gfp));
1044
1045 return xas_result(&xas, curr);
1046}
1047EXPORT_SYMBOL(__xa_cmpxchg);
1048
1049/**
979 * __xa_set_mark() - Set this mark on this entry while locked. 1050 * __xa_set_mark() - Set this mark on this entry while locked.
980 * @xa: XArray. 1051 * @xa: XArray.
981 * @index: Index of entry. 1052 * @index: Index of entry.