2017-11-24 17:00:37 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
* Base infrastructure for Linux - z / VM Monitor Stream , Stage 1.
* Exports appldata_register_ops ( ) and appldata_unregister_ops ( ) for the
* data gathering modules .
*
2009-06-16 12:30:36 +04:00
* Copyright IBM Corp . 2003 , 2009
2005-04-17 02:20:36 +04:00
*
2006-06-29 17:08:35 +04:00
* Author : Gerald Schaefer < gerald . schaefer @ de . ibm . com >
2005-04-17 02:20:36 +04:00
*/
2008-12-25 15:39:41 +03:00
# define KMSG_COMPONENT "appldata"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2017-02-03 13:03:12 +03:00
# include <linux/sched/stat.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/proc_fs.h>
2006-09-29 12:58:41 +04:00
# include <linux/mm.h>
2005-04-17 02:20:36 +04:00
# include <linux/swap.h>
# include <linux/pagemap.h>
# include <linux/sysctl.h>
# include <linux/notifier.h>
# include <linux/cpu.h>
2005-06-05 02:43:33 +04:00
# include <linux/workqueue.h>
2009-06-16 12:30:36 +04:00
# include <linux/suspend.h>
# include <linux/platform_device.h>
2006-09-20 17:59:26 +04:00
# include <asm/appldata.h>
2012-07-20 13:15:08 +04:00
# include <asm/vtimer.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2006-09-20 17:59:26 +04:00
# include <asm/io.h>
# include <asm/smp.h>
2005-04-17 02:20:36 +04: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 */
2009-06-16 12:30:36 +04:00
static struct platform_device * appldata_pdev ;
2005-04-17 02:20:36 +04:00
/*
* / proc entries ( sysctl )
*/
static const char appldata_proc_name [ APPLDATA_PROC_NAME_LENGTH ] = " appldata " ;
2013-10-23 02:29:46 +04:00
static int appldata_timer_handler ( struct ctl_table * ctl , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer , size_t * lenp , loff_t * ppos ) ;
2013-10-23 02:29:46 +04:00
static int appldata_interval_handler ( struct ctl_table * ctl , int write ,
2005-04-17 02:20:36 +04:00
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 ,
2009-11-16 14:11:48 +03:00
. proc_handler = appldata_timer_handler ,
2005-04-17 02:20:36 +04:00
} ,
{
. procname = " interval " ,
. mode = S_IRUGO | S_IWUSR ,
2009-11-16 14:11:48 +03:00
. proc_handler = appldata_interval_handler ,
2005-04-17 02:20:36 +04:00
} ,
2007-11-20 13:13:34 +03:00
{ } ,
2005-04-17 02:20:36 +04: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 13:13:34 +03:00
{ } ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Timer
*/
2012-07-20 13:15:08 +04:00
static struct vtimer_list appldata_timer ;
2005-04-17 02:20:36 +04:00
static DEFINE_SPINLOCK ( appldata_timer_lock ) ;
static int appldata_interval = APPLDATA_CPU_INTERVAL ;
static int appldata_timer_active ;
2009-06-16 12:30:36 +04:00
static int appldata_timer_suspended = 0 ;
2005-04-17 02:20:36 +04:00
/*
2005-06-05 02:43:33 +04:00
* Work queue
2005-04-17 02:20:36 +04:00
*/
2005-06-05 02:43:33 +04:00
static struct workqueue_struct * appldata_wq ;
2006-12-05 22:36:26 +03:00
static void appldata_work_fn ( struct work_struct * work ) ;
static DECLARE_WORK ( appldata_work , appldata_work_fn ) ;
2005-06-05 02:43:33 +04:00
2005-04-17 02:20:36 +04:00
/*
* Ops list
*/
2009-04-23 15:58:07 +04:00
static DEFINE_MUTEX ( appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
static LIST_HEAD ( appldata_ops_list ) ;
2005-06-05 02:43:33 +04:00
/*************************** timer, work, DIAG *******************************/
2005-04-17 02:20:36 +04:00
/*
* appldata_timer_function ( )
*
2005-06-05 02:43:33 +04:00
* schedule work and reschedule timer
2005-04-17 02:20:36 +04:00
*/
2006-10-11 17:31:26 +04:00
static void appldata_timer_function ( unsigned long data )
2005-04-17 02:20:36 +04:00
{
2012-07-20 13:15:08 +04:00
queue_work ( appldata_wq , ( struct work_struct * ) data ) ;
2005-04-17 02:20:36 +04:00
}
/*
2005-06-05 02:43:33 +04:00
* appldata_work_fn ( )
2005-04-17 02:20:36 +04:00
*
* call data gathering function for each ( active ) module
*/
2006-12-05 22:36:26 +03:00
static void appldata_work_fn ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
struct list_head * lh ;
struct appldata_ops * ops ;
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
list_for_each ( lh , & appldata_ops_list ) {
ops = list_entry ( lh , struct appldata_ops , list ) ;
if ( ops - > active = = 1 ) {
ops - > callback ( ops - > data ) ;
}
}
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
}
/*
* appldata_diag ( )
*
* prepare parameter list , issue DIAG 0xDC
*/
2006-06-29 17:08:35 +04:00
int appldata_diag ( char record_nr , u16 function , unsigned long buffer ,
u16 length , char * mod_lvl )
2005-04-17 02:20:36 +04:00
{
2006-09-20 17:59:26 +04:00
struct appldata_product_id id = {
2005-04-17 02:20:36 +04:00
. prod_nr = { 0xD3 , 0xC9 , 0xD5 , 0xE4 ,
2006-09-20 17:59:26 +04:00
0xE7 , 0xD2 , 0xD9 } , /* "LINUXKR" */
. prod_fn = 0xD5D3 , /* "NL" */
. version_nr = 0xF2F6 , /* "26" */
. release_nr = 0xF0F1 , /* "01" */
2005-04-17 02:20:36 +04:00
} ;
2006-09-28 18:55:23 +04:00
id . record_nr = record_nr ;
id . mod_lvl = ( mod_lvl [ 0 ] ) < < 8 | mod_lvl [ 1 ] ;
2006-09-20 17:59:26 +04:00
return appldata_asm ( & id , function , ( void * ) buffer , length ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-05 02:43:33 +04:00
/************************ timer, work, DIAG <END> ****************************/
2005-04-17 02:20:36 +04:00
/****************************** /proc stuff **********************************/
# 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 .
*/
2012-07-20 13:15:08 +04:00
static void __appldata_vtimer_setup ( int cmd )
2005-04-17 02:20:36 +04:00
{
2012-07-20 13:15:08 +04:00
u64 timer_interval = ( u64 ) appldata_interval * 1000 * TOD_MICRO ;
2005-04-17 02:20:36 +04:00
switch ( cmd ) {
case APPLDATA_ADD_TIMER :
if ( appldata_timer_active )
break ;
2012-07-20 13:15:08 +04:00
appldata_timer . expires = timer_interval ;
add_virt_timer_periodic ( & appldata_timer ) ;
2005-04-17 02:20:36 +04:00
appldata_timer_active = 1 ;
break ;
case APPLDATA_DEL_TIMER :
2012-07-20 13:15:08 +04:00
del_virt_timer ( & appldata_timer ) ;
2005-04-17 02:20:36 +04:00
if ( ! appldata_timer_active )
break ;
appldata_timer_active = 0 ;
break ;
case APPLDATA_MOD_TIMER :
if ( ! appldata_timer_active )
break ;
2012-07-20 13:15:08 +04:00
mod_virt_timer_periodic ( & appldata_timer , timer_interval ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* appldata_timer_handler ( )
*
* Start / Stop timer , show status of timer ( 0 = not active , 1 = active )
*/
static int
2013-10-23 02:29:46 +04:00
appldata_timer_handler ( struct ctl_table * ctl , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer , size_t * lenp , loff_t * ppos )
{
2018-07-01 17:59:44 +03:00
int timer_active = appldata_timer_active ;
int zero = 0 ;
int one = 1 ;
int rc ;
struct ctl_table ctl_entry = {
. procname = ctl - > procname ,
. data = & timer_active ,
. maxlen = sizeof ( int ) ,
. extra1 = & zero ,
. extra2 = & one ,
} ;
rc = proc_douintvec_minmax ( & ctl_entry , write , buffer , lenp , ppos ) ;
if ( rc < 0 | | ! write )
return rc ;
2005-04-17 02:20:36 +04:00
spin_lock ( & appldata_timer_lock ) ;
2018-07-01 17:59:44 +03:00
if ( timer_active )
2005-04-17 02:20:36 +04:00
__appldata_vtimer_setup ( APPLDATA_ADD_TIMER ) ;
2018-07-01 17:59:44 +03:00
else
2005-04-17 02:20:36 +04:00
__appldata_vtimer_setup ( APPLDATA_DEL_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
return 0 ;
}
/*
* appldata_interval_handler ( )
*
* Set ( CPU ) timer interval for collection of data ( in milliseconds ) , show
* current timer interval .
*/
static int
2013-10-23 02:29:46 +04:00
appldata_interval_handler ( struct ctl_table * ctl , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer , size_t * lenp , loff_t * ppos )
{
2018-07-01 17:59:44 +03:00
int interval = appldata_interval ;
int one = 1 ;
int rc ;
struct ctl_table ctl_entry = {
. procname = ctl - > procname ,
. data = & interval ,
. maxlen = sizeof ( int ) ,
. extra1 = & one ,
} ;
2005-04-17 02:20:36 +04:00
2018-07-01 17:59:44 +03:00
rc = proc_dointvec_minmax ( & ctl_entry , write , buffer , lenp , ppos ) ;
if ( rc < 0 | | ! write )
return rc ;
2005-04-17 02:20:36 +04:00
spin_lock ( & appldata_timer_lock ) ;
appldata_interval = interval ;
__appldata_vtimer_setup ( APPLDATA_MOD_TIMER ) ;
spin_unlock ( & appldata_timer_lock ) ;
return 0 ;
}
/*
* appldata_generic_handler ( )
*
* Generic start / stop monitoring and DIAG , show status of
* monitoring ( 0 = not in process , 1 = in process )
*/
static int
2013-10-23 02:29:46 +04:00
appldata_generic_handler ( struct ctl_table * ctl , int write ,
2005-04-17 02:20:36 +04:00
void __user * buffer , size_t * lenp , loff_t * ppos )
{
struct appldata_ops * ops = NULL , * tmp_ops ;
struct list_head * lh ;
2018-07-01 17:59:44 +03:00
int rc , found ;
int active ;
int zero = 0 ;
int one = 1 ;
struct ctl_table ctl_entry = {
. data = & active ,
. maxlen = sizeof ( int ) ,
. extra1 = & zero ,
. extra2 = & one ,
} ;
2005-04-17 02:20:36 +04:00
found = 0 ;
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04: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 ) {
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
ops = ctl - > data ;
if ( ! try_module_get ( ops - > owner ) ) { // protect this function
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
2018-07-01 17:59:44 +03:00
active = ops - > active ;
rc = proc_douintvec_minmax ( & ctl_entry , write , buffer , lenp , ppos ) ;
if ( rc < 0 | | ! write ) {
2005-04-17 02:20:36 +04:00
module_put ( ops - > owner ) ;
2018-07-01 17:59:44 +03:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2018-07-01 17:59:44 +03:00
if ( active & & ( ops - > active = = 0 ) ) {
2005-06-05 02:43:33 +04:00
// protect work queue callback
if ( ! try_module_get ( ops - > owner ) ) {
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04: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 17:08:35 +04:00
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
2005-04-17 02:20:36 +04:00
if ( rc ! = 0 ) {
2008-12-25 15:39:41 +03:00
pr_err ( " Starting the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
2005-04-17 02:20:36 +04:00
module_put ( ops - > owner ) ;
2008-07-14 11:59:34 +04:00
} else
2006-06-29 17:08:35 +04:00
ops - > active = 1 ;
2018-07-01 17:59:44 +03:00
} else if ( ! active & & ( ops - > active = = 1 ) ) {
2005-04-17 02:20:36 +04:00
ops - > active = 0 ;
rc = appldata_diag ( ops - > record_nr , APPLDATA_STOP_REC ,
2006-06-29 17:08:35 +04:00
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
2008-07-14 11:59:34 +04:00
if ( rc ! = 0 )
2008-12-25 15:39:41 +03:00
pr_err ( " Stopping the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
2005-04-17 02:20:36 +04:00
module_put ( ops - > owner ) ;
}
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
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 13:10:18 +03:00
if ( ops - > size > APPLDATA_MAX_REC_SIZE )
2007-11-20 13:13:34 +03:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
ops - > ctl_table = kcalloc ( 4 , sizeof ( struct ctl_table ) , GFP_KERNEL ) ;
2007-11-20 13:13:34 +03:00
if ( ! ops - > ctl_table )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
list_add ( & ops - > list , & appldata_ops_list ) ;
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04: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 11:34:09 +03:00
ops - > sysctl_header = register_sysctl_table ( ops - > ctl_table ) ;
2007-11-20 13:13:34 +03:00
if ( ! ops - > sysctl_header )
goto out ;
2005-04-17 02:20:36 +04:00
return 0 ;
2007-11-20 13:13:34 +03:00
out :
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2007-11-20 13:13:34 +03:00
list_del ( & ops - > list ) ;
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2007-11-20 13:13:34 +03:00
kfree ( ops - > ctl_table ) ;
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
/*
* appldata_unregister_ops ( )
*
* update ops list , unregister / proc entries , stop DIAG if necessary
*/
void appldata_unregister_ops ( struct appldata_ops * ops )
{
2009-04-23 15:58:07 +04:00
mutex_lock ( & appldata_ops_mutex ) ;
2005-04-17 02:20:36 +04:00
list_del ( & ops - > list ) ;
2009-04-23 15:58:07 +04:00
mutex_unlock ( & appldata_ops_mutex ) ;
2005-11-04 13:18:40 +03:00
unregister_sysctl_table ( ops - > sysctl_header ) ;
2007-11-20 13:13:34 +03:00
kfree ( ops - > ctl_table ) ;
2005-04-17 02:20:36 +04:00
}
/********************** module-ops management <END> **************************/
2009-06-16 12:30:36 +04:00
/**************************** suspend / resume *******************************/
static int appldata_freeze ( struct device * dev )
{
struct appldata_ops * ops ;
int rc ;
struct list_head * lh ;
spin_lock ( & appldata_timer_lock ) ;
if ( appldata_timer_active ) {
__appldata_vtimer_setup ( APPLDATA_DEL_TIMER ) ;
appldata_timer_suspended = 1 ;
}
spin_unlock ( & appldata_timer_lock ) ;
mutex_lock ( & appldata_ops_mutex ) ;
list_for_each ( lh , & appldata_ops_list ) {
ops = list_entry ( lh , struct appldata_ops , list ) ;
if ( ops - > active = = 1 ) {
rc = appldata_diag ( ops - > record_nr , APPLDATA_STOP_REC ,
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
if ( rc ! = 0 )
pr_err ( " Stopping the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
}
}
mutex_unlock ( & appldata_ops_mutex ) ;
return 0 ;
}
static int appldata_restore ( struct device * dev )
{
struct appldata_ops * ops ;
int rc ;
struct list_head * lh ;
spin_lock ( & appldata_timer_lock ) ;
if ( appldata_timer_suspended ) {
__appldata_vtimer_setup ( APPLDATA_ADD_TIMER ) ;
appldata_timer_suspended = 0 ;
}
spin_unlock ( & appldata_timer_lock ) ;
mutex_lock ( & appldata_ops_mutex ) ;
list_for_each ( lh , & appldata_ops_list ) {
ops = list_entry ( lh , struct appldata_ops , list ) ;
if ( ops - > active = = 1 ) {
ops - > callback ( ops - > data ) ; // init record
rc = appldata_diag ( ops - > record_nr ,
APPLDATA_START_INTERVAL_REC ,
( unsigned long ) ops - > data , ops - > size ,
ops - > mod_lvl ) ;
if ( rc ! = 0 ) {
pr_err ( " Starting the data collection for %s "
" failed with rc=%d \n " , ops - > name , rc ) ;
}
}
}
mutex_unlock ( & appldata_ops_mutex ) ;
return 0 ;
}
static int appldata_thaw ( struct device * dev )
{
return appldata_restore ( dev ) ;
}
2009-12-15 05:00:08 +03:00
static const struct dev_pm_ops appldata_pm_ops = {
2009-06-16 12:30:36 +04:00
. freeze = appldata_freeze ,
. thaw = appldata_thaw ,
. restore = appldata_restore ,
} ;
static struct platform_driver appldata_pdrv = {
. driver = {
. name = " appldata " ,
. pm = & appldata_pm_ops ,
} ,
} ;
/************************* suspend / resume <END> ****************************/
2005-04-17 02:20:36 +04:00
/******************************* init / exit *********************************/
/*
* appldata_init ( )
*
2005-06-05 02:43:33 +04:00
* init timer , register / proc entries
2005-04-17 02:20:36 +04:00
*/
static int __init appldata_init ( void )
{
2012-07-20 13:15:08 +04:00
int rc ;
2014-01-28 21:40:12 +04:00
init_virt_timer ( & appldata_timer ) ;
2012-07-20 13:15:08 +04:00
appldata_timer . function = appldata_timer_function ;
appldata_timer . data = ( unsigned long ) & appldata_work ;
2009-06-16 12:30:36 +04:00
rc = platform_driver_register ( & appldata_pdrv ) ;
if ( rc )
return rc ;
2005-04-17 02:20:36 +04:00
2009-06-16 12:30:36 +04:00
appldata_pdev = platform_device_register_simple ( " appldata " , - 1 , NULL ,
0 ) ;
if ( IS_ERR ( appldata_pdev ) ) {
rc = PTR_ERR ( appldata_pdev ) ;
goto out_driver ;
}
2016-08-30 23:27:20 +03:00
appldata_wq = alloc_ordered_workqueue ( " appldata " , 0 ) ;
2009-06-16 12:30:36 +04:00
if ( ! appldata_wq ) {
rc = - ENOMEM ;
goto out_device ;
}
2005-06-05 02:43:33 +04:00
2007-02-14 11:34:09 +03:00
appldata_sysctl_header = register_sysctl_table ( appldata_dir_table ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2009-06-16 12:30:36 +04:00
out_device :
platform_device_unregister ( appldata_pdev ) ;
out_driver :
platform_driver_unregister ( & appldata_pdrv ) ;
return rc ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 18:11:32 +04:00
__initcall ( appldata_init ) ;
2005-04-17 02:20:36 +04:00
/**************************** init / exit <END> ******************************/
EXPORT_SYMBOL_GPL ( appldata_register_ops ) ;
EXPORT_SYMBOL_GPL ( appldata_unregister_ops ) ;
2006-06-29 17:08:35 +04:00
EXPORT_SYMBOL_GPL ( appldata_diag ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 11:57:27 +04:00
# ifdef CONFIG_SWAP
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL_GPL ( si_swapinfo ) ;
2008-07-14 11:57:27 +04:00
# endif
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL_GPL ( nr_threads ) ;
EXPORT_SYMBOL_GPL ( nr_running ) ;
EXPORT_SYMBOL_GPL ( nr_iowait ) ;