Commit 3159f943 authored by Matthew Wilcox's avatar Matthew Wilcox

xarray: Replace exceptional entries

Introduce xarray value entries and tagged pointers to replace radix
tree exceptional entries.  This is a slight change in encoding to allow
the use of an extra bit (we can now store BITS_PER_LONG - 1 bits in a
value entry).  It is also a change in emphasis; exceptional entries are
intimidating and different.  As the comment explains, you can choose
to store values or pointers in the xarray and they are both first-class
citizens.
Signed-off-by: default avatarMatthew Wilcox <willy@infradead.org>
Reviewed-by: default avatarJosef Bacik <jbacik@fb.com>
parent 66ee620f
...@@ -723,9 +723,7 @@ static inline bool pte_user(pte_t pte) ...@@ -723,9 +723,7 @@ static inline bool pte_user(pte_t pte)
BUILD_BUG_ON(_PAGE_HPTEFLAGS & (0x1f << _PAGE_BIT_SWAP_TYPE)); \ BUILD_BUG_ON(_PAGE_HPTEFLAGS & (0x1f << _PAGE_BIT_SWAP_TYPE)); \
BUILD_BUG_ON(_PAGE_HPTEFLAGS & _PAGE_SWP_SOFT_DIRTY); \ BUILD_BUG_ON(_PAGE_HPTEFLAGS & _PAGE_SWP_SOFT_DIRTY); \
} while (0) } while (0)
/*
* on pte we don't need handle RADIX_TREE_EXCEPTIONAL_SHIFT;
*/
#define SWP_TYPE_BITS 5 #define SWP_TYPE_BITS 5
#define __swp_type(x) (((x).val >> _PAGE_BIT_SWAP_TYPE) \ #define __swp_type(x) (((x).val >> _PAGE_BIT_SWAP_TYPE) \
& ((1UL << SWP_TYPE_BITS) - 1)) & ((1UL << SWP_TYPE_BITS) - 1))
......
...@@ -313,9 +313,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma, ...@@ -313,9 +313,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
#define MAX_SWAPFILES_CHECK() do { \ #define MAX_SWAPFILES_CHECK() do { \
BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS); \ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS); \
} while (0) } while (0)
/*
* on pte we don't need handle RADIX_TREE_EXCEPTIONAL_SHIFT;
*/
#define SWP_TYPE_BITS 5 #define SWP_TYPE_BITS 5
#define __swp_type(x) (((x).val >> _PAGE_BIT_SWAP_TYPE) \ #define __swp_type(x) (((x).val >> _PAGE_BIT_SWAP_TYPE) \
& ((1UL << SWP_TYPE_BITS) - 1)) & ((1UL << SWP_TYPE_BITS) - 1))
......
...@@ -5996,7 +5996,8 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj, ...@@ -5996,7 +5996,8 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
count = __sg_page_count(sg); count = __sg_page_count(sg);
while (idx + count <= n) { while (idx + count <= n) {
unsigned long exception, i; void *entry;
unsigned long i;
int ret; int ret;
/* If we cannot allocate and insert this entry, or the /* If we cannot allocate and insert this entry, or the
...@@ -6011,12 +6012,9 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj, ...@@ -6011,12 +6012,9 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
if (ret && ret != -EEXIST) if (ret && ret != -EEXIST)
goto scan; goto scan;
exception = entry = xa_mk_value(idx);
RADIX_TREE_EXCEPTIONAL_ENTRY |
idx << RADIX_TREE_EXCEPTIONAL_SHIFT;
for (i = 1; i < count; i++) { for (i = 1; i < count; i++) {
ret = radix_tree_insert(&iter->radix, idx + i, ret = radix_tree_insert(&iter->radix, idx + i, entry);
(void *)exception);
if (ret && ret != -EEXIST) if (ret && ret != -EEXIST)
goto scan; goto scan;
} }
...@@ -6054,15 +6052,14 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj, ...@@ -6054,15 +6052,14 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
GEM_BUG_ON(!sg); GEM_BUG_ON(!sg);
/* If this index is in the middle of multi-page sg entry, /* If this index is in the middle of multi-page sg entry,
* the radixtree will contain an exceptional entry that points * the radix tree will contain a value entry that points
* to the start of that range. We will return the pointer to * to the start of that range. We will return the pointer to
* the base page and the offset of this page within the * the base page and the offset of this page within the
* sg entry's range. * sg entry's range.
*/ */
*offset = 0; *offset = 0;
if (unlikely(radix_tree_exception(sg))) { if (unlikely(xa_is_value(sg))) {
unsigned long base = unsigned long base = xa_to_value(sg);
(unsigned long)sg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
sg = radix_tree_lookup(&iter->radix, base); sg = radix_tree_lookup(&iter->radix, base);
GEM_BUG_ON(!sg); GEM_BUG_ON(!sg);
......
...@@ -35,7 +35,6 @@ static atomic_long_t erofs_global_shrink_cnt; ...@@ -35,7 +35,6 @@ static atomic_long_t erofs_global_shrink_cnt;
#ifdef CONFIG_EROFS_FS_ZIP #ifdef CONFIG_EROFS_FS_ZIP
/* radix_tree and the future XArray both don't use tagptr_t yet */
struct erofs_workgroup *erofs_find_workgroup( struct erofs_workgroup *erofs_find_workgroup(
struct super_block *sb, pgoff_t index, bool *tag) struct super_block *sb, pgoff_t index, bool *tag)
{ {
...@@ -47,9 +46,8 @@ struct erofs_workgroup *erofs_find_workgroup( ...@@ -47,9 +46,8 @@ struct erofs_workgroup *erofs_find_workgroup(
rcu_read_lock(); rcu_read_lock();
grp = radix_tree_lookup(&sbi->workstn_tree, index); grp = radix_tree_lookup(&sbi->workstn_tree, index);
if (grp != NULL) { if (grp != NULL) {
*tag = radix_tree_exceptional_entry(grp); *tag = xa_pointer_tag(grp);
grp = (void *)((unsigned long)grp & grp = xa_untag_pointer(grp);
~RADIX_TREE_EXCEPTIONAL_ENTRY);
if (erofs_workgroup_get(grp, &oldcount)) { if (erofs_workgroup_get(grp, &oldcount)) {
/* prefer to relax rcu read side */ /* prefer to relax rcu read side */
...@@ -83,9 +81,7 @@ int erofs_register_workgroup(struct super_block *sb, ...@@ -83,9 +81,7 @@ int erofs_register_workgroup(struct super_block *sb,
sbi = EROFS_SB(sb); sbi = EROFS_SB(sb);
erofs_workstn_lock(sbi); erofs_workstn_lock(sbi);
if (tag) grp = xa_tag_pointer(grp, tag);
grp = (void *)((unsigned long)grp |
1UL << RADIX_TREE_EXCEPTIONAL_SHIFT);
err = radix_tree_insert(&sbi->workstn_tree, err = radix_tree_insert(&sbi->workstn_tree,
grp->index, grp); grp->index, grp);
...@@ -131,9 +127,7 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi, ...@@ -131,9 +127,7 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
for (i = 0; i < found; ++i) { for (i = 0; i < found; ++i) {
int cnt; int cnt;
struct erofs_workgroup *grp = (void *) struct erofs_workgroup *grp = xa_untag_pointer(batch[i]);
((unsigned long)batch[i] &
~RADIX_TREE_EXCEPTIONAL_ENTRY);
first_index = grp->index + 1; first_index = grp->index + 1;
...@@ -150,8 +144,8 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi, ...@@ -150,8 +144,8 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
#endif #endif
continue; continue;
if (radix_tree_delete(&sbi->workstn_tree, if (xa_untag_pointer(radix_tree_delete(&sbi->workstn_tree,
grp->index) != grp) { grp->index)) != grp) {
#ifdef EROFS_FS_HAS_MANAGED_CACHE #ifdef EROFS_FS_HAS_MANAGED_CACHE
skip: skip:
erofs_workgroup_unfreeze(grp, 1); erofs_workgroup_unfreeze(grp, 1);
......
...@@ -440,7 +440,7 @@ static noinline int add_ra_bio_pages(struct inode *inode, ...@@ -440,7 +440,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
rcu_read_lock(); rcu_read_lock();
page = radix_tree_lookup(&mapping->i_pages, pg_index); page = radix_tree_lookup(&mapping->i_pages, pg_index);
rcu_read_unlock(); rcu_read_unlock();
if (page && !radix_tree_exceptional_entry(page)) { if (page && !xa_is_value(page)) {
misses++; misses++;
if (misses > 4) if (misses > 4)
break; break;
......
This diff is collapsed.
...@@ -521,7 +521,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr, ...@@ -521,7 +521,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
if (!page) if (!page)
return; return;
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
mss->swap += PAGE_SIZE; mss->swap += PAGE_SIZE;
else else
put_page(page); put_page(page);
......
...@@ -28,34 +28,26 @@ ...@@ -28,34 +28,26 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/xarray.h>
/* /*
* The bottom two bits of the slot determine how the remaining bits in the * The bottom two bits of the slot determine how the remaining bits in the
* slot are interpreted: * slot are interpreted:
* *
* 00 - data pointer * 00 - data pointer
* 01 - internal entry * 10 - internal entry
* 10 - exceptional entry * x1 - value entry
* 11 - this bit combination is currently unused/reserved
* *
* The internal entry may be a pointer to the next level in the tree, a * The internal entry may be a pointer to the next level in the tree, a
* sibling entry, or an indicator that the entry in this slot has been moved * sibling entry, or an indicator that the entry in this slot has been moved
* to another location in the tree and the lookup should be restarted. While * to another location in the tree and the lookup should be restarted. While
* NULL fits the 'data pointer' pattern, it means that there is no entry in * NULL fits the 'data pointer' pattern, it means that there is no entry in
* the tree for this index (no matter what level of the tree it is found at). * the tree for this index (no matter what level of the tree it is found at).
* This means that you cannot store NULL in the tree as a value for the index. * This means that storing a NULL entry in the tree is the same as deleting
* the entry from the tree.
*/ */
#define RADIX_TREE_ENTRY_MASK 3UL #define RADIX_TREE_ENTRY_MASK 3UL
#define RADIX_TREE_INTERNAL_NODE 1UL #define RADIX_TREE_INTERNAL_NODE 2UL
/*
* Most users of the radix tree store pointers but shmem/tmpfs stores swap
* entries in the same tree. They are marked as exceptional entries to
* distinguish them from pointers to struct page.
* EXCEPTIONAL_ENTRY tests the bit, EXCEPTIONAL_SHIFT shifts content past it.
*/
#define RADIX_TREE_EXCEPTIONAL_ENTRY 2
#define RADIX_TREE_EXCEPTIONAL_SHIFT 2
static inline bool radix_tree_is_internal_node(void *ptr) static inline bool radix_tree_is_internal_node(void *ptr)
{ {
...@@ -83,11 +75,10 @@ static inline bool radix_tree_is_internal_node(void *ptr) ...@@ -83,11 +75,10 @@ static inline bool radix_tree_is_internal_node(void *ptr)
/* /*
* @count is the count of every non-NULL element in the ->slots array * @count is the count of every non-NULL element in the ->slots array
* whether that is an exceptional entry, a retry entry, a user pointer, * whether that is a value entry, a retry entry, a user pointer,
* a sibling entry or a pointer to the next level of the tree. * a sibling entry or a pointer to the next level of the tree.
* @exceptional is the count of every element in ->slots which is * @exceptional is the count of every element in ->slots which is
* either radix_tree_exceptional_entry() or is a sibling entry for an * either a value entry or a sibling of a value entry.
* exceptional entry.
*/ */
struct radix_tree_node { struct radix_tree_node {
unsigned char shift; /* Bits remaining in each slot */ unsigned char shift; /* Bits remaining in each slot */
...@@ -268,17 +259,6 @@ static inline int radix_tree_deref_retry(void *arg) ...@@ -268,17 +259,6 @@ static inline int radix_tree_deref_retry(void *arg)
return unlikely(radix_tree_is_internal_node(arg)); return unlikely(radix_tree_is_internal_node(arg));
} }
/**
* radix_tree_exceptional_entry - radix_tree_deref_slot gave exceptional entry?
* @arg: value returned by radix_tree_deref_slot
* Returns: 0 if well-aligned pointer, non-0 if exceptional entry.
*/
static inline int radix_tree_exceptional_entry(void *arg)
{
/* Not unlikely because radix_tree_exception often tested first */
return (unsigned long)arg & RADIX_TREE_EXCEPTIONAL_ENTRY;
}
/** /**
* radix_tree_exception - radix_tree_deref_slot returned either exception? * radix_tree_exception - radix_tree_deref_slot returned either exception?
* @arg: value returned by radix_tree_deref_slot * @arg: value returned by radix_tree_deref_slot
......
...@@ -18,9 +18,8 @@ ...@@ -18,9 +18,8 @@
* *
* swp_entry_t's are *never* stored anywhere in their arch-dependent format. * swp_entry_t's are *never* stored anywhere in their arch-dependent format.
*/ */
#define SWP_TYPE_SHIFT(e) ((sizeof(e.val) * 8) - \ #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
(MAX_SWAPFILES_SHIFT + RADIX_TREE_EXCEPTIONAL_SHIFT)) #define SWP_OFFSET_MASK ((1UL << SWP_TYPE_SHIFT) - 1)
#define SWP_OFFSET_MASK(e) ((1UL << SWP_TYPE_SHIFT(e)) - 1)
/* /*
* Store a type+offset into a swp_entry_t in an arch-independent format * Store a type+offset into a swp_entry_t in an arch-independent format
...@@ -29,8 +28,7 @@ static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset) ...@@ -29,8 +28,7 @@ static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset)
{ {
swp_entry_t ret; swp_entry_t ret;
ret.val = (type << SWP_TYPE_SHIFT(ret)) | ret.val = (type << SWP_TYPE_SHIFT) | (offset & SWP_OFFSET_MASK);
(offset & SWP_OFFSET_MASK(ret));
return ret; return ret;
} }
...@@ -40,7 +38,7 @@ static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset) ...@@ -40,7 +38,7 @@ static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset)
*/ */
static inline unsigned swp_type(swp_entry_t entry) static inline unsigned swp_type(swp_entry_t entry)
{ {
return (entry.val >> SWP_TYPE_SHIFT(entry)); return (entry.val >> SWP_TYPE_SHIFT);
} }
/* /*
...@@ -49,7 +47,7 @@ static inline unsigned swp_type(swp_entry_t entry) ...@@ -49,7 +47,7 @@ static inline unsigned swp_type(swp_entry_t entry)
*/ */
static inline pgoff_t swp_offset(swp_entry_t entry) static inline pgoff_t swp_offset(swp_entry_t entry)
{ {
return entry.val & SWP_OFFSET_MASK(entry); return entry.val & SWP_OFFSET_MASK;
} }
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
...@@ -90,16 +88,13 @@ static inline swp_entry_t radix_to_swp_entry(void *arg) ...@@ -90,16 +88,13 @@ static inline swp_entry_t radix_to_swp_entry(void *arg)
{ {
swp_entry_t entry; swp_entry_t entry;
entry.val = (unsigned long)arg >> RADIX_TREE_EXCEPTIONAL_SHIFT; entry.val = xa_to_value(arg);
return entry; return entry;
} }
static inline void *swp_to_radix_entry(swp_entry_t entry) static inline void *swp_to_radix_entry(swp_entry_t entry)
{ {
unsigned long value; return xa_mk_value(entry.val);
value = entry.val << RADIX_TREE_EXCEPTIONAL_SHIFT;
return (void *)(value | RADIX_TREE_EXCEPTIONAL_ENTRY);
} }
#if IS_ENABLED(CONFIG_DEVICE_PRIVATE) #if IS_ENABLED(CONFIG_DEVICE_PRIVATE)
......
...@@ -5,9 +5,111 @@ ...@@ -5,9 +5,111 @@
* eXtensible Arrays * eXtensible Arrays
* Copyright (c) 2017 Microsoft Corporation * Copyright (c) 2017 Microsoft Corporation
* Author: Matthew Wilcox <willy@infradead.org> * Author: Matthew Wilcox <willy@infradead.org>
*
* See Documentation/core-api/xarray.rst for how to use the XArray.
*/ */
#include <linux/bug.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h>
/*
* The bottom two bits of the entry determine how the XArray interprets
* the contents:
*
* 00: Pointer entry
* 10: Internal entry
* x1: Value entry or tagged pointer
*
* Attempting to store internal entries in the XArray is a bug.
*/
#define BITS_PER_XA_VALUE (BITS_PER_LONG - 1)
/**
* xa_mk_value() - Create an XArray entry from an integer.
* @v: Value to store in XArray.
*
* Context: Any context.
* Return: An entry suitable for storing in the XArray.
*/
static inline void *xa_mk_value(unsigned long v)
{
WARN_ON((long)v < 0);
return (void *)((v << 1) | 1);
}
/**
* xa_to_value() - Get value stored in an XArray entry.
* @entry: XArray entry.
*
* Context: Any context.
* Return: The value stored in the XArray entry.
*/
static inline unsigned long xa_to_value(const void *entry)
{
return (unsigned long)entry >> 1;
}
/**
* xa_is_value() - Determine if an entry is a value.
* @entry: XArray entry.
*
* Context: Any context.
* Return: True if the entry is a value, false if it is a pointer.
*/
static inline bool xa_is_value(const void *entry)
{
return (unsigned long)entry & 1;
}
/**
* xa_tag_pointer() - Create an XArray entry for a tagged pointer.
* @p: Plain pointer.
* @tag: Tag value (0, 1 or 3).
*
* If the user of the XArray prefers, they can tag their pointers instead
* of storing value entries. Three tags are available (0, 1 and 3).
* These are distinct from the xa_mark_t as they are not replicated up
* through the array and cannot be searched for.
*
* Context: Any context.
* Return: An XArray entry.
*/
static inline void *xa_tag_pointer(void *p, unsigned long tag)
{
return (void *)((unsigned long)p | tag);
}
/**
* xa_untag_pointer() - Turn an XArray entry into a plain pointer.
* @entry: XArray entry.
*
* If you have stored a tagged pointer in the XArray, call this function
* to get the untagged version of the pointer.
*
* Context: Any context.
* Return: A pointer.
*/
static inline void *xa_untag_pointer(void *entry)
{
return (void *)((unsigned long)entry & ~3UL);
}
/**
* xa_pointer_tag() - Get the tag stored in an XArray entry.
* @entry: XArray entry.
*
* If you have stored a tagged pointer in the XArray, call this function
* to get the tag of that pointer.
*
* Context: Any context.
* Return: A tag.
*/
static inline unsigned int xa_pointer_tag(void *entry)
{
return (unsigned long)entry & 3UL;
}
#define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) #define xa_trylock(xa) spin_trylock(&(xa)->xa_lock)
#define xa_lock(xa) spin_lock(&(xa)->xa_lock) #define xa_lock(xa) spin_lock(&(xa)->xa_lock)
......
...@@ -338,11 +338,8 @@ EXPORT_SYMBOL(idr_replace); ...@@ -338,11 +338,8 @@ EXPORT_SYMBOL(idr_replace);
* by the number of bits in the leaf bitmap before doing a radix tree lookup. * by the number of bits in the leaf bitmap before doing a radix tree lookup.
* *
* As an optimisation, if there are only a few low bits set in any given * As an optimisation, if there are only a few low bits set in any given
* leaf, instead of allocating a 128-byte bitmap, we use the 'exceptional * leaf, instead of allocating a 128-byte bitmap, we store the bits
* entry' functionality of the radix tree to store BITS_PER_LONG - 2 bits * directly in the entry.
* directly in the entry. By being really tricksy, we could store
* BITS_PER_LONG - 1 bits, but there're diminishing returns after optimising
* for 0-3 allocated IDs.
* *
* We allow the radix tree 'exceptional' count to get out of date. Nothing * We allow the radix tree 'exceptional' count to get out of date. Nothing
* in the IDA nor the radix tree code checks it. If it becomes important * in the IDA nor the radix tree code checks it. If it becomes important
...@@ -366,12 +363,11 @@ static int ida_get_new_above(struct ida *ida, int start) ...@@ -366,12 +363,11 @@ static int ida_get_new_above(struct ida *ida, int start)
struct radix_tree_iter iter; struct radix_tree_iter iter;
struct ida_bitmap *bitmap; struct ida_bitmap *bitmap;
unsigned long index; unsigned long index;
unsigned bit, ebit; unsigned bit;
int new; int new;
index = start / IDA_BITMAP_BITS; index = start / IDA_BITMAP_BITS;
bit = start % IDA_BITMAP_BITS; bit = start % IDA_BITMAP_BITS;
ebit = bit + RADIX_TREE_EXCEPTIONAL_SHIFT;
slot = radix_tree_iter_init(&iter, index); slot = radix_tree_iter_init(&iter, index);
for (;;) { for (;;) {
...@@ -386,25 +382,23 @@ static int ida_get_new_above(struct ida *ida, int start) ...@@ -386,25 +382,23 @@ static int ida_get_new_above(struct ida *ida, int start)
return PTR_ERR(slot); return PTR_ERR(slot);
} }
} }
if (iter.index > index) { if (iter.index > index)
bit = 0; bit = 0;
ebit = RADIX_TREE_EXCEPTIONAL_SHIFT;
}
new = iter.index * IDA_BITMAP_BITS; new = iter.index * IDA_BITMAP_BITS;
bitmap = rcu_dereference_raw(*slot); bitmap = rcu_dereference_raw(*slot);
if (radix_tree_exception(bitmap)) { if (xa_is_value(bitmap)) {
unsigned long tmp = (unsigned long)bitmap; unsigned long tmp = xa_to_value(bitmap);
ebit = find_next_zero_bit(&tmp, BITS_PER_LONG, ebit); int vbit = find_next_zero_bit(&tmp, BITS_PER_XA_VALUE,
if (ebit < BITS_PER_LONG) { bit);
tmp |= 1UL << ebit; if (vbit < BITS_PER_XA_VALUE) {
rcu_assign_pointer(*slot, (void *)tmp); tmp |= 1UL << vbit;
return new + ebit - rcu_assign_pointer(*slot, xa_mk_value(tmp));
RADIX_TREE_EXCEPTIONAL_SHIFT; return new + vbit;
} }
bitmap = this_cpu_xchg(ida_bitmap, NULL); bitmap = this_cpu_xchg(ida_bitmap, NULL);
if (!bitmap) if (!bitmap)
return -EAGAIN; return -EAGAIN;
bitmap->bitmap[0] = tmp >> RADIX_TREE_EXCEPTIONAL_SHIFT; bitmap->bitmap[0] = tmp;
rcu_assign_pointer(*slot, bitmap); rcu_assign_pointer(*slot, bitmap);
} }
...@@ -425,17 +419,14 @@ static int ida_get_new_above(struct ida *ida, int start) ...@@ -425,17 +419,14 @@ static int ida_get_new_above(struct ida *ida, int start)
new += bit; new += bit;
if (new < 0) if (new < 0)
return -ENOSPC; return -ENOSPC;
if (ebit < BITS_PER_LONG) { if (bit < BITS_PER_XA_VALUE) {
bitmap = (void *)((1UL << ebit) | bitmap = xa_mk_value(1UL << bit);
RADIX_TREE_EXCEPTIONAL_ENTRY); } else {
radix_tree_iter_replace(root, &iter, slot, bitmap = this_cpu_xchg(ida_bitmap, NULL);
bitmap); if (!bitmap)
return new; return -EAGAIN;
__set_bit(bit, bitmap->bitmap);
} }
bitmap = this_cpu_xchg(ida_bitmap, NULL);
if (!bitmap)
return -EAGAIN;
__set_bit(bit, bitmap->bitmap);
radix_tree_iter_replace(root, &iter, slot, bitmap); radix_tree_iter_replace(root, &iter, slot, bitmap);
} }
...@@ -457,9 +448,9 @@ static void ida_remove(struct ida *ida, int id) ...@@ -457,9 +448,9 @@ static void ida_remove(struct ida *ida, int id)
goto err; goto err;
bitmap = rcu_dereference_raw(*slot); bitmap = rcu_dereference_raw(*slot);
if (radix_tree_exception(bitmap)) { if (xa_is_value(bitmap)) {
btmp = (unsigned long *)slot; btmp = (unsigned long *)slot;
offset += RADIX_TREE_EXCEPTIONAL_SHIFT; offset += 1; /* Intimate knowledge of the value encoding */
if (offset >= BITS_PER_LONG) if (offset >= BITS_PER_LONG)
goto err; goto err;
} else { } else {
...@@ -470,9 +461,8 @@ static void ida_remove(struct ida *ida, int id) ...@@ -470,9 +461,8 @@ static void ida_remove(struct ida *ida, int id)
__clear_bit(offset, btmp); __clear_bit(offset, btmp);
radix_tree_iter_tag_set(&ida->ida_rt, &iter, IDR_FREE); radix_tree_iter_tag_set(&ida->ida_rt, &iter, IDR_FREE);
if (radix_tree_exception(bitmap)) { if (xa_is_value(bitmap)) {
if (rcu_dereference_raw(*slot) == if (xa_to_value(rcu_dereference_raw(*slot)) == 0)
(void *)RADIX_TREE_EXCEPTIONAL_ENTRY)
radix_tree_iter_delete(&ida->ida_rt, &iter, slot); radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
} else if (bitmap_empty(btmp, IDA_BITMAP_BITS)) { } else if (bitmap_empty(btmp, IDA_BITMAP_BITS)) {
kfree(bitmap); kfree(bitmap);
...@@ -503,7 +493,7 @@ void ida_destroy(struct ida *ida) ...@@ -503,7 +493,7 @@ void ida_destroy(struct ida *ida)
xa_lock_irqsave(&ida->ida_rt, flags); xa_lock_irqsave(&ida->ida_rt, flags);
radix_tree_for_each_slot(slot, &ida->ida_rt, &iter, 0) { radix_tree_for_each_slot(slot, &ida->ida_rt, &iter, 0) {
struct ida_bitmap *bitmap = rcu_dereference_raw(*slot); struct ida_bitmap *bitmap = rcu_dereference_raw(*slot);
if (!radix_tree_exception(bitmap)) if (!xa_is_value(bitmap))
kfree(bitmap); kfree(bitmap);
radix_tree_iter_delete(&ida->ida_rt, &iter, slot); radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
} }
......
...@@ -340,14 +340,12 @@ static void dump_ida_node(void *entry, unsigned long index) ...@@ -340,14 +340,12 @@ static void dump_ida_node(void *entry, unsigned long index)
for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) for (i = 0; i < RADIX_TREE_MAP_SIZE; i++)
dump_ida_node(node->slots[i], dump_ida_node(node->slots[i],
index | (i << node->shift)); index | (i << node->shift));
} else if (radix_tree_exceptional_entry(entry)) { } else if (xa_is_value(entry)) {
pr_debug("ida excp: %p offset %d indices %lu-%lu data %lx\n", pr_debug("ida excp: %p offset %d indices %lu-%lu data %lx\n",
entry, (int)(index & RADIX_TREE_MAP_MASK), entry, (int)(index & RADIX_TREE_MAP_MASK),
index * IDA_BITMAP_BITS, index * IDA_BITMAP_BITS,
index * IDA_BITMAP_BITS + BITS_PER_LONG - index * IDA_BITMAP_BITS + BITS_PER_XA_VALUE,
RADIX_TREE_EXCEPTIONAL_SHIFT, xa_to_value(entry));
(unsigned long)entry >>
RADIX_TREE_EXCEPTIONAL_SHIFT);
} else { } else {
struct ida_bitmap *bitmap = entry; struct ida_bitmap *bitmap = entry;
...@@ -656,7 +654,7 @@ static int radix_tree_extend(struct radix_tree_root *root, gfp_t gfp, ...@@ -656,7 +654,7 @@ static int radix_tree_extend(struct radix_tree_root *root, gfp_t gfp,
BUG_ON(shift > BITS_PER_LONG); BUG_ON(shift > BITS_PER_LONG);
if (radix_tree_is_internal_node(entry)) { if (radix_tree_is_internal_node(entry)) {
entry_to_node(entry)->parent = node; entry_to_node(entry)->parent = node;
} else if (radix_tree_exceptional_entry(entry)) { } else if (xa_is_value(entry)) {
/* Moving an exceptional root->rnode to a node */ /* Moving an exceptional root->rnode to a node */
node->exceptional = 1; node->exceptional = 1;
} }
...@@ -955,12 +953,12 @@ static inline int insert_entries(struct radix_tree_node *node, ...@@ -955,12 +953,12 @@ static inline int insert_entries(struct radix_tree_node *node,
!is_sibling_entry(node, old) && !is_sibling_entry(node, old) &&
(old != RADIX_TREE_RETRY)) (old != RADIX_TREE_RETRY))
radix_tree_free_nodes(old); radix_tree_free_nodes(old);
if (radix_tree_exceptional_entry(old)) if (xa_is_value(old))
node->exceptional--; node->exceptional--;
} }
if (node) { if (node) {
node->count += n; node->count += n;
if (radix_tree_exceptional_entry(item)) if (xa_is_value(item))
node->exceptional += n; node->exceptional += n;
} }
return n; return n;
...@@ -974,7 +972,7 @@ static inline int insert_entries(struct radix_tree_node *node, ...@@ -974,7 +972,7 @@ static inline int insert_entries(struct radix_tree_node *node,
rcu_assign_pointer(*slot, item); rcu_assign_pointer(*slot, item);
if (node) { if (node) {
node->count++; node->count++;
if (radix_tree_exceptional_entry(item)) if (xa_is_value(item))
node->exceptional++; node->exceptional++;
} }
return 1; return 1;
...@@ -1190,8 +1188,7 @@ void __radix_tree_replace(struct radix_tree_root *root, ...@@ -1190,8 +1188,7 @@ void __radix_tree_replace(struct radix_tree_root *root,
radix_tree_update_node_t update_node) radix_tree_update_node_t update_node)
{ {
void *old = rcu_dereference_raw(*slot); void *old = rcu_dereference_raw(*slot);
int exceptional = !!radix_tree_exceptional_entry(item) - int exceptional = !!xa_is_value(item) - !!xa_is_value(old);
!!radix_tree_exceptional_entry(old);
int count = calculate_count(root, node, slot, item, old); int count = calculate_count(root, node, slot, item, old);
/* /*
...@@ -1992,7 +1989,7 @@ static bool __radix_tree_delete(struct radix_tree_root *root, ...@@ -1992,7 +1989,7 @@ static bool __radix_tree_delete(struct radix_tree_root *root,
struct radix_tree_node *node, void __rcu **slot) struct radix_tree_node *node, void __rcu **slot)
{ {
void *old = rcu_dereference_raw(*slot); void *old = rcu_dereference_raw(*slot);
int exceptional = radix_tree_exceptional_entry(old) ? -1 : 0; int exceptional = xa_is_value(old) ? -1 : 0;
unsigned offset = get_slot_offset(node, slot); unsigned offset = get_slot_offset(node, slot);
int tag; int tag;
......
...@@ -127,7 +127,7 @@ static int page_cache_tree_insert(struct address_space *mapping, ...@@ -127,7 +127,7 @@ static int page_cache_tree_insert(struct address_space *mapping,
p = radix_tree_deref_slot_protected(slot, p = radix_tree_deref_slot_protected(slot,
&mapping->i_pages.xa_lock); &mapping->i_pages.xa_lock);
if (!radix_tree_exceptional_entry(p)) if (!xa_is_value(p))
return -EEXIST; return -EEXIST;
mapping->nrexceptional--; mapping->nrexceptional--;
...@@ -336,7 +336,7 @@ page_cache_tree_delete_batch(struct address_space *mapping, ...@@ -336,7 +336,7 @@ page_cache_tree_delete_batch(struct address_space *mapping,
break; break;
page = radix_tree_deref_slot_protected(slot, page = radix_tree_deref_slot_protected(slot,
&mapping->i_pages.xa_lock); &mapping->i_pages.xa_lock);
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
continue; continue;
if (!tail_pages) { if (!tail_pages) {
/* /*
...@@ -1355,7 +1355,7 @@ pgoff_t page_cache_next_hole(struct address_space *mapping, ...@@ -1355,7 +1355,7 @@ pgoff_t page_cache_next_hole(struct address_space *mapping,
struct page *page; struct page *page;
page = radix_tree_lookup(&mapping->i_pages, index); page = radix_tree_lookup(&mapping->i_pages, index);
if (!page || radix_tree_exceptional_entry(page)) if (!page || xa_is_value(page))
break; break;
index++; index++;
if (index == 0) if (index == 0)
...@@ -1396,7 +1396,7 @@ pgoff_t page_cache_prev_hole(struct address_space *mapping, ...@@ -1396,7 +1396,7 @@ pgoff_t page_cache_prev_hole(struct address_space *mapping,
struct page *page; struct page *page;
page = radix_tree_lookup(&mapping->i_pages, index); page = radix_tree_lookup(&mapping->i_pages, index);
if (!page || radix_tree_exceptional_entry(page)) if (!page || xa_is_value(page))
break; break;
index--; index--;
if (index == ULONG_MAX) if (index == ULONG_MAX)
...@@ -1539,7 +1539,7 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, ...@@ -1539,7 +1539,7 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset,
repeat: repeat:
page = find_get_entry(mapping, offset); page = find_get_entry(mapping, offset);
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
page = NULL; page = NULL;
if (!page) if (!page)
goto no_page; goto no_page;
......
...@@ -1369,7 +1369,7 @@ static void collapse_shmem(struct mm_struct *mm, ...@@ -1369,7 +1369,7 @@ static void collapse_shmem(struct mm_struct *mm,
page = radix_tree_deref_slot_protected(slot, page = radix_tree_deref_slot_protected(slot,
&mapping->i_pages.xa_lock); &mapping->i_pages.xa_lock);
if (radix_tree_exceptional_entry(page) || !PageUptodate(page)) { if (xa_is_value(page) || !PageUptodate(page)) {
xa_unlock_irq(&mapping->i_pages); xa_unlock_irq(&mapping->i_pages);
/* swap in or instantiate fallocated page */ /* swap in or instantiate fallocated page */
if (shmem_getpage(mapping->host, index, &page, if (shmem_getpage(mapping->host, index, &page,
......
...@@ -251,7 +251,7 @@ static void force_shm_swapin_readahead(struct vm_area_struct *vma, ...@@ -251,7 +251,7 @@ static void force_shm_swapin_readahead(struct vm_area_struct *vma,
index = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; index = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
page = find_get_entry(mapping, index); page = find_get_entry(mapping, index);
if (!radix_tree_exceptional_entry(page)) { if (!xa_is_value(page)) {
if (page) if (page)
put_page(page); put_page(page);
continue; continue;
......
...@@ -4750,7 +4750,7 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma, ...@@ -4750,7 +4750,7 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
/* shmem/tmpfs may report page out on swap: account for that too. */ /* shmem/tmpfs may report page out on swap: account for that too. */
if (shmem_mapping(mapping)) { if (shmem_mapping(mapping)) {
page = find_get_entry(mapping, pgoff); page = find_get_entry(mapping, pgoff);
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
swp_entry_t swp = radix_to_swp_entry(page); swp_entry_t swp = radix_to_swp_entry(page);
if (do_memsw_account()) if (do_memsw_account())
*entry = swp; *entry = swp;
......
...@@ -66,7 +66,7 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff) ...@@ -66,7 +66,7 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
* shmem/tmpfs may return swap: account for swapcache * shmem/tmpfs may return swap: account for swapcache
* page too. * page too.
*/ */
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
swp_entry_t swp = radix_to_swp_entry(page); swp_entry_t swp = radix_to_swp_entry(page);
page = find_get_page(swap_address_space(swp), page = find_get_page(swap_address_space(swp),
swp_offset(swp)); swp_offset(swp));
......
...@@ -179,7 +179,7 @@ unsigned int __do_page_cache_readahead(struct address_space *mapping, ...@@ -179,7 +179,7 @@ unsigned int __do_page_cache_readahead(struct address_space *mapping,
rcu_read_lock(); rcu_read_lock();
page = radix_tree_lookup(&mapping->i_pages, page_offset); page = radix_tree_lookup(&mapping->i_pages, page_offset);
rcu_read_unlock(); rcu_read_unlock();
if (page && !radix_tree_exceptional_entry(page)) { if (page && !xa_is_value(page)) {
/* /*
* Page already present? Kick off the current batch of * Page already present? Kick off the current batch of
* contiguous pages before continuing with the next * contiguous pages before continuing with the next
......
...@@ -709,7 +709,7 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping, ...@@ -709,7 +709,7 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
continue; continue;
} }
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
swapped++; swapped++;
if (need_resched()) { if (need_resched()) {
...@@ -824,7 +824,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, ...@@ -824,7 +824,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
if (index >= end) if (index >= end)
break; break;
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
if (unfalloc) if (unfalloc)
continue; continue;
nr_swaps_freed += !shmem_free_swap(mapping, nr_swaps_freed += !shmem_free_swap(mapping,
...@@ -921,7 +921,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, ...@@ -921,7 +921,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
if (index >= end) if (index >= end)
break; break;
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
if (unfalloc) if (unfalloc)
continue; continue;
if (shmem_free_swap(mapping, index, page)) { if (shmem_free_swap(mapping, index, page)) {
...@@ -1643,7 +1643,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, ...@@ -1643,7 +1643,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
repeat: repeat:
swap.val = 0; swap.val = 0;
page = find_lock_entry(mapping, index); page = find_lock_entry(mapping, index);
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
swap = radix_to_swp_entry(page); swap = radix_to_swp_entry(page);
page = NULL; page = NULL;
} }
...@@ -2578,7 +2578,7 @@ static pgoff_t shmem_seek_hole_data(struct address_space *mapping, ...@@ -2578,7 +2578,7 @@ static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
index = indices[i]; index = indices[i];
} }
page = pvec.pages[i]; page = pvec.pages[i];
if (page && !radix_tree_exceptional_entry(page)) { if (page && !xa_is_value(page)) {
if (!PageUptodate(page)) if (!PageUptodate(page))
page = NULL; page = NULL;
} }
......
...@@ -965,7 +965,7 @@ void pagevec_remove_exceptionals(struct pagevec *pvec) ...@@ -965,7 +965,7 @@ void pagevec_remove_exceptionals(struct pagevec *pvec)
for (i = 0, j = 0; i < pagevec_count(pvec); i++) { for (i = 0, j = 0; i < pagevec_count(pvec); i++) {
struct page *page = pvec->pages[i]; struct page *page = pvec->pages[i];
if (!radix_tree_exceptional_entry(page)) if (!xa_is_value(page))
pvec->pages[j++] = page; pvec->pages[j++] = page;
} }
pvec->nr = j; pvec->nr = j;
......
...@@ -70,7 +70,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping, ...@@ -70,7 +70,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping,
return; return;
for (j = 0; j < pagevec_count(pvec); j++) for (j = 0; j < pagevec_count(pvec); j++)
if (radix_tree_exceptional_entry(pvec->pages[j])) if (xa_is_value(pvec->pages[j]))
break; break;
if (j == pagevec_count(pvec)) if (j == pagevec_count(pvec))
...@@ -85,7 +85,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping, ...@@ -85,7 +85,7 @@ static void truncate_exceptional_pvec_entries(struct address_space *mapping,
struct page *page = pvec->pages[i]; struct page *page = pvec->pages[i];
pgoff_t index = indices[i]; pgoff_t index = indices[i];
if (!radix_tree_exceptional_entry(page)) { if (!xa_is_value(page)) {
pvec->pages[j++] = page; pvec->pages[j++] = page;
continue; continue;
} }
...@@ -347,7 +347,7 @@ void truncate_inode_pages_range(struct address_space *mapping, ...@@ -347,7 +347,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
if (index >= end) if (index >= end)
break; break;
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
continue; continue;
if (!trylock_page(page)) if (!trylock_page(page))
...@@ -442,7 +442,7 @@ void truncate_inode_pages_range(struct address_space *mapping, ...@@ -442,7 +442,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
break; break;
} }
if (radix_tree_exceptional_entry(page)) if (xa_is_value(page))
continue; continue;
lock_page(page); lock_page(page);
...@@ -561,7 +561,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, ...@@ -561,7 +561,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
if (index > end) if (index > end)
break; break;
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
invalidate_exceptional_entry(mapping, index, invalidate_exceptional_entry(mapping, index,
page); page);
continue; continue;
...@@ -692,7 +692,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping, ...@@ -692,7 +692,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
if (index > end) if (index > end)
break; break;
if (radix_tree_exceptional_entry(page)) { if (xa_is_value(page)) {
if (!invalidate_exceptional_entry2(mapping, if (!invalidate_exceptional_entry2(mapping,
index, page)) index, page))
ret = -EBUSY; ret = -EBUSY;
......
...@@ -155,8 +155,8 @@ ...@@ -155,8 +155,8 @@
* refault distance will immediately activate the refaulting page. * refault distance will immediately activate the refaulting page.
*/ */
#define EVICTION_SHIFT (RADIX_TREE_EXCEPTIONAL_ENTRY + \ #define EVICTION_SHIFT ((BITS_PER_LONG - BITS_PER_XA_VALUE) + \
NODES_SHIFT + \ NODES_SHIFT + \
MEM_CGROUP_ID_SHIFT) MEM_CGROUP_ID_SHIFT)
#define EVICTION_MASK (~0UL >> EVICTION_SHIFT) #define EVICTION_MASK (~0UL >> EVICTION_SHIFT)
...@@ -173,20 +173,19 @@ static unsigned int bucket_order __read_mostly; ...@@ -173,20 +173,19 @@ static unsigned int bucket_order __read_mostly;
static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction) static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction)
{ {
eviction >>= bucket_order; eviction >>= bucket_order;
eviction &= EVICTION_MASK;
eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid;
eviction = (eviction << NODES_SHIFT) | pgdat->node_id; eviction = (eviction << NODES_SHIFT) | pgdat->node_id;
eviction = (eviction << RADIX_TREE_EXCEPTIONAL_SHIFT);
return (void *)(eviction | RADIX_TREE_EXCEPTIONAL_ENTRY); return xa_mk_value(eviction);
} }
static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat,
unsigned long *evictionp) unsigned long *evictionp)
{ {
unsigned long entry = (unsigned long)shadow; unsigned long entry = xa_to_value(shadow);
int memcgid, nid; int memcgid, nid;
entry >>= RADIX_TREE_EXCEPTIONAL_SHIFT;
nid = entry & ((1UL << NODES_SHIFT) - 1); nid = entry & ((1UL << NODES_SHIFT) - 1);
entry >>= NODES_SHIFT; entry >>= NODES_SHIFT;
memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1); memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1);
...@@ -453,7 +452,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item, ...@@ -453,7 +452,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
goto out_invalid; goto out_invalid;
for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) {
if (node->slots[i]) { if (node->slots[i]) {
if (WARN_ON_ONCE(!radix_tree_exceptional_entry(node->slots[i]))) if (WARN_ON_ONCE(!xa_is_value(node->slots[i])))
goto out_invalid; goto out_invalid;
if (WARN_ON_ONCE(!node->exceptional)) if (WARN_ON_ONCE(!node->exceptional))
goto out_invalid; goto out_invalid;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "test.h" #include "test.h"
#define DUMMY_PTR ((void *)0x12) #define DUMMY_PTR ((void *)0x10)
int item_idr_free(int id, void *p, void *data) int item_idr_free(int id, void *p, void *data)
{ {
...@@ -411,11 +411,11 @@ void ida_check_conv_user(void) ...@@ -411,11 +411,11 @@ void ida_check_conv_user(void)
int id = ida_alloc(&ida, GFP_NOWAIT); int id = ida_alloc(&ida, GFP_NOWAIT);
if (id == -ENOMEM) { if (id == -ENOMEM) {
IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) != IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) !=
BITS_PER_LONG - 2); BITS_PER_XA_VALUE);
id = ida_alloc(&ida, GFP_KERNEL); id = ida_alloc(&ida, GFP_KERNEL);
} else { } else {
IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) == IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) ==
BITS_PER_LONG - 2); BITS_PER_XA_VALUE);
} }
IDA_BUG_ON(&ida, id != i); IDA_BUG_ON(&ida, id != i);
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#ifndef _TEST_RADIX_TREE_H #ifndef _TEST_RADIX_TREE_H
#define _TEST_RADIX_TREE_H #define _TEST_RADIX_TREE_H
#include "generated/map-shift.h"
#include "../../../../include/linux/radix-tree.h" #include "../../../../include/linux/radix-tree.h"
extern int kmalloc_verbose; extern int kmalloc_verbose;
......
...@@ -39,12 +39,11 @@ static void __multiorder_tag_test(int index, int order) ...@@ -39,12 +39,11 @@ static void __multiorder_tag_test(int index, int order)
/* /*
* Verify we get collisions for covered indices. We try and fail to * Verify we get collisions for covered indices. We try and fail to
* insert an exceptional entry so we don't leak memory via * insert a value entry so we don't leak memory via
* item_insert_order(). * item_insert_order().
*/ */
for_each_index(i, base, order) { for_each_index(i, base, order) {
err = __radix_tree_insert(&tree, i, order, err = __radix_tree_insert(&tree, i, order, xa_mk_value(0xA0));
(void *)(0xA0 | RADIX_TREE_EXCEPTIONAL_ENTRY));
assert(err == -EEXIST); assert(err == -EEXIST);
} }
...@@ -380,8 +379,8 @@ static void multiorder_join1(unsigned long index, ...@@ -380,8 +379,8 @@ static void multiorder_join1(unsigned long index,
} }
/* /*
* Check that the accounting of exceptional entries is handled correctly * Check that the accounting of value entries is handled correctly
* by joining an exceptional entry to a normal pointer. * by joining a value entry to a normal pointer.
*/ */
static void multiorder_join2(unsigned order1, unsigned order2) static void multiorder_join2(unsigned order1, unsigned order2)
{ {
...@@ -391,9 +390,9 @@ static void multiorder_join2(unsigned order1, unsigned order2) ...@@ -391,9 +390,9 @@ static void multiorder_join2(unsigned order1, unsigned order2)
void *item2; void *item2;
item_insert_order(&tree, 0, order2); item_insert_order(&tree, 0, order2);
radix_tree_insert(&tree, 1 << order2, (void *)0x12UL); radix_tree_insert(&tree, 1 << order2, xa_mk_value(5));
item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL); item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL);
assert(item2 == (void *)0x12UL); assert(item2 == xa_mk_value(5));
assert(node->exceptional == 1); assert(node->exceptional == 1);
item2 = radix_tree_lookup(&tree, 0); item2 = radix_tree_lookup(&tree, 0);
...@@ -407,7 +406,7 @@ static void multiorder_join2(unsigned order1, unsigned order2) ...@@ -407,7 +406,7 @@ static void multiorder_join2(unsigned order1, unsigned order2)
} }
/* /*
* This test revealed an accounting bug for exceptional entries at one point. * This test revealed an accounting bug for value entries at one point.
* Nodes were being freed back into the pool with an elevated exception count * Nodes were being freed back into the pool with an elevated exception count
* by radix_tree_join() and then radix_tree_split() was failing to zero the * by radix_tree_join() and then radix_tree_split() was failing to zero the
* count of exceptional entries. * count of exceptional entries.
...@@ -421,16 +420,16 @@ static void multiorder_join3(unsigned int order) ...@@ -421,16 +420,16 @@ static void multiorder_join3(unsigned int order)
unsigned long i; unsigned long i;
for (i = 0; i < (1 << order); i++) { for (i = 0; i < (1 << order); i++) {
radix_tree_insert(&tree, i, (void *)0x12UL); radix_tree_insert(&tree, i, xa_mk_value(5));
} }
radix_tree_join(&tree, 0, order, (void *)0x16UL); radix_tree_join(&tree, 0, order, xa_mk_value(7));
rcu_barrier(); rcu_barrier();
radix_tree_split(&tree, 0, 0); radix_tree_split(&tree, 0, 0);
radix_tree_for_each_slot(slot, &tree, &iter, 0) { radix_tree_for_each_slot(slot, &tree, &iter, 0) {
radix_tree_iter_replace(&tree, &iter, slot, (void *)0x12UL); radix_tree_iter_replace(&tree, &iter, slot, xa_mk_value(5));
} }
__radix_tree_lookup(&tree, 0, &node, NULL); __radix_tree_lookup(&tree, 0, &node, NULL);
...@@ -517,10 +516,10 @@ static void __multiorder_split2(int old_order, int new_order) ...@@ -517,10 +516,10 @@ static void __multiorder_split2(int old_order, int new_order)
struct radix_tree_node *node; struct radix_tree_node *node;
void *item; void *item;
__radix_tree_insert(&tree, 0, old_order, (void *)0x12); __radix_tree_insert(&tree, 0, old_order, xa_mk_value(5));
item = __radix_tree_lookup(&tree, 0, &node, NULL); item = __radix_tree_lookup(&tree, 0, &node, NULL);
assert(item == (void *)0x12); assert(item == xa_mk_value(5));
assert(node->exceptional > 0); assert(node->exceptional > 0);
radix_tree_split(&tree, 0, new_order); radix_tree_split(&tree, 0, new_order);
...@@ -530,7 +529,7 @@ static void __multiorder_split2(int old_order, int new_order) ...@@ -530,7 +529,7 @@ static void __multiorder_split2(int old_order, int new_order)
} }
item = __radix_tree_lookup(&tree, 0, &node, NULL); item = __radix_tree_lookup(&tree, 0, &node, NULL);
assert(item != (void *)0x12); assert(item != xa_mk_value(5));
assert(node->exceptional == 0); assert(node->exceptional == 0);
item_kill_tree(&tree); item_kill_tree(&tree);
...@@ -544,40 +543,40 @@ static void __multiorder_split3(int old_order, int new_order) ...@@ -544,40 +543,40 @@ static void __multiorder_split3(int old_order, int new_order)
struct radix_tree_node *node; struct radix_tree_node *node;
void *item; void *item;
__radix_tree_insert(&tree, 0, old_order, (void *)0x12); __radix_tree_insert(&tree, 0, old_order, xa_mk_value(5));
item = __radix_tree_lookup(&tree, 0, &node, NULL); item = __radix_tree_lookup(&tree, 0, &node, NULL);
assert(item == (void *)0x12); assert(item == xa_mk_value(5));
assert(node->exceptional > 0); assert(node->exceptional > 0);
radix_tree_split(&tree, 0, new_order); radix_tree_split(&tree, 0, new_order);
radix_tree_for_each_slot(slot, &tree, &iter, 0) { radix_tree_for_each_slot(slot, &tree, &iter, 0) {
radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16); radix_tree_iter_replace(&tree, &iter, slot, xa_mk_value(7));
} }
item = __radix_tree_lookup(&tree, 0, &node, NULL); item = __radix_tree_lookup(&tree, 0, &node, NULL);
assert(item == (void *)0x16); assert(item == xa_mk_value(7));
assert(node->exceptional > 0); assert(node->exceptional > 0);
item_kill_tree(&tree); item_kill_tree(&tree);
__radix_tree_insert(&tree, 0, old_order, (void *)0x12); __radix_tree_insert(&tree, 0, old_order, xa_mk_value(5));
item = __radix_tree_lookup(&tree, 0, &node, NULL); item = __radix_tree_lookup(&tree, 0, &node, NULL);
assert(item == (void *)0x12); assert(item == xa_mk_value(5));
assert(node->exceptional > 0); assert(node->exceptional > 0);
radix_tree_split(&tree, 0, new_order); radix_tree_split(&tree, 0, new_order);
radix_tree_for_each_slot(slot, &tree, &iter, 0) { radix_tree_for_each_slot(slot, &tree, &iter, 0) {
if (iter.index == (1 << new_order)) if (iter.index == (1 << new_order))
radix_tree_iter_replace(&tree, &iter, slot, radix_tree_iter_replace(&tree, &iter, slot,
(void *)0x16); xa_mk_value(7));
else else
radix_tree_iter_replace(&tree, &iter, slot, NULL); radix_tree_iter_replace(&tree, &iter, slot, NULL);
} }
item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL); item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL);
assert(item == (void *)0x16); assert(item == xa_mk_value(7));
assert(node->count == node->exceptional); assert(node->count == node->exceptional);
do { do {
node = node->parent; node = node->parent;
...@@ -610,13 +609,13 @@ static void multiorder_account(void) ...@@ -610,13 +609,13 @@ static void multiorder_account(void)
item_insert_order(&tree, 0, 5); item_insert_order(&tree, 0, 5);
__radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); __radix_tree_insert(&tree, 1 << 5, 5, xa_mk_value(5));
__radix_tree_lookup(&tree, 0, &node, NULL); __radix_tree_lookup(&tree, 0, &node, NULL);
assert(node->count == node->exceptional * 2); assert(node->count == node->exceptional * 2);
radix_tree_delete(&tree, 1 << 5); radix_tree_delete(&tree, 1 << 5);
assert(node->exceptional == 0); assert(node->exceptional == 0);
__radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); __radix_tree_insert(&tree, 1 << 5, 5, xa_mk_value(5));
__radix_tree_lookup(&tree, 1 << 5, &node, &slot); __radix_tree_lookup(&tree, 1 << 5, &node, &slot);
assert(node->count == node->exceptional * 2); assert(node->count == node->exceptional * 2);
__radix_tree_replace(&tree, node, slot, NULL, NULL); __radix_tree_replace(&tree, node, slot, NULL, NULL);
......
...@@ -295,7 +295,7 @@ void item_kill_tree(struct radix_tree_root *root) ...@@ -295,7 +295,7 @@ void item_kill_tree(struct radix_tree_root *root)
int nfound; int nfound;
radix_tree_for_each_slot(slot, root, &iter, 0) { radix_tree_for_each_slot(slot, root, &iter, 0) {
if (radix_tree_exceptional_entry(*slot)) if (xa_is_value(*slot))
radix_tree_delete(root, iter.index); radix_tree_delete(root, iter.index);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment