mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-04-08 03:28:15 +07:00
XArray: Permit storing 2-byte-aligned pointers
On m68k, statically allocated pointers may only be two-byte aligned. This clashes with the XArray's method for tagging internal pointers. Permit storing these pointers in single slots (ie not in multislots). Signed-off-by: Matthew Wilcox <willy@infradead.org>
This commit is contained in:
parent
4a31896c5b
commit
76b4e52995
@ -176,7 +176,8 @@ static inline bool xa_is_internal(const void *entry)
|
|||||||
*/
|
*/
|
||||||
static inline bool xa_is_err(const void *entry)
|
static inline bool xa_is_err(const void *entry)
|
||||||
{
|
{
|
||||||
return unlikely(xa_is_internal(entry));
|
return unlikely(xa_is_internal(entry) &&
|
||||||
|
(unsigned long)entry >= -((MAX_ERRNO << 2) + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1039,8 +1040,8 @@ static inline bool xa_is_sibling(const void *entry)
|
|||||||
(entry < xa_mk_sibling(XA_CHUNK_SIZE - 1));
|
(entry < xa_mk_sibling(XA_CHUNK_SIZE - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XA_ZERO_ENTRY xa_mk_internal(256)
|
#define XA_RETRY_ENTRY xa_mk_internal(256)
|
||||||
#define XA_RETRY_ENTRY xa_mk_internal(257)
|
#define XA_ZERO_ENTRY xa_mk_internal(257)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xa_is_zero() - Is the entry a zero entry?
|
* xa_is_zero() - Is the entry a zero entry?
|
||||||
@ -1064,6 +1065,17 @@ static inline bool xa_is_retry(const void *entry)
|
|||||||
return unlikely(entry == XA_RETRY_ENTRY);
|
return unlikely(entry == XA_RETRY_ENTRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xa_is_advanced() - Is the entry only permitted for the advanced API?
|
||||||
|
* @entry: Entry to be stored in the XArray.
|
||||||
|
*
|
||||||
|
* Return: %true if the entry cannot be stored by the normal API.
|
||||||
|
*/
|
||||||
|
static inline bool xa_is_advanced(const void *entry)
|
||||||
|
{
|
||||||
|
return xa_is_internal(entry) && (entry <= XA_RETRY_ENTRY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* typedef xa_update_node_t - A callback function from the XArray.
|
* typedef xa_update_node_t - A callback function from the XArray.
|
||||||
* @node: The node which is being processed
|
* @node: The node which is being processed
|
||||||
|
@ -1184,6 +1184,35 @@ static noinline void check_store_range(struct xarray *xa)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_align_1(struct xarray *xa, char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int id;
|
||||||
|
unsigned long index;
|
||||||
|
void *entry;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
id = 0;
|
||||||
|
XA_BUG_ON(xa, xa_alloc(xa, &id, UINT_MAX, name + i, GFP_KERNEL)
|
||||||
|
!= 0);
|
||||||
|
XA_BUG_ON(xa, id != i);
|
||||||
|
}
|
||||||
|
xa_for_each(xa, index, entry)
|
||||||
|
XA_BUG_ON(xa, xa_is_err(entry));
|
||||||
|
xa_destroy(xa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline void check_align(struct xarray *xa)
|
||||||
|
{
|
||||||
|
char name[] = "Motorola 68000";
|
||||||
|
|
||||||
|
check_align_1(xa, name);
|
||||||
|
check_align_1(xa, name + 1);
|
||||||
|
check_align_1(xa, name + 2);
|
||||||
|
check_align_1(xa, name + 3);
|
||||||
|
// check_align_2(xa, name);
|
||||||
|
}
|
||||||
|
|
||||||
static LIST_HEAD(shadow_nodes);
|
static LIST_HEAD(shadow_nodes);
|
||||||
|
|
||||||
static void test_update_node(struct xa_node *node)
|
static void test_update_node(struct xa_node *node)
|
||||||
@ -1333,6 +1362,7 @@ static int xarray_checks(void)
|
|||||||
check_create_range(&array);
|
check_create_range(&array);
|
||||||
check_store_range(&array);
|
check_store_range(&array);
|
||||||
check_store_iter(&array);
|
check_store_iter(&array);
|
||||||
|
check_align(&xa0);
|
||||||
|
|
||||||
check_workingset(&array, 0);
|
check_workingset(&array, 0);
|
||||||
check_workingset(&array, 64);
|
check_workingset(&array, 64);
|
||||||
|
22
lib/xarray.c
22
lib/xarray.c
@ -232,6 +232,8 @@ void *xas_load(struct xa_state *xas)
|
|||||||
if (xas->xa_shift > node->shift)
|
if (xas->xa_shift > node->shift)
|
||||||
break;
|
break;
|
||||||
entry = xas_descend(xas, node);
|
entry = xas_descend(xas, node);
|
||||||
|
if (node->shift == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -506,7 +508,7 @@ static void xas_free_nodes(struct xa_state *xas, struct xa_node *top)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
void *entry = xa_entry_locked(xas->xa, node, offset);
|
void *entry = xa_entry_locked(xas->xa, node, offset);
|
||||||
|
|
||||||
if (xa_is_node(entry)) {
|
if (node->shift && xa_is_node(entry)) {
|
||||||
node = xa_to_node(entry);
|
node = xa_to_node(entry);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
continue;
|
continue;
|
||||||
@ -604,6 +606,7 @@ static int xas_expand(struct xa_state *xas, void *head)
|
|||||||
/*
|
/*
|
||||||
* xas_create() - Create a slot to store an entry in.
|
* xas_create() - Create a slot to store an entry in.
|
||||||
* @xas: XArray operation state.
|
* @xas: XArray operation state.
|
||||||
|
* @allow_root: %true if we can store the entry in the root directly
|
||||||
*
|
*
|
||||||
* Most users will not need to call this function directly, as it is called
|
* Most users will not need to call this function directly, as it is called
|
||||||
* by xas_store(). It is useful for doing conditional store operations
|
* by xas_store(). It is useful for doing conditional store operations
|
||||||
@ -613,7 +616,7 @@ static int xas_expand(struct xa_state *xas, void *head)
|
|||||||
* If the slot was newly created, returns %NULL. If it failed to create the
|
* If the slot was newly created, returns %NULL. If it failed to create the
|
||||||
* slot, returns %NULL and indicates the error in @xas.
|
* slot, returns %NULL and indicates the error in @xas.
|
||||||
*/
|
*/
|
||||||
static void *xas_create(struct xa_state *xas)
|
static void *xas_create(struct xa_state *xas, bool allow_root)
|
||||||
{
|
{
|
||||||
struct xarray *xa = xas->xa;
|
struct xarray *xa = xas->xa;
|
||||||
void *entry;
|
void *entry;
|
||||||
@ -628,6 +631,8 @@ static void *xas_create(struct xa_state *xas)
|
|||||||
shift = xas_expand(xas, entry);
|
shift = xas_expand(xas, entry);
|
||||||
if (shift < 0)
|
if (shift < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (!shift && !allow_root)
|
||||||
|
shift = XA_CHUNK_SHIFT;
|
||||||
entry = xa_head_locked(xa);
|
entry = xa_head_locked(xa);
|
||||||
slot = &xa->xa_head;
|
slot = &xa->xa_head;
|
||||||
} else if (xas_error(xas)) {
|
} else if (xas_error(xas)) {
|
||||||
@ -687,7 +692,7 @@ void xas_create_range(struct xa_state *xas)
|
|||||||
xas->xa_sibs = 0;
|
xas->xa_sibs = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
xas_create(xas);
|
xas_create(xas, true);
|
||||||
if (xas_error(xas))
|
if (xas_error(xas))
|
||||||
goto restore;
|
goto restore;
|
||||||
if (xas->xa_index <= (index | XA_CHUNK_MASK))
|
if (xas->xa_index <= (index | XA_CHUNK_MASK))
|
||||||
@ -754,7 +759,7 @@ void *xas_store(struct xa_state *xas, void *entry)
|
|||||||
bool value = xa_is_value(entry);
|
bool value = xa_is_value(entry);
|
||||||
|
|
||||||
if (entry)
|
if (entry)
|
||||||
first = xas_create(xas);
|
first = xas_create(xas, !xa_is_node(entry));
|
||||||
else
|
else
|
||||||
first = xas_load(xas);
|
first = xas_load(xas);
|
||||||
|
|
||||||
@ -1279,7 +1284,6 @@ static void *xas_result(struct xa_state *xas, void *curr)
|
|||||||
{
|
{
|
||||||
if (xa_is_zero(curr))
|
if (xa_is_zero(curr))
|
||||||
return NULL;
|
return NULL;
|
||||||
XA_NODE_BUG_ON(xas->xa_node, xa_is_internal(curr));
|
|
||||||
if (xas_error(xas))
|
if (xas_error(xas))
|
||||||
curr = xas->xa_node;
|
curr = xas->xa_node;
|
||||||
return curr;
|
return curr;
|
||||||
@ -1349,7 +1353,7 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
|
|||||||
XA_STATE(xas, xa, index);
|
XA_STATE(xas, xa, index);
|
||||||
void *curr;
|
void *curr;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
if (WARN_ON_ONCE(xa_is_advanced(entry)))
|
||||||
return XA_ERROR(-EINVAL);
|
return XA_ERROR(-EINVAL);
|
||||||
if (xa_track_free(xa) && !entry)
|
if (xa_track_free(xa) && !entry)
|
||||||
entry = XA_ZERO_ENTRY;
|
entry = XA_ZERO_ENTRY;
|
||||||
@ -1415,7 +1419,7 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index,
|
|||||||
XA_STATE(xas, xa, index);
|
XA_STATE(xas, xa, index);
|
||||||
void *curr;
|
void *curr;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
if (WARN_ON_ONCE(xa_is_advanced(entry)))
|
||||||
return XA_ERROR(-EINVAL);
|
return XA_ERROR(-EINVAL);
|
||||||
if (xa_track_free(xa) && !entry)
|
if (xa_track_free(xa) && !entry)
|
||||||
entry = XA_ZERO_ENTRY;
|
entry = XA_ZERO_ENTRY;
|
||||||
@ -1538,7 +1542,7 @@ void *xa_store_range(struct xarray *xa, unsigned long first,
|
|||||||
if (last + 1)
|
if (last + 1)
|
||||||
order = __ffs(last + 1);
|
order = __ffs(last + 1);
|
||||||
xas_set_order(&xas, last, order);
|
xas_set_order(&xas, last, order);
|
||||||
xas_create(&xas);
|
xas_create(&xas, true);
|
||||||
if (xas_error(&xas))
|
if (xas_error(&xas))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
@ -1580,7 +1584,7 @@ int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp)
|
|||||||
XA_STATE(xas, xa, 0);
|
XA_STATE(xas, xa, 0);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
if (WARN_ON_ONCE(xa_is_advanced(entry)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (WARN_ON_ONCE(!xa_track_free(xa)))
|
if (WARN_ON_ONCE(!xa_track_free(xa)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
Loading…
Reference in New Issue
Block a user