2010-02-10 12:20:07 +03:00
/*
* Range add and subtract
*/
2011-05-25 17:52:21 +04:00
# include <linux/kernel.h>
2010-02-10 12:20:07 +03:00
# include <linux/init.h>
# include <linux/sort.h>
2013-06-14 00:17:02 +04:00
# include <linux/string.h>
2010-02-10 12:20:07 +03:00
# include <linux/range.h>
int add_range ( struct range * range , int az , int nr_range , u64 start , u64 end )
{
2010-02-10 12:20:13 +03:00
if ( start > = end )
2010-02-10 12:20:07 +03:00
return nr_range ;
/* Out of slots: */
if ( nr_range > = az )
return nr_range ;
range [ nr_range ] . start = start ;
range [ nr_range ] . end = end ;
nr_range + + ;
return nr_range ;
}
int add_range_with_merge ( struct range * range , int az , int nr_range ,
u64 start , u64 end )
{
int i ;
2010-02-10 12:20:13 +03:00
if ( start > = end )
2010-02-10 12:20:07 +03:00
return nr_range ;
2013-06-14 00:17:02 +04:00
/* get new start/end: */
2010-02-10 12:20:07 +03:00
for ( i = 0 ; i < nr_range ; i + + ) {
u64 common_start , common_end ;
if ( ! range [ i ] . end )
continue ;
common_start = max ( range [ i ] . start , start ) ;
common_end = min ( range [ i ] . end , end ) ;
2010-02-10 12:20:13 +03:00
if ( common_start > common_end )
2010-02-10 12:20:07 +03:00
continue ;
2013-06-14 00:17:02 +04:00
/* new start/end, will add it back at last */
start = min ( range [ i ] . start , start ) ;
end = max ( range [ i ] . end , end ) ;
2010-02-10 12:20:07 +03:00
2013-06-14 00:17:02 +04:00
memmove ( & range [ i ] , & range [ i + 1 ] ,
( nr_range - ( i + 1 ) ) * sizeof ( range [ i ] ) ) ;
range [ nr_range - 1 ] . start = 0 ;
range [ nr_range - 1 ] . end = 0 ;
nr_range - - ;
i - - ;
2010-02-10 12:20:07 +03:00
}
/* Need to add it: */
return add_range ( range , az , nr_range , start , end ) ;
}
void subtract_range ( struct range * range , int az , u64 start , u64 end )
{
int i , j ;
2010-02-10 12:20:13 +03:00
if ( start > = end )
2010-02-10 12:20:07 +03:00
return ;
for ( j = 0 ; j < az ; j + + ) {
if ( ! range [ j ] . end )
continue ;
if ( start < = range [ j ] . start & & end > = range [ j ] . end ) {
range [ j ] . start = 0 ;
range [ j ] . end = 0 ;
continue ;
}
if ( start < = range [ j ] . start & & end < range [ j ] . end & &
2010-02-10 12:20:13 +03:00
range [ j ] . start < end ) {
range [ j ] . start = end ;
2010-02-10 12:20:07 +03:00
continue ;
}
if ( start > range [ j ] . start & & end > = range [ j ] . end & &
2010-02-10 12:20:13 +03:00
range [ j ] . end > start ) {
range [ j ] . end = start ;
2010-02-10 12:20:07 +03:00
continue ;
}
if ( start > range [ j ] . start & & end < range [ j ] . end ) {
/* Find the new spare: */
for ( i = 0 ; i < az ; i + + ) {
if ( range [ i ] . end = = 0 )
break ;
}
if ( i < az ) {
range [ i ] . end = range [ j ] . end ;
2010-02-10 12:20:13 +03:00
range [ i ] . start = end ;
2010-02-10 12:20:07 +03:00
} else {
2013-05-01 02:27:07 +04:00
pr_err ( " %s: run out of slot in ranges \n " ,
__func__ ) ;
2010-02-10 12:20:07 +03:00
}
2010-02-10 12:20:13 +03:00
range [ j ] . end = start ;
2010-02-10 12:20:07 +03:00
continue ;
}
}
}
static int cmp_range ( const void * x1 , const void * x2 )
{
const struct range * r1 = x1 ;
const struct range * r2 = x2 ;
2015-01-16 08:04:46 +03:00
if ( r1 - > start < r2 - > start )
return - 1 ;
if ( r1 - > start > r2 - > start )
return 1 ;
return 0 ;
2010-02-10 12:20:07 +03:00
}
int clean_sort_range ( struct range * range , int az )
{
2010-11-12 01:05:14 +03:00
int i , j , k = az - 1 , nr_range = az ;
2010-02-10 12:20:07 +03:00
for ( i = 0 ; i < k ; i + + ) {
if ( range [ i ] . end )
continue ;
for ( j = k ; j > i ; j - - ) {
if ( range [ j ] . end ) {
k = j ;
break ;
}
}
if ( j = = i )
break ;
range [ i ] . start = range [ k ] . start ;
range [ i ] . end = range [ k ] . end ;
range [ k ] . start = 0 ;
range [ k ] . end = 0 ;
k - - ;
}
/* count it */
for ( i = 0 ; i < az ; i + + ) {
if ( ! range [ i ] . end ) {
nr_range = i ;
break ;
}
}
/* sort them */
sort ( range , nr_range , sizeof ( struct range ) , cmp_range , NULL ) ;
return nr_range ;
}
void sort_range ( struct range * range , int nr_range )
{
/* sort them */
sort ( range , nr_range , sizeof ( struct range ) , cmp_range , NULL ) ;
}