2005-04-16 15:20:36 -07:00
/*
* arch / s390 / appldata / appldata_base . c
*
* Base infrastructure for Linux - z / VM Monitor Stream , Stage 1.
* Exports appldata_register_ops ( ) and appldata_unregister_ops ( ) for the
* data gathering modules .
*
2008-07-14 09:59:34 +02:00
* Copyright IBM Corp . 2003 , 2008
2005-04-16 15:20:36 -07:00
*
2006-06-29 15:08:35 +02:00
* Author : Gerald Schaefer < gerald . schaefer @ de . ibm . com >
2005-04-16 15:20:36 -07:00
*/
2008-12-25 13:39:41 +01:00
# define KMSG_COMPONENT "appldata"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/proc_fs.h>
2006-09-29 01:58:41 -07:00
# include <linux/mm.h>
2005-04-16 15:20:36 -07:00
# include <linux/swap.h>
# include <linux/pagemap.h>
# include <linux/sysctl.h>
# include <linux/notifier.h>
# include <linux/cpu.h>
2005-06-04 15:43:33 -07:00
# include <linux/workqueue.h>
2006-09-20 15:59:26 +02:00
# include <asm/appldata.h>
# include <asm/timer.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/smp.h>
2005-04-16 15:20:36 -07:00
# include "appldata.h"
# define APPLDATA_CPU_INTERVAL 10000 / * default (CPU) time for
sampling interval in
milliseconds */
# define TOD_MICRO 0x01000 / * nr. of TOD clock units
for 1 microsecond */
/*
* / proc entries ( sysctl )
*/
static const char appldata_proc_name [ APPLDATA_PROC_NAME_LENGTH ] = " appldata " ;
static int appldata_timer_handler ( ctl_table * ctl , int write , struct file * filp ,
void __user * buffer , size_t * lenp , loff_t * ppos ) ;
static int appldata_interval_handler ( ctl_table * ctl , int write ,
struct file * filp ,
void __user * buffer ,
size_t * lenp , loff_t * ppos ) ;
static struct ctl_table_header * appldata_sysctl_header ;
static struct ctl_table appldata_table [ ] = {
{
. procname = " timer " ,
. mode = S_IRUGO | S_IWUSR ,
. proc_handler = & appldata_timer_handler ,
} ,
{
. procname = " interval " ,
. mode = S_IRUGO | S_IWUSR ,
. proc_handler = & appldata_interval_handler ,
} ,
2007-11-20 11:13:34 +01:00
{ } ,
2005-04-16 15:20:36 -07:00
} ;
static struct ctl_table appldata_dir_table [ ] = {
{
. procname = appldata_proc_name ,
. maxlen = 0 ,
. mode = S_IRUGO | S_IXUGO ,
. child = appldata_table ,
} ,
2007-11-20 11:13:34 +01:00
{ } ,
2005-04-16 15:20:36 -07:00
} ;
/*
* Timer
*/
2007-02-05 21:16:47 +01:00
static DEFINE_PER_CPU ( struct vtimer_list , appldata_timer ) ;
2005-04-16 15:20:36 -07:00
static atomic_t appldata_expire_count = ATOMIC_INIT ( 0 ) ;
static DEFINE_SPINLOCK ( appldata_timer_lock ) ;
static int appldata_interval = APPLDATA_CPU_INTERVAL ;
static int appldata_timer_active ;
/*
2005-06-04 15:43:33 -07:00
* Work queue
2005-04-16 15:20:36 -07:00
*/
2005-06-04 15:43:33 -07:00
static struct workqueue_struct * appldata_wq ;
2006-12-05 19:36:26 +00:00
static void appldata_work_fn ( struct work_struct * work ) ;
static DECLARE_WORK ( appldata_work , appldata_work_fn ) ;
2005-06-04 15:43:33 -07:00
2005-04-16 15:20:36 -07:00
/*
* Ops list
*/
static DEFINE_SPINLOCK ( appldata_ops_lock ) ;
static LIST_HEAD ( appldata_ops_list ) ;
2005-06-04 15:43:33 -07:00
/*************************** timer, work, DIAG *******************************/
2005-04-16 15:20:36 -07:00
/*
* appldata_timer_function ( )
*
2005-06-04 15:43:33 -07:00
* schedule work and reschedule timer
2005-04-16 15:20:36 -07:00
*/
2006-10-11 15:31:26 +02:00
static void appldata_timer_function ( unsigned long data )
2005-04-16 15:20:36 -07:00
{
if ( atomic_dec_and_test ( & appldata_expire_count ) ) {
atomic_set ( & appldata_expire_count , num_online_cpus ( ) ) ;
2005-06-04 15:43:33 -07:00
queue_work ( appldata_wq , ( struct work_struct * ) data ) ;
2005-04-16 15:20:36 -07:00
}
}
/*
2005-06-04 15:43:33 -07:00
* appldata_work_fn ( )
2005-04-16 15:20:36 -07:00
*
* call data gathering function for each ( active ) module
*/
2006-12-05 19:36:26 +00:00
static void appldata_work_fn ( struct work_struct * work )
2005-04-16 15:20:36 -07:00
{
struct list_head * lh ;
struct appldata_ops * ops ;
int i ;
i = 0 ;
2008-05-30 10:03:28 +02:00
get_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & appldata_ops_lock ) ;
list_for_each ( lh , & appldata_ops_list ) {
ops = list_entry ( lh , struct appldata_ops , list ) ;
if ( ops - > active = = 1 ) {
ops - > callback ( ops - > data ) ;
}
}
spin_unlock ( & appldata_ops_lock ) ;
2008-05-30 10:03:28 +02:00
put_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
}
/*
* appldata_diag ( )
*
* prepare parameter list , issue DIAG 0xDC
*/
2006-06-29 15:08:35 +02:00
int appldata_diag ( char record_nr , u16 function , unsigned long buffer ,
u16 length , char * mod_lvl )
2005-04-16 15:20:36 -07:00
{
2006-09-20 15:59:26 +02:00
struct appldata_product_id id = {
2005-04-16 15:20:36 -07:00
. prod_nr = { 0xD3 , 0xC9 , 0xD5 , 0xE4 ,
2006-09-20 15:59:26 +02:00
0xE7 , 0xD2 , 0xD9 } , /* "LINUXKR" */
. prod_fn = 0xD5D3 , /* "NL" */
. version_nr = 0xF2F6 , /* "26" */
. release_nr = 0xF0F1 , /* "01" */
2005-04-16 15:20:36 -07:00
} ;
2006-09-28 16:55:23 +02:00
id . record_nr = record_nr ;
id . mod_lvl = ( mod_lvl [ 0 ] ) < < 8 | mod_lvl [ 1 ] ;
2006-09-20 15:59:26 +02:00
return appldata_asm ( & id , function , ( void * ) buffer , length ) ;
2005-04-16 15:20:36 -07:00
}
2005-06-04 15:43:33 -07:00
/************************ timer, work, DIAG <END> ****************************/
2005-04-16 15:20:36 -07:00
/****************************** /proc stuff **********************************/
/*
* appldata_mod_vtimer_wrap ( )
*
2007-07-27 12:29:08 +02:00
* wrapper function for mod_virt_timer ( ) , because smp_call_function_single ( )
2005-04-16 15:20:36 -07:00
* accepts only one parameter .
*/
static void __appldata_mod_vtimer_wrap ( void * p ) {
struct {
struct vtimer_list * timer ;
u64 expires ;
} * args = p ;
mod_virt_timer ( args - > timer , args - > expires ) ;
}
# define APPLDATA_ADD_TIMER 0
# define APPLDATA_DEL_TIMER 1
# define APPLDATA_MOD_TIMER 2
/*
* __appldata_vtimer_setup ( )
*
* Add , delete or modify virtual timers on all online cpus .
* The caller needs to get the appldata_timer_lock spinlock .
*/
static void
__appldata_vtimer_setup ( int cmd )
{
u64 per_cpu_interval ;
int i ;
switch ( cmd ) {
case APPLDATA_ADD_TIMER :
if ( appldata_timer_active )
break ;
per_cpu_interval = ( u64 ) ( appldata_interval * 1000 /
num_online_cpus ( ) ) * TOD_MICRO ;
for_each_online_cpu ( i ) {
per_cpu ( appldata_timer , i ) . expires = per_cpu_interval ;
2007-07-27 12:29:08 +02:00
smp_call_function_single ( i , add_virt_timer_periodic ,
& per_cpu ( appldata_timer , i ) ,
2008-06-06 11:18:06 +02:00
1 ) ;
2005-04-16 15:20:36 -07:00
}
appldata_timer_active = 1 ;
break ;
case APPLDATA_DEL_TIMER :
for_each_online_cpu ( i )
del_virt_timer ( & per_cpu ( appldata_timer , i ) ) ;
if ( ! appldata_timer_active )
break ;
appldata_timer_active = 0 ;
atomic_set ( & appldata_expire_count , num_online_cpus ( ) ) ;
break ;
case APPLDATA_MOD_TIMER :
per_cpu_interval = ( u64 ) ( appldata_interval * 1000 /
num_online_cpus ( ) ) * TOD_MICRO ;
if ( ! appldata_timer_active )
break ;
for_each_online_cpu ( i ) {
struct {
struct vtimer_list * timer ;
u64 expires ;
} args ;
args . timer = & per_cpu ( appldata_timer , i ) ;
args . expires = per_cpu_interval ;
2007-07-27 12:29:08 +02:00
smp_call_function_single ( i , __appldata_mod_vtimer_wrap ,
2008-06-06 11:18:06 +02:00
& args , 1 ) ;
2005-04-16 15:20:36 -07:00
}
}
}
/*
* appldata_timer_handler ( )
*
* Start / Stop timer , show status of timer ( 0 = not active , 1 = active )
*/
static int
appldata_timer_handler ( ctl_table * ctl , int write , struct file * filp ,
void __user * buffer , size_t * lenp , loff_t * ppos )
{
int len ;
char buf [ 2 ] ;
if ( ! * lenp | | * ppos ) {
* lenp = 0 ;
return 0 ;
}
if ( ! write ) {
len = sprintf ( buf , appldata_timer_active ? " 1 \n " : " 0 \n " ) ;
if ( len > * lenp )
len = * lenp ;
if ( copy_to_user ( buffer , buf , len ) )
return - EFAULT ;
goto out ;
}
len = * lenp ;
if ( copy_from_user ( buf , buffer , len > sizeof ( buf ) ? sizeof ( buf ) : len ) )
return - EFAULT ;
2008-05-30 10:03:28 +02:00
get_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & appldata_timer_lock ) ;
if ( buf [ 0 ] = = ' 1 ' )
__appldata_vtimer_setup ( APPLDATA_ADD_TIMER ) ;
else if ( buf [ 0 ] = = ' 0 ' )
__appldata_vtimer_setup ( APPLDATA_DEL_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
2008-05-30 10:03:28 +02:00
put_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
out :
* lenp = len ;
* ppos + = len ;
return 0 ;
}
/*
* appldata_interval_handler ( )
*
* Set ( CPU ) timer interval for collection of data ( in milliseconds ) , show
* current timer interval .
*/
static int
appldata_interval_handler ( ctl_table * ctl , int write , struct file * filp ,
void __user * buffer , size_t * lenp , loff_t * ppos )
{
int len , interval ;
char buf [ 16 ] ;
if ( ! * lenp | | * ppos ) {
* lenp = 0 ;
return 0 ;
}
if ( ! write ) {
len = sprintf ( buf , " %i \n " , appldata_interval ) ;
if ( len > * lenp )
len = * lenp ;
if ( copy_to_user ( buffer , buf , len ) )
return - EFAULT ;
goto out ;
}
len = * lenp ;
if ( copy_from_user ( buf , buffer , len > sizeof ( buf ) ? sizeof ( buf ) : len ) ) {
return - EFAULT ;
}
2006-10-27 12:39:13 +02:00
interval = 0 ;
2005-04-16 15:20:36 -07:00
sscanf ( buf , " %i " , & interval ) ;
2008-07-14 09:59:34 +02:00
if ( interval < = 0 )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2008-05-30 10:03:28 +02:00
get_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & appldata_timer_lock ) ;
appldata_interval = interval ;
__appldata_vtimer_setup ( APPLDATA_MOD_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
2008-05-30 10:03:28 +02:00
put_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
out :
* lenp = len ;
* ppos + = len ;
return 0 ;
}
/*
* appldata_generic_handler ( )
*
* Generic start / stop monitoring and DIAG , show status of
* monitoring ( 0 = not in process , 1 = in process )
*/
static int
appldata_generic_handler ( ctl_table * ctl , int write , struct file * filp ,
void __user * buffer , size_t * lenp , loff_t * ppos )
{
struct appldata_ops * ops = NULL , * tmp_ops ;
int rc , len , found ;
char buf [ 2 ] ;
struct list_head * lh ;
found = 0 ;
2005-06-04 15:43:33 -07:00
spin_lock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
list_for_each ( lh , & appldata_ops_list ) {
tmp_ops = list_entry ( lh , struct appldata_ops , list ) ;
if ( & tmp_ops - > ctl_table [ 2 ] = = ctl ) {
found = 1 ;
}
}
if ( ! found ) {
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
ops = ctl - > data ;
if ( ! try_module_get ( ops - > owner ) ) { // protect this function
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
if ( ! * lenp | | * ppos ) {
* lenp = 0 ;
module_put ( ops - > owner ) ;
return 0 ;
}
if ( ! write ) {
len = sprintf ( buf , ops - > active ? " 1 \n " : " 0 \n " ) ;
if ( len > * lenp )
len = * lenp ;
if ( copy_to_user ( buffer , buf , len ) ) {
module_put ( ops - > owner ) ;
return - EFAULT ;
}
goto out ;
}
len = * lenp ;
if ( copy_from_user ( buf , buffer ,
len > sizeof ( buf ) ? sizeof ( buf ) : len ) ) {
module_put ( ops - > owner ) ;
return - EFAULT ;
}
2005-06-04 15:43:33 -07:00
spin_lock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
if ( ( buf [ 0 ] = = ' 1 ' ) & & ( ops - > active = = 0 ) ) {
2005-06-04 15:43:33 -07:00
// protect work queue callback
if ( ! try_module_get ( ops - > owner ) ) {
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
module_put ( ops - > owner ) ;
return - ENODEV ;
}
ops - > callback ( ops - > data ) ; // init record
rc = appldata_diag ( ops - > record_nr ,
APPLDATA_START_INTERVAL_REC ,
2006-06-29 15:08:35 +02:00
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
2005-04-16 15:20:36 -07:00
if ( rc ! = 0 ) {
2008-12-25 13:39:41 +01:00
pr_err ( " Starting the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
2005-04-16 15:20:36 -07:00
module_put ( ops - > owner ) ;
2008-07-14 09:59:34 +02:00
} else
2006-06-29 15:08:35 +02:00
ops - > active = 1 ;
2005-04-16 15:20:36 -07:00
} else if ( ( buf [ 0 ] = = ' 0 ' ) & & ( ops - > active = = 1 ) ) {
ops - > active = 0 ;
rc = appldata_diag ( ops - > record_nr , APPLDATA_STOP_REC ,
2006-06-29 15:08:35 +02:00
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
2008-07-14 09:59:34 +02:00
if ( rc ! = 0 )
2008-12-25 13:39:41 +01:00
pr_err ( " Stopping the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
2005-04-16 15:20:36 -07:00
module_put ( ops - > owner ) ;
}
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
out :
* lenp = len ;
* ppos + = len ;
module_put ( ops - > owner ) ;
return 0 ;
}
/*************************** /proc stuff <END> *******************************/
/************************* module-ops management *****************************/
/*
* appldata_register_ops ( )
*
* update ops list , register / proc / sys entries
*/
int appldata_register_ops ( struct appldata_ops * ops )
{
2008-10-28 11:10:18 +01:00
if ( ops - > size > APPLDATA_MAX_REC_SIZE )
2007-11-20 11:13:34 +01:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2007-11-20 11:13:34 +01:00
ops - > ctl_table = kzalloc ( 4 * sizeof ( struct ctl_table ) , GFP_KERNEL ) ;
if ( ! ops - > ctl_table )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2005-06-04 15:43:33 -07:00
spin_lock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
list_add ( & ops - > list , & appldata_ops_list ) ;
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
ops - > ctl_table [ 0 ] . procname = appldata_proc_name ;
ops - > ctl_table [ 0 ] . maxlen = 0 ;
ops - > ctl_table [ 0 ] . mode = S_IRUGO | S_IXUGO ;
ops - > ctl_table [ 0 ] . child = & ops - > ctl_table [ 2 ] ;
ops - > ctl_table [ 2 ] . procname = ops - > name ;
ops - > ctl_table [ 2 ] . mode = S_IRUGO | S_IWUSR ;
ops - > ctl_table [ 2 ] . proc_handler = appldata_generic_handler ;
ops - > ctl_table [ 2 ] . data = ops ;
2007-02-14 00:34:09 -08:00
ops - > sysctl_header = register_sysctl_table ( ops - > ctl_table ) ;
2007-11-20 11:13:34 +01:00
if ( ! ops - > sysctl_header )
goto out ;
2005-04-16 15:20:36 -07:00
return 0 ;
2007-11-20 11:13:34 +01:00
out :
spin_lock ( & appldata_ops_lock ) ;
list_del ( & ops - > list ) ;
spin_unlock ( & appldata_ops_lock ) ;
kfree ( ops - > ctl_table ) ;
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
}
/*
* appldata_unregister_ops ( )
*
* update ops list , unregister / proc entries , stop DIAG if necessary
*/
void appldata_unregister_ops ( struct appldata_ops * ops )
{
2005-06-04 15:43:33 -07:00
spin_lock ( & appldata_ops_lock ) ;
2005-04-16 15:20:36 -07:00
list_del ( & ops - > list ) ;
2005-06-04 15:43:33 -07:00
spin_unlock ( & appldata_ops_lock ) ;
2005-11-04 10:18:40 +00:00
unregister_sysctl_table ( ops - > sysctl_header ) ;
2007-11-20 11:13:34 +01:00
kfree ( ops - > ctl_table ) ;
2005-04-16 15:20:36 -07:00
}
/********************** module-ops management <END> **************************/
/******************************* init / exit *********************************/
2007-06-19 13:10:03 +02:00
static void __cpuinit appldata_online_cpu ( int cpu )
2005-04-16 15:20:36 -07:00
{
init_virt_timer ( & per_cpu ( appldata_timer , cpu ) ) ;
per_cpu ( appldata_timer , cpu ) . function = appldata_timer_function ;
per_cpu ( appldata_timer , cpu ) . data = ( unsigned long )
2005-06-04 15:43:33 -07:00
& appldata_work ;
2005-04-16 15:20:36 -07:00
atomic_inc ( & appldata_expire_count ) ;
spin_lock ( & appldata_timer_lock ) ;
__appldata_vtimer_setup ( APPLDATA_MOD_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
}
2007-10-12 16:11:32 +02:00
static void __cpuinit appldata_offline_cpu ( int cpu )
2005-04-16 15:20:36 -07:00
{
del_virt_timer ( & per_cpu ( appldata_timer , cpu ) ) ;
if ( atomic_dec_and_test ( & appldata_expire_count ) ) {
atomic_set ( & appldata_expire_count , num_online_cpus ( ) ) ;
2005-06-04 15:43:33 -07:00
queue_work ( appldata_wq , & appldata_work ) ;
2005-04-16 15:20:36 -07:00
}
spin_lock ( & appldata_timer_lock ) ;
__appldata_vtimer_setup ( APPLDATA_MOD_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
}
2007-10-12 16:11:31 +02:00
static int __cpuinit appldata_cpu_notify ( struct notifier_block * self ,
unsigned long action ,
void * hcpu )
2005-04-16 15:20:36 -07:00
{
switch ( action ) {
case CPU_ONLINE :
2007-05-09 02:35:10 -07:00
case CPU_ONLINE_FROZEN :
2005-04-16 15:20:36 -07:00
appldata_online_cpu ( ( long ) hcpu ) ;
break ;
case CPU_DEAD :
2007-05-09 02:35:10 -07:00
case CPU_DEAD_FROZEN :
2005-04-16 15:20:36 -07:00
appldata_offline_cpu ( ( long ) hcpu ) ;
break ;
default :
break ;
}
return NOTIFY_OK ;
}
2007-06-19 13:10:03 +02:00
static struct notifier_block __cpuinitdata appldata_nb = {
2005-04-16 15:20:36 -07:00
. notifier_call = appldata_cpu_notify ,
} ;
/*
* appldata_init ( )
*
2005-06-04 15:43:33 -07:00
* init timer , register / proc entries
2005-04-16 15:20:36 -07:00
*/
static int __init appldata_init ( void )
{
int i ;
2005-06-04 15:43:33 -07:00
appldata_wq = create_singlethread_workqueue ( " appldata " ) ;
2008-07-14 09:59:34 +02:00
if ( ! appldata_wq )
2005-06-04 15:43:33 -07:00
return - ENOMEM ;
2008-05-30 10:03:28 +02:00
get_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
for_each_online_cpu ( i )
appldata_online_cpu ( i ) ;
2008-05-30 10:03:28 +02:00
put_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
/* Register cpu hotplug notifier */
2006-07-30 03:03:37 -07:00
register_hotcpu_notifier ( & appldata_nb ) ;
2005-04-16 15:20:36 -07:00
2007-02-14 00:34:09 -08:00
appldata_sysctl_header = register_sysctl_table ( appldata_dir_table ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-10-12 16:11:32 +02:00
__initcall ( appldata_init ) ;
2005-04-16 15:20:36 -07:00
/**************************** init / exit <END> ******************************/
EXPORT_SYMBOL_GPL ( appldata_register_ops ) ;
EXPORT_SYMBOL_GPL ( appldata_unregister_ops ) ;
2006-06-29 15:08:35 +02:00
EXPORT_SYMBOL_GPL ( appldata_diag ) ;
2005-04-16 15:20:36 -07:00
2008-07-14 09:57:27 +02:00
# ifdef CONFIG_SWAP
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL_GPL ( si_swapinfo ) ;
2008-07-14 09:57:27 +02:00
# endif
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL_GPL ( nr_threads ) ;
EXPORT_SYMBOL_GPL ( nr_running ) ;
EXPORT_SYMBOL_GPL ( nr_iowait ) ;