2016-04-29 20:26:56 +03:00
/*
* Check decoding of move_pages syscall .
*
* Copyright ( c ) 2016 Dmitry V . Levin < ldv @ altlinux . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "tests.h"
# include <sys/syscall.h>
# ifdef __NR_move_pages
# include <errno.h>
# include <stdio.h>
# include <unistd.h>
# define MAX_STRLEN 3
static void
print_page_array ( const void * * const pages ,
const unsigned long count ,
const unsigned int offset )
{
2016-05-08 02:02:36 +03:00
if ( ! count ) {
printf ( " %s " , pages ? " [] " : " NULL " ) ;
return ;
}
2016-04-29 20:26:56 +03:00
if ( count < = offset ) {
printf ( " %p " , pages ) ;
return ;
}
printf ( " [ " ) ;
unsigned long i ;
for ( i = 0 ; i < count ; + + i ) {
if ( i )
printf ( " , " ) ;
if ( i + offset < count ) {
if ( i > = MAX_STRLEN ) {
printf ( " ... " ) ;
break ;
}
} else {
printf ( " %p " , pages + i ) ;
break ;
}
const void * const addr = pages [ i ] ;
if ( addr )
printf ( " %p " , addr ) ;
else
printf ( " NULL " ) ;
}
printf ( " ] " ) ;
}
static void
print_node_array ( const int * const nodes ,
const unsigned long count ,
const unsigned int offset )
{
2016-05-08 02:02:36 +03:00
if ( ! count ) {
printf ( " %s " , nodes ? " [] " : " NULL " ) ;
return ;
}
2016-04-29 20:26:56 +03:00
if ( count < = offset ) {
printf ( " %p " , nodes ) ;
return ;
}
printf ( " [ " ) ;
unsigned long i ;
for ( i = 0 ; i < count ; + + i ) {
if ( i )
printf ( " , " ) ;
if ( i + offset < count ) {
if ( i > = MAX_STRLEN ) {
printf ( " ... " ) ;
break ;
}
} else {
printf ( " %p " , nodes + i ) ;
break ;
}
printf ( " %d " , nodes [ i ] ) ;
}
printf ( " ] " ) ;
}
static void
print_status_array ( const int * const status , const unsigned long count )
{
if ( ! count ) {
2016-05-08 02:02:36 +03:00
printf ( " %s " , status ? " [] " : " NULL " ) ;
2016-04-29 20:26:56 +03:00
return ;
}
printf ( " [ " ) ;
unsigned long i ;
for ( i = 0 ; i < count ; + + i ) {
if ( i )
printf ( " , " ) ;
if ( i > = MAX_STRLEN ) {
printf ( " ... " ) ;
break ;
}
if ( status [ i ] > = 0 ) {
printf ( " %d " , status [ i ] ) ;
} else {
errno = - status [ i ] ;
printf ( " %s " , errno2name ( ) ) ;
}
}
printf ( " ] " ) ;
}
static void
print_stat_pages ( const unsigned long pid , const unsigned long count ,
const void * * const pages , int * const status )
{
const unsigned long flags = ( unsigned long ) 0xfacefeed00000002 ;
long rc = syscall ( __NR_move_pages ,
pid , count , pages , NULL , status , flags ) ;
if ( rc ) {
int saved_errno = errno ;
printf ( " move_pages(%d, %lu, " , ( int ) pid , count ) ;
print_page_array ( pages , count , 0 ) ;
2016-05-08 02:02:36 +03:00
printf ( " , NULL, " ) ;
if ( count )
printf ( " %p " , status ) ;
else
printf ( " [] " ) ;
2016-04-29 20:26:56 +03:00
errno = saved_errno ;
2016-05-08 02:02:36 +03:00
printf ( " , MPOL_MF_MOVE) = %ld %s (%m) \n " ,
rc , errno2name ( ) ) ;
2016-04-29 20:26:56 +03:00
} else {
printf ( " move_pages(%d, %lu, " , ( int ) pid , count ) ;
print_page_array ( pages , count , 0 ) ;
printf ( " , NULL, " ) ;
print_status_array ( status , count ) ;
printf ( " , MPOL_MF_MOVE) = 0 \n " ) ;
}
}
static void
print_move_pages ( const unsigned long pid ,
unsigned long count ,
const unsigned int offset ,
const void * * const pages ,
int * const nodes ,
int * const status )
{
const unsigned long flags = ( unsigned long ) 0xfacefeed00000004 ;
count + = offset ;
long rc = syscall ( __NR_move_pages ,
pid , count , pages , nodes , status , flags ) ;
int saved_errno = errno ;
printf ( " move_pages(%d, %lu, " , ( int ) pid , count ) ;
print_page_array ( pages , count , offset ) ;
printf ( " , " ) ;
print_node_array ( nodes , count , offset ) ;
2016-05-08 02:02:36 +03:00
printf ( " , " ) ;
if ( count )
printf ( " %p " , status ) ;
else
printf ( " [] " ) ;
printf ( " , MPOL_MF_MOVE_ALL) = " ) ;
2016-04-29 20:26:56 +03:00
if ( rc ) {
errno = saved_errno ;
printf ( " %ld %s (%m) \n " , rc , errno2name ( ) ) ;
} else {
puts ( " 0 " ) ;
}
}
int
main ( void )
{
const unsigned long pid =
( unsigned long ) 0xfacefeed00000000 | getpid ( ) ;
unsigned long count = 1 ;
( void ) tail_alloc ( 1 ) ;
const unsigned page_size = get_page_size ( ) ;
const void * const page = tail_alloc ( page_size ) ;
const void * const efault = page + page_size ;
const void * * pages = tail_alloc ( sizeof ( * pages ) ) ;
int * nodes = tail_alloc ( sizeof ( * nodes ) ) ;
int * status = tail_alloc ( sizeof ( * status ) ) ;
( void ) tail_alloc ( 1 ) ;
print_stat_pages ( pid , 0 , pages , status ) ;
print_move_pages ( pid , 0 , 0 , pages , nodes , status ) ;
print_move_pages ( pid , 0 , 1 , pages + 1 , nodes + 1 , status + 1 ) ;
* pages = page ;
print_stat_pages ( pid , count , pages , status ) ;
* nodes = 0xdeadbee1 ;
print_move_pages ( pid , count , 0 , pages , nodes , status ) ;
print_move_pages ( pid , count , 1 , pages , nodes , status ) ;
+ + count ;
- - status ;
* ( - - pages ) = efault ;
print_stat_pages ( pid , count , pages , status ) ;
* ( - - nodes ) = 0xdeadbee2 ;
print_move_pages ( pid , count , 0 , pages , nodes , status ) ;
print_move_pages ( pid , count , 1 , pages , nodes , status ) ;
+ + count ;
- - status ;
* ( - - pages ) = nodes ;
print_stat_pages ( pid , count , pages , status ) ;
* ( - - nodes ) = 0xdeadbee3 ;
print_move_pages ( pid , count , 0 , pages , nodes , status ) ;
print_move_pages ( pid , count , 1 , pages , nodes , status ) ;
+ + count ;
- - status ;
* ( - - pages ) = status ;
print_stat_pages ( pid , count , pages , status ) ;
* ( - - nodes ) = 0xdeadbee4 ;
print_move_pages ( pid , count , 0 , pages , nodes , status ) ;
print_move_pages ( pid , count , 1 , pages , nodes , status ) ;
puts ( " +++ exited with 0 +++ " ) ;
return 0 ;
}
# else
SKIP_MAIN_UNDEFINED ( " __NR_move_pages " )
# endif