2016-03-18 00:21:45 +03:00
# include <stdlib.h>
# include <assert.h>
# include <stdio.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/bitops.h>
# include "test.h"
struct item *
item_tag_set ( struct radix_tree_root * root , unsigned long index , int tag )
{
return radix_tree_tag_set ( root , index , tag ) ;
}
struct item *
item_tag_clear ( struct radix_tree_root * root , unsigned long index , int tag )
{
return radix_tree_tag_clear ( root , index , tag ) ;
}
int item_tag_get ( struct radix_tree_root * root , unsigned long index , int tag )
{
return radix_tree_tag_get ( root , index , tag ) ;
}
2016-12-15 02:08:23 +03:00
int __item_insert ( struct radix_tree_root * root , struct item * item )
2016-03-18 00:21:45 +03:00
{
2016-12-15 02:08:23 +03:00
return __radix_tree_insert ( root , item - > index , item - > order , item ) ;
2016-03-18 00:21:45 +03:00
}
int item_insert ( struct radix_tree_root * root , unsigned long index )
{
2016-12-15 02:08:23 +03:00
return __item_insert ( root , item_create ( index , 0 ) ) ;
2016-05-21 03:02:14 +03:00
}
int item_insert_order ( struct radix_tree_root * root , unsigned long index ,
unsigned order )
{
2016-12-15 02:08:23 +03:00
return __item_insert ( root , item_create ( index , order ) ) ;
}
void item_sanity ( struct item * item , unsigned long index )
{
unsigned long mask ;
assert ( ! radix_tree_is_internal_node ( item ) ) ;
assert ( item - > order < BITS_PER_LONG ) ;
mask = ( 1UL < < item - > order ) - 1 ;
assert ( ( item - > index | mask ) = = ( index | mask ) ) ;
2016-03-18 00:21:45 +03:00
}
int item_delete ( struct radix_tree_root * root , unsigned long index )
{
struct item * item = radix_tree_delete ( root , index ) ;
if ( item ) {
2016-12-15 02:08:23 +03:00
item_sanity ( item , index ) ;
2016-03-18 00:21:45 +03:00
free ( item ) ;
return 1 ;
}
return 0 ;
}
2016-12-15 02:08:23 +03:00
struct item * item_create ( unsigned long index , unsigned int order )
2016-03-18 00:21:45 +03:00
{
struct item * ret = malloc ( sizeof ( * ret ) ) ;
ret - > index = index ;
2016-12-15 02:08:23 +03:00
ret - > order = order ;
2016-03-18 00:21:45 +03:00
return ret ;
}
void item_check_present ( struct radix_tree_root * root , unsigned long index )
{
struct item * item ;
item = radix_tree_lookup ( root , index ) ;
2016-12-15 02:08:23 +03:00
assert ( item ! = NULL ) ;
item_sanity ( item , index ) ;
2016-03-18 00:21:45 +03:00
}
struct item * item_lookup ( struct radix_tree_root * root , unsigned long index )
{
return radix_tree_lookup ( root , index ) ;
}
void item_check_absent ( struct radix_tree_root * root , unsigned long index )
{
struct item * item ;
item = radix_tree_lookup ( root , index ) ;
2016-12-15 02:08:23 +03:00
assert ( item = = NULL ) ;
2016-03-18 00:21:45 +03:00
}
/*
* Scan only the passed ( start , start + nr ] for present items
*/
void item_gang_check_present ( struct radix_tree_root * root ,
unsigned long start , unsigned long nr ,
int chunk , int hop )
{
struct item * items [ chunk ] ;
unsigned long into ;
for ( into = 0 ; into < nr ; ) {
int nfound ;
int nr_to_find = chunk ;
int i ;
if ( nr_to_find > ( nr - into ) )
nr_to_find = nr - into ;
nfound = radix_tree_gang_lookup ( root , ( void * * ) items ,
start + into , nr_to_find ) ;
assert ( nfound = = nr_to_find ) ;
for ( i = 0 ; i < nfound ; i + + )
assert ( items [ i ] - > index = = start + into + i ) ;
into + = hop ;
}
}
/*
* Scan the entire tree , only expecting present items ( start , start + nr ]
*/
void item_full_scan ( struct radix_tree_root * root , unsigned long start ,
unsigned long nr , int chunk )
{
struct item * items [ chunk ] ;
unsigned long into = 0 ;
unsigned long this_index = start ;
int nfound ;
int i ;
// printf("%s(0x%08lx, 0x%08lx, %d)\n", __FUNCTION__, start, nr, chunk);
while ( ( nfound = radix_tree_gang_lookup ( root , ( void * * ) items , into ,
chunk ) ) ) {
// printf("At 0x%08lx, nfound=%d\n", into, nfound);
for ( i = 0 ; i < nfound ; i + + ) {
assert ( items [ i ] - > index = = this_index ) ;
this_index + + ;
}
// printf("Found 0x%08lx->0x%08lx\n",
// items[0]->index, items[nfound-1]->index);
into = this_index ;
}
if ( chunk )
assert ( this_index = = start + nr ) ;
nfound = radix_tree_gang_lookup ( root , ( void * * ) items ,
this_index , chunk ) ;
assert ( nfound = = 0 ) ;
}
2016-12-15 02:08:55 +03:00
/* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */
int tag_tagged_items ( struct radix_tree_root * root , pthread_mutex_t * lock ,
unsigned long start , unsigned long end , unsigned batch ,
unsigned iftag , unsigned thentag )
{
unsigned long tagged = 0 ;
struct radix_tree_iter iter ;
void * * slot ;
if ( batch = = 0 )
batch = 1 ;
if ( lock )
pthread_mutex_lock ( lock ) ;
radix_tree_for_each_tagged ( slot , root , & iter , start , iftag ) {
if ( iter . index > end )
break ;
radix_tree_iter_tag_set ( root , & iter , thentag ) ;
tagged + + ;
if ( ( tagged % batch ) ! = 0 )
continue ;
slot = radix_tree_iter_resume ( slot , & iter ) ;
if ( lock ) {
pthread_mutex_unlock ( lock ) ;
rcu_barrier ( ) ;
pthread_mutex_lock ( lock ) ;
}
}
if ( lock )
pthread_mutex_unlock ( lock ) ;
return tagged ;
}
2016-12-15 02:08:52 +03:00
/* Use the same pattern as find_swap_entry() in mm/shmem.c */
unsigned long find_item ( struct radix_tree_root * root , void * item )
{
struct radix_tree_iter iter ;
void * * slot ;
unsigned long found = - 1 ;
unsigned long checked = 0 ;
radix_tree_for_each_slot ( slot , root , & iter , 0 ) {
if ( * slot = = item ) {
found = iter . index ;
break ;
}
checked + + ;
if ( ( checked % 4 ) ! = 0 )
continue ;
slot = radix_tree_iter_resume ( slot , & iter ) ;
}
return found ;
}
2016-03-18 00:21:45 +03:00
static int verify_node ( struct radix_tree_node * slot , unsigned int tag ,
2016-05-21 03:03:16 +03:00
int tagged )
2016-03-18 00:21:45 +03:00
{
int anyset = 0 ;
int i ;
int j ;
2016-05-21 03:03:27 +03:00
slot = entry_to_node ( slot ) ;
2016-03-18 00:21:48 +03:00
2016-03-18 00:21:45 +03:00
/* Verify consistency at this level */
for ( i = 0 ; i < RADIX_TREE_TAG_LONGS ; i + + ) {
if ( slot - > tags [ tag ] [ i ] ) {
anyset = 1 ;
break ;
}
}
if ( tagged ! = anyset ) {
2016-05-21 03:03:16 +03:00
printf ( " tag: %u, shift %u, tagged: %d, anyset: %d \n " ,
tag , slot - > shift , tagged , anyset ) ;
2016-03-18 00:21:45 +03:00
for ( j = 0 ; j < RADIX_TREE_MAX_TAGS ; j + + ) {
printf ( " tag %d: " , j ) ;
for ( i = 0 ; i < RADIX_TREE_TAG_LONGS ; i + + )
printf ( " %016lx " , slot - > tags [ j ] [ i ] ) ;
printf ( " \n " ) ;
}
return 1 ;
}
assert ( tagged = = anyset ) ;
/* Go for next level */
2016-05-21 03:03:16 +03:00
if ( slot - > shift > 0 ) {
2016-03-18 00:21:45 +03:00
for ( i = 0 ; i < RADIX_TREE_MAP_SIZE ; i + + )
if ( slot - > slots [ i ] )
2016-05-21 03:03:16 +03:00
if ( verify_node ( slot - > slots [ i ] , tag ,
2016-03-18 00:21:45 +03:00
! ! test_bit ( i , slot - > tags [ tag ] ) ) ) {
printf ( " Failure at off %d \n " , i ) ;
for ( j = 0 ; j < RADIX_TREE_MAX_TAGS ; j + + ) {
printf ( " tag %d: " , j ) ;
for ( i = 0 ; i < RADIX_TREE_TAG_LONGS ; i + + )
printf ( " %016lx " , slot - > tags [ j ] [ i ] ) ;
printf ( " \n " ) ;
}
return 1 ;
}
}
return 0 ;
}
void verify_tag_consistency ( struct radix_tree_root * root , unsigned int tag )
{
2016-05-21 03:03:16 +03:00
struct radix_tree_node * node = root - > rnode ;
2016-05-21 03:03:30 +03:00
if ( ! radix_tree_is_internal_node ( node ) )
2016-03-18 00:21:45 +03:00
return ;
2016-05-21 03:03:16 +03:00
verify_node ( node , tag , ! ! root_tag_get ( root , tag ) ) ;
2016-03-18 00:21:45 +03:00
}
void item_kill_tree ( struct radix_tree_root * root )
{
2016-12-15 02:08:20 +03:00
struct radix_tree_iter iter ;
void * * slot ;
2016-03-18 00:21:45 +03:00
struct item * items [ 32 ] ;
int nfound ;
2016-12-15 02:08:20 +03:00
radix_tree_for_each_slot ( slot , root , & iter , 0 ) {
if ( radix_tree_exceptional_entry ( * slot ) )
radix_tree_delete ( root , iter . index ) ;
}
2016-03-18 00:21:45 +03:00
while ( ( nfound = radix_tree_gang_lookup ( root , ( void * * ) items , 0 , 32 ) ) ) {
int i ;
for ( i = 0 ; i < nfound ; i + + ) {
void * ret ;
ret = radix_tree_delete ( root , items [ i ] - > index ) ;
assert ( ret = = items [ i ] ) ;
free ( items [ i ] ) ;
}
}
assert ( radix_tree_gang_lookup ( root , ( void * * ) items , 0 , 32 ) = = 0 ) ;
assert ( root - > rnode = = NULL ) ;
}
void tree_verify_min_height ( struct radix_tree_root * root , int maxindex )
{
2016-05-21 03:03:16 +03:00
unsigned shift ;
struct radix_tree_node * node = root - > rnode ;
2016-05-21 03:03:30 +03:00
if ( ! radix_tree_is_internal_node ( node ) ) {
2016-05-21 03:03:16 +03:00
assert ( maxindex = = 0 ) ;
return ;
}
2016-05-21 03:03:27 +03:00
node = entry_to_node ( node ) ;
2016-05-21 03:03:16 +03:00
assert ( maxindex < = node_maxindex ( node ) ) ;
shift = node - > shift ;
if ( shift > 0 )
assert ( maxindex > shift_maxindex ( shift - RADIX_TREE_MAP_SHIFT ) ) ;
else
assert ( maxindex > 0 ) ;
2016-03-18 00:21:45 +03:00
}