2005-04-17 02:20:36 +04:00
/* Helpers for initial module or kernel cmdline parsing
Copyright ( C ) 2001 Rusty Russell .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/err.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
2009-07-06 19:11:22 +04:00
# include <linux/ctype.h>
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:19 +04:00
/* Protects all parameters, and incidentally kmalloced_param list. */
static DEFINE_MUTEX ( param_lock ) ;
2010-08-12 09:04:18 +04:00
/* This just allows us to keep track of which parameters are kmalloced. */
struct kmalloced_param {
struct list_head list ;
char val [ ] ;
} ;
static LIST_HEAD ( kmalloced_params ) ;
static void * kmalloc_parameter ( unsigned int size )
{
struct kmalloced_param * p ;
p = kmalloc ( sizeof ( * p ) + size , GFP_KERNEL ) ;
if ( ! p )
return NULL ;
list_add ( & p - > list , & kmalloced_params ) ;
return p - > val ;
}
/* Does nothing if parameter wasn't kmalloced above. */
static void maybe_kfree_parameter ( void * param )
{
struct kmalloced_param * p ;
list_for_each_entry ( p , & kmalloced_params , list ) {
if ( p - > val = = param ) {
list_del ( & p - > list ) ;
kfree ( p ) ;
break ;
}
}
}
2011-10-10 02:03:37 +04:00
static char dash2underscore ( char c )
2005-04-17 02:20:36 +04:00
{
if ( c = = ' - ' )
return ' _ ' ;
return c ;
}
2011-10-10 02:03:37 +04:00
bool parameqn ( const char * a , const char * b , size_t n )
2005-04-17 02:20:36 +04:00
{
2011-10-10 02:03:37 +04:00
size_t i ;
for ( i = 0 ; i < n ; i + + ) {
if ( dash2underscore ( a [ i ] ) ! = dash2underscore ( b [ i ] ) )
return false ;
}
return true ;
}
bool parameq ( const char * a , const char * b )
{
return parameqn ( a , b , strlen ( a ) + 1 ) ;
2005-04-17 02:20:36 +04:00
}
static int parse_one ( char * param ,
char * val ,
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
const char * doing ,
2010-08-12 09:04:18 +04:00
const struct kernel_param * params ,
2005-04-17 02:20:36 +04:00
unsigned num_params ,
2012-03-26 06:20:51 +04:00
s16 min_level ,
s16 max_level ,
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
int ( * handle_unknown ) ( char * param , char * val ,
const char * doing ) )
2005-04-17 02:20:36 +04:00
{
unsigned int i ;
2010-08-12 09:04:19 +04:00
int err ;
2005-04-17 02:20:36 +04:00
/* Find parameter */
for ( i = 0 ; i < num_params ; i + + ) {
if ( parameq ( param , params [ i ] . name ) ) {
2012-03-26 06:20:51 +04:00
if ( params [ i ] . level < min_level
| | params [ i ] . level > max_level )
return 0 ;
2011-03-31 05:57:33 +04:00
/* No one handled NULL, so do it here. */
2013-08-20 10:03:19 +04:00
if ( ! val & &
! ( params [ i ] . ops - > flags & KERNEL_PARAM_FL_NOARG ) )
2010-08-12 09:04:10 +04:00
return - EINVAL ;
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
pr_debug ( " handling %s with %p \n " , param ,
params [ i ] . ops - > set ) ;
2010-08-12 09:04:19 +04:00
mutex_lock ( & param_lock ) ;
err = params [ i ] . ops - > set ( val , & params [ i ] ) ;
mutex_unlock ( & param_lock ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
}
if ( handle_unknown ) {
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
pr_debug ( " doing %s: %s='%s' \n " , doing , param , val ) ;
return handle_unknown ( param , val , doing ) ;
2005-04-17 02:20:36 +04:00
}
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
pr_debug ( " Unknown argument '%s' \n " , param ) ;
2005-04-17 02:20:36 +04:00
return - ENOENT ;
}
/* You can use " around spaces, but can't escape ". */
/* Hyphens and underscores equivalent in parameter names. */
static char * next_arg ( char * args , char * * param , char * * val )
{
unsigned int i , equals = 0 ;
int in_quote = 0 , quoted = 0 ;
char * next ;
if ( * args = = ' " ' ) {
args + + ;
in_quote = 1 ;
quoted = 1 ;
}
for ( i = 0 ; args [ i ] ; i + + ) {
2009-07-06 19:11:22 +04:00
if ( isspace ( args [ i ] ) & & ! in_quote )
2005-04-17 02:20:36 +04:00
break ;
if ( equals = = 0 ) {
if ( args [ i ] = = ' = ' )
equals = i ;
}
if ( args [ i ] = = ' " ' )
in_quote = ! in_quote ;
}
* param = args ;
if ( ! equals )
* val = NULL ;
else {
args [ equals ] = ' \0 ' ;
* val = args + equals + 1 ;
/* Don't include quotes in value. */
if ( * * val = = ' " ' ) {
( * val ) + + ;
if ( args [ i - 1 ] = = ' " ' )
args [ i - 1 ] = ' \0 ' ;
}
if ( quoted & & args [ i - 1 ] = = ' " ' )
args [ i - 1 ] = ' \0 ' ;
}
if ( args [ i ] ) {
args [ i ] = ' \0 ' ;
next = args + i + 1 ;
} else
next = args + i ;
2005-09-28 08:45:34 +04:00
/* Chew up trailing spaces. */
2009-12-15 05:01:06 +03:00
return skip_spaces ( next ) ;
2005-04-17 02:20:36 +04:00
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
int parse_args ( const char * doing ,
2005-04-17 02:20:36 +04:00
char * args ,
2010-08-12 09:04:18 +04:00
const struct kernel_param * params ,
2005-04-17 02:20:36 +04:00
unsigned num ,
2012-03-26 06:20:51 +04:00
s16 min_level ,
s16 max_level ,
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
int ( * unknown ) ( char * param , char * val , const char * doing ) )
2005-04-17 02:20:36 +04:00
{
char * param , * val ;
2005-09-28 08:45:34 +04:00
/* Chew leading spaces */
2009-12-15 05:01:06 +03:00
args = skip_spaces ( args ) ;
2005-09-28 08:45:34 +04:00
2012-05-03 21:57:37 +04:00
if ( * args )
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
pr_debug ( " doing %s, parsing ARGS: '%s' \n " , doing , args ) ;
2005-04-17 02:20:36 +04:00
while ( * args ) {
int ret ;
2007-01-06 03:36:20 +03:00
int irq_was_disabled ;
2005-04-17 02:20:36 +04:00
args = next_arg ( args , & param , & val ) ;
2007-01-06 03:36:20 +03:00
irq_was_disabled = irqs_disabled ( ) ;
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
ret = parse_one ( param , val , doing , params , num ,
2012-03-26 06:20:51 +04:00
min_level , max_level , unknown ) ;
2012-05-04 04:22:44 +04:00
if ( irq_was_disabled & & ! irqs_disabled ( ) )
pr_warn ( " %s: option '%s' enabled irq's! \n " ,
doing , param ) ;
2005-04-17 02:20:36 +04:00
switch ( ret ) {
case - ENOENT :
2012-05-04 04:22:44 +04:00
pr_err ( " %s: Unknown parameter `%s' \n " , doing , param ) ;
2005-04-17 02:20:36 +04:00
return ret ;
case - ENOSPC :
2012-05-04 04:22:44 +04:00
pr_err ( " %s: `%s' too large for parameter `%s' \n " ,
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
doing , val ? : " " , param ) ;
2005-04-17 02:20:36 +04:00
return ret ;
case 0 :
break ;
default :
2012-05-04 04:22:44 +04:00
pr_err ( " %s: `%s' invalid for parameter `%s' \n " ,
params: add 3rd arg to option handler callback signature
Add a 3rd arg, named "doing", to unknown-options callbacks invoked
from parse_args(). The arg is passed as:
"Booting kernel" from start_kernel(),
initcall_level_names[i] from do_initcall_level(),
mod->name from load_module(), via parse_args(), parse_one()
parse_args() already has the "name" parameter, which is renamed to
"doing" to better reflect current uses 1,2 above. parse_args() passes
it to an altered parse_one(), which now passes it down into the
unknown option handler callbacks.
The mod->name will be needed to handle dyndbg for loadable modules,
since params passed by modprobe are not qualified (they do not have a
"$modname." prefix), and by the time the unknown-param callback is
called, the module name is not otherwise available.
Minor tweaks:
Add param-name to parse_one's pr_debug(), current message doesnt
identify the param being handled, add it.
Add a pr_info to print current level and level_name of the initcall,
and number of registered initcalls at that level. This adds 7 lines
to dmesg output, like:
initlevel:6=device, 172 registered initcalls
Drop "parameters" from initcall_level_names[], its unhelpful in the
pr_info() added above. This array is passed into parse_args() by
do_initcall_level().
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 00:30:34 +04:00
doing , val ? : " " , param ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
}
/* All parsed OK. */
return 0 ;
}
/* Lazy bastard, eh? */
2013-12-04 07:39:38 +04:00
# define STANDARD_PARAM_DEF(name, type, format, strtolfn) \
2010-08-12 09:04:12 +04:00
int param_set_ # # name ( const char * val , const struct kernel_param * kp ) \
2005-04-17 02:20:36 +04:00
{ \
2013-12-04 07:39:38 +04:00
return strtolfn ( val , 0 , ( type * ) kp - > arg ) ; \
2005-04-17 02:20:36 +04:00
} \
2010-08-12 09:04:12 +04:00
int param_get_ # # name ( char * buffer , const struct kernel_param * kp ) \
2005-04-17 02:20:36 +04:00
{ \
2013-08-20 10:05:04 +04:00
return scnprintf ( buffer , PAGE_SIZE , format , \
* ( ( type * ) kp - > arg ) ) ; \
2010-08-12 09:04:11 +04:00
} \
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_ops_ # # name = { \
. set = param_set_ # # name , \
. get = param_get_ # # name , \
} ; \
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_set_ # # name ) ; \
2010-08-12 09:04:12 +04:00
EXPORT_SYMBOL ( param_get_ # # name ) ; \
EXPORT_SYMBOL ( param_ops_ # # name )
2005-04-17 02:20:36 +04:00
2013-12-04 07:39:38 +04:00
STANDARD_PARAM_DEF ( byte , unsigned char , " %hhu " , kstrtou8 ) ;
STANDARD_PARAM_DEF ( short , short , " %hi " , kstrtos16 ) ;
STANDARD_PARAM_DEF ( ushort , unsigned short , " %hu " , kstrtou16 ) ;
STANDARD_PARAM_DEF ( int , int , " %i " , kstrtoint ) ;
STANDARD_PARAM_DEF ( uint , unsigned int , " %u " , kstrtouint ) ;
STANDARD_PARAM_DEF ( long , long , " %li " , kstrtol ) ;
STANDARD_PARAM_DEF ( ulong , unsigned long , " %lu " , kstrtoul ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
int param_set_charp ( const char * val , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
if ( strlen ( val ) > 1024 ) {
2012-05-04 04:22:44 +04:00
pr_err ( " %s: string parameter too long \n " , kp - > name ) ;
2005-04-17 02:20:36 +04:00
return - ENOSPC ;
}
2010-08-12 09:04:18 +04:00
maybe_kfree_parameter ( * ( char * * ) kp - > arg ) ;
/* This is a hack. We can't kmalloc in early boot, and we
2009-03-31 23:05:29 +04:00
* don ' t need to ; this mangled commandline is preserved . */
if ( slab_is_available ( ) ) {
2010-08-12 09:04:18 +04:00
* ( char * * ) kp - > arg = kmalloc_parameter ( strlen ( val ) + 1 ) ;
2009-10-29 17:56:17 +03:00
if ( ! * ( char * * ) kp - > arg )
2009-03-31 23:05:29 +04:00
return - ENOMEM ;
2010-08-12 09:04:18 +04:00
strcpy ( * ( char * * ) kp - > arg , val ) ;
2009-03-31 23:05:29 +04:00
} else
* ( const char * * ) kp - > arg = val ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_set_charp ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
int param_get_charp ( char * buffer , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2013-08-20 10:05:04 +04:00
return scnprintf ( buffer , PAGE_SIZE , " %s " , * ( ( char * * ) kp - > arg ) ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_get_charp ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:18 +04:00
static void param_free_charp ( void * arg )
{
maybe_kfree_parameter ( * ( ( char * * ) arg ) ) ;
}
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_ops_charp = {
. set = param_set_charp ,
. get = param_get_charp ,
2010-08-12 09:04:18 +04:00
. free = param_free_charp ,
2010-08-12 09:04:12 +04:00
} ;
EXPORT_SYMBOL ( param_ops_charp ) ;
2009-06-13 07:46:57 +04:00
/* Actually could be a bool or an int, for historical reasons. */
2010-08-12 09:04:12 +04:00
int param_set_bool ( const char * val , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
/* No equals means "set"... */
if ( ! val ) val = " 1 " ;
/* One of =[yYnN01] */
2012-03-26 06:20:51 +04:00
return strtobool ( val , kp - > arg ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_set_bool ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
int param_get_bool ( char * buffer , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
/* Y and N chosen as being relatively non-coder friendly */
2012-03-26 06:20:51 +04:00
return sprintf ( buffer , " %c " , * ( bool * ) kp - > arg ? ' Y ' : ' N ' ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_get_bool ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_ops_bool = {
2013-08-20 10:03:19 +04:00
. flags = KERNEL_PARAM_FL_NOARG ,
2010-08-12 09:04:12 +04:00
. set = param_set_bool ,
. get = param_get_bool ,
} ;
EXPORT_SYMBOL ( param_ops_bool ) ;
2009-06-13 07:46:57 +04:00
/* This one must be bool. */
2010-08-12 09:04:12 +04:00
int param_set_invbool ( const char * val , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2009-06-13 07:46:57 +04:00
int ret ;
bool boolval ;
2007-10-17 10:29:34 +04:00
struct kernel_param dummy ;
2005-04-17 02:20:36 +04:00
2007-10-17 10:29:34 +04:00
dummy . arg = & boolval ;
2005-04-17 02:20:36 +04:00
ret = param_set_bool ( val , & dummy ) ;
if ( ret = = 0 )
2009-06-13 07:46:53 +04:00
* ( bool * ) kp - > arg = ! boolval ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_set_invbool ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
int param_get_invbool ( char * buffer , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2009-06-13 07:46:53 +04:00
return sprintf ( buffer , " %c " , ( * ( bool * ) kp - > arg ) ? ' N ' : ' Y ' ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_get_invbool ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_ops_invbool = {
. set = param_set_invbool ,
. get = param_get_invbool ,
} ;
EXPORT_SYMBOL ( param_ops_invbool ) ;
2012-01-13 03:02:17 +04:00
int param_set_bint ( const char * val , const struct kernel_param * kp )
{
struct kernel_param boolkp ;
bool v ;
int ret ;
/* Match bool exactly, by re-using it. */
boolkp = * kp ;
boolkp . arg = & v ;
ret = param_set_bool ( val , & boolkp ) ;
if ( ret = = 0 )
* ( int * ) kp - > arg = v ;
return ret ;
}
EXPORT_SYMBOL ( param_set_bint ) ;
struct kernel_param_ops param_ops_bint = {
2013-08-20 10:03:19 +04:00
. flags = KERNEL_PARAM_FL_NOARG ,
2012-01-13 03:02:17 +04:00
. set = param_set_bint ,
. get = param_get_int ,
} ;
EXPORT_SYMBOL ( param_ops_bint ) ;
2007-05-08 11:28:50 +04:00
/* We break the rule and mangle the string. */
2006-03-25 14:07:06 +03:00
static int param_array ( const char * name ,
const char * val ,
unsigned int min , unsigned int max ,
void * elem , int elemsize ,
2010-08-12 09:04:12 +04:00
int ( * set ) ( const char * , const struct kernel_param * kp ) ,
2012-03-26 06:20:51 +04:00
s16 level ,
2008-02-06 12:37:50 +03:00
unsigned int * num )
2005-04-17 02:20:36 +04:00
{
int ret ;
struct kernel_param kp ;
char save ;
/* Get the name right for errors. */
kp . name = name ;
kp . arg = elem ;
2012-03-26 06:20:51 +04:00
kp . level = level ;
2005-04-17 02:20:36 +04:00
* num = 0 ;
/* We expect a comma-separated list of values. */
do {
int len ;
if ( * num = = max ) {
2012-05-04 04:22:44 +04:00
pr_err ( " %s: can only take %i arguments \n " , name , max ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
len = strcspn ( val , " , " ) ;
/* nul-terminate and parse */
save = val [ len ] ;
( ( char * ) val ) [ len ] = ' \0 ' ;
2010-08-12 09:04:19 +04:00
BUG_ON ( ! mutex_is_locked ( & param_lock ) ) ;
2005-04-17 02:20:36 +04:00
ret = set ( val , & kp ) ;
if ( ret ! = 0 )
return ret ;
kp . arg + = elemsize ;
val + = len + 1 ;
( * num ) + + ;
} while ( save = = ' , ' ) ;
if ( * num < min ) {
2012-05-04 04:22:44 +04:00
pr_err ( " %s: needs at least %i arguments \n " , name , min ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
return 0 ;
}
2010-08-12 09:04:12 +04:00
static int param_array_set ( const char * val , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2007-10-17 10:29:34 +04:00
const struct kparam_array * arr = kp - > arr ;
[PATCH] kernel/param.c: don't use .max when .num is NULL in param_array_set()
there seems to be a bug, at least for me, in kernel/param.c for arrays with
.num == NULL. If .num == NULL, the function param_array_set() uses &.max
for the call to param_array(), wich alters the .max value to the number of
arguments. The result is, you can't set more array arguments as the last
time you set the parameter.
example:
# a module 'example' with
# static int array[10] = { 0, };
# module_param_array(array, int, NULL, 0644);
$ insmod example.ko array=1,2,3
$ cat /sys/module/example/parameters/array
1,2,3
$ echo "4,3,2,1" > /sys/module/example/parameters/array
$ dmesg | tail -n 1
kernel: array: can take only 3 arguments
Signed-off-by: Bert Wesarg <wesarg@informatik.uni-halle.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-04-17 02:25:42 +04:00
unsigned int temp_num ;
2005-04-17 02:20:36 +04:00
return param_array ( kp - > name , val , 1 , arr - > max , arr - > elem ,
2012-03-26 06:20:51 +04:00
arr - > elemsize , arr - > ops - > set , kp - > level ,
2009-10-29 17:56:19 +03:00
arr - > num ? : & temp_num ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-12 09:04:12 +04:00
static int param_array_get ( char * buffer , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
int i , off , ret ;
2007-10-17 10:29:34 +04:00
const struct kparam_array * arr = kp - > arr ;
2005-04-17 02:20:36 +04:00
struct kernel_param p ;
p = * kp ;
for ( i = off = 0 ; i < ( arr - > num ? * arr - > num : arr - > max ) ; i + + ) {
if ( i )
buffer [ off + + ] = ' , ' ;
p . arg = arr - > elem + arr - > elemsize * i ;
2010-08-12 09:04:19 +04:00
BUG_ON ( ! mutex_is_locked ( & param_lock ) ) ;
2010-08-12 09:04:12 +04:00
ret = arr - > ops - > get ( buffer + off , & p ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 )
return ret ;
off + = ret ;
}
buffer [ off ] = ' \0 ' ;
return off ;
}
2010-08-12 09:04:17 +04:00
static void param_array_free ( void * arg )
{
unsigned int i ;
const struct kparam_array * arr = arg ;
if ( arr - > ops - > free )
for ( i = 0 ; i < ( arr - > num ? * arr - > num : arr - > max ) ; i + + )
arr - > ops - > free ( arr - > elem + arr - > elemsize * i ) ;
}
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_array_ops = {
. set = param_array_set ,
. get = param_array_get ,
2010-08-12 09:04:17 +04:00
. free = param_array_free ,
2010-08-12 09:04:12 +04:00
} ;
EXPORT_SYMBOL ( param_array_ops ) ;
int param_set_copystring ( const char * val , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2007-10-17 10:29:34 +04:00
const struct kparam_string * kps = kp - > str ;
2005-04-17 02:20:36 +04:00
if ( strlen ( val ) + 1 > kps - > maxlen ) {
2012-05-04 04:22:44 +04:00
pr_err ( " %s: string doesn't fit in %u chars. \n " ,
2005-04-17 02:20:36 +04:00
kp - > name , kps - > maxlen - 1 ) ;
return - ENOSPC ;
}
strcpy ( kps - > string , val ) ;
return 0 ;
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_set_copystring ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
int param_get_string ( char * buffer , const struct kernel_param * kp )
2005-04-17 02:20:36 +04:00
{
2007-10-17 10:29:34 +04:00
const struct kparam_string * kps = kp - > str ;
2005-04-17 02:20:36 +04:00
return strlcpy ( buffer , kps - > string , kps - > maxlen ) ;
}
2010-08-12 09:04:11 +04:00
EXPORT_SYMBOL ( param_get_string ) ;
2005-04-17 02:20:36 +04:00
2010-08-12 09:04:12 +04:00
struct kernel_param_ops param_ops_string = {
. set = param_set_copystring ,
. get = param_get_string ,
} ;
EXPORT_SYMBOL ( param_ops_string ) ;
2005-04-17 02:20:36 +04:00
/* sysfs output in /sys/modules/XYZ/parameters/ */
2010-02-02 02:26:59 +03:00
# define to_module_attr(n) container_of(n, struct module_attribute, attr)
# define to_module_kobject(n) container_of(n, struct module_kobject, kobj)
2005-04-17 02:20:36 +04:00
extern struct kernel_param __start___param [ ] , __stop___param [ ] ;
struct param_attribute
{
struct module_attribute mattr ;
2010-08-12 09:04:12 +04:00
const struct kernel_param * param ;
2005-04-17 02:20:36 +04:00
} ;
struct module_param_attrs
{
2008-10-22 19:00:22 +04:00
unsigned int num ;
2005-04-17 02:20:36 +04:00
struct attribute_group grp ;
struct param_attribute attrs [ 0 ] ;
} ;
2007-02-14 02:19:06 +03:00
# ifdef CONFIG_SYSFS
2010-02-02 02:26:59 +03:00
# define to_param_attr(n) container_of(n, struct param_attribute, mattr)
2005-04-17 02:20:36 +04:00
static ssize_t param_attr_show ( struct module_attribute * mattr ,
2011-07-24 16:36:04 +04:00
struct module_kobject * mk , char * buf )
2005-04-17 02:20:36 +04:00
{
int count ;
struct param_attribute * attribute = to_param_attr ( mattr ) ;
2010-08-12 09:04:12 +04:00
if ( ! attribute - > param - > ops - > get )
2005-04-17 02:20:36 +04:00
return - EPERM ;
2010-08-12 09:04:19 +04:00
mutex_lock ( & param_lock ) ;
2010-08-12 09:04:12 +04:00
count = attribute - > param - > ops - > get ( buf , attribute - > param ) ;
2010-08-12 09:04:19 +04:00
mutex_unlock ( & param_lock ) ;
2005-04-17 02:20:36 +04:00
if ( count > 0 ) {
strcat ( buf , " \n " ) ;
+ + count ;
}
return count ;
}
/* sysfs always hands a nul-terminated string in buf. We rely on that. */
static ssize_t param_attr_store ( struct module_attribute * mattr ,
2011-07-24 16:36:04 +04:00
struct module_kobject * km ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t len )
{
int err ;
struct param_attribute * attribute = to_param_attr ( mattr ) ;
2010-08-12 09:04:12 +04:00
if ( ! attribute - > param - > ops - > set )
2005-04-17 02:20:36 +04:00
return - EPERM ;
2010-08-12 09:04:19 +04:00
mutex_lock ( & param_lock ) ;
2010-08-12 09:04:12 +04:00
err = attribute - > param - > ops - > set ( buf , attribute - > param ) ;
2010-08-12 09:04:19 +04:00
mutex_unlock ( & param_lock ) ;
2005-04-17 02:20:36 +04:00
if ( ! err )
return len ;
return err ;
}
2007-02-14 02:19:06 +03:00
# endif
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_MODULES
# define __modinit
# else
# define __modinit __init
# endif
2007-02-14 02:19:06 +03:00
# ifdef CONFIG_SYSFS
2010-08-12 09:04:19 +04:00
void __kernel_param_lock ( void )
{
mutex_lock ( & param_lock ) ;
}
EXPORT_SYMBOL ( __kernel_param_lock ) ;
void __kernel_param_unlock ( void )
{
mutex_unlock ( & param_lock ) ;
}
EXPORT_SYMBOL ( __kernel_param_unlock ) ;
2005-04-17 02:20:36 +04:00
/*
2008-10-22 19:00:22 +04:00
* add_sysfs_param - add a parameter to sysfs
* @ mk : struct module_kobject
* @ kparam : the actual parameter definition to add to sysfs
* @ name : name of parameter
2005-04-17 02:20:36 +04:00
*
2008-10-22 19:00:22 +04:00
* Create a kobject if for a ( per - module ) parameter if mp NULL , and
* create file in sysfs . Returns an error on out of memory . Always cleans up
* if there ' s an error .
2005-04-17 02:20:36 +04:00
*/
2008-10-22 19:00:22 +04:00
static __modinit int add_sysfs_param ( struct module_kobject * mk ,
2010-08-12 09:04:12 +04:00
const struct kernel_param * kp ,
2008-10-22 19:00:22 +04:00
const char * name )
2005-04-17 02:20:36 +04:00
{
2008-10-22 19:00:22 +04:00
struct module_param_attrs * new ;
struct attribute * * attrs ;
int err , num ;
/* We don't bother calling this with invisible parameters. */
BUG_ON ( ! kp - > perm ) ;
if ( ! mk - > mp ) {
num = 0 ;
attrs = NULL ;
} else {
num = mk - > mp - > num ;
attrs = mk - > mp - > grp . attrs ;
2005-04-17 02:20:36 +04:00
}
2008-10-22 19:00:22 +04:00
/* Enlarge. */
new = krealloc ( mk - > mp ,
sizeof ( * mk - > mp ) + sizeof ( mk - > mp - > attrs [ 0 ] ) * ( num + 1 ) ,
GFP_KERNEL ) ;
if ( ! new ) {
2013-03-14 17:23:11 +04:00
kfree ( attrs ) ;
2008-10-22 19:00:22 +04:00
err = - ENOMEM ;
goto fail ;
}
2013-03-14 17:23:11 +04:00
/* Despite looking like the typical realloc() bug, this is safe.
* We * want * the old ' attrs ' to be freed either way , and we ' ll store
* the new one in the success case . */
2008-10-22 19:00:22 +04:00
attrs = krealloc ( attrs , sizeof ( new - > grp . attrs [ 0 ] ) * ( num + 2 ) , GFP_KERNEL ) ;
if ( ! attrs ) {
err = - ENOMEM ;
goto fail_free_new ;
}
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
/* Sysfs wants everything zeroed. */
memset ( new , 0 , sizeof ( * new ) ) ;
memset ( & new - > attrs [ num ] , 0 , sizeof ( new - > attrs [ num ] ) ) ;
memset ( & attrs [ num ] , 0 , sizeof ( attrs [ num ] ) ) ;
new - > grp . name = " parameters " ;
new - > grp . attrs = attrs ;
/* Tack new one on the end. */
2010-02-12 02:23:05 +03:00
sysfs_attr_init ( & new - > attrs [ num ] . mattr . attr ) ;
2008-10-22 19:00:22 +04:00
new - > attrs [ num ] . param = kp ;
new - > attrs [ num ] . mattr . show = param_attr_show ;
new - > attrs [ num ] . mattr . store = param_attr_store ;
new - > attrs [ num ] . mattr . attr . name = ( char * ) name ;
new - > attrs [ num ] . mattr . attr . mode = kp - > perm ;
new - > num = num + 1 ;
/* Fix up all the pointers, since krealloc can move us */
for ( num = 0 ; num < new - > num ; num + + )
new - > grp . attrs [ num ] = & new - > attrs [ num ] . mattr . attr ;
new - > grp . attrs [ num ] = NULL ;
mk - > mp = new ;
return 0 ;
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
fail_free_new :
kfree ( new ) ;
fail :
mk - > mp = NULL ;
return err ;
}
2005-04-17 02:20:36 +04:00
2008-10-23 23:07:17 +04:00
# ifdef CONFIG_MODULES
2008-10-22 19:00:22 +04:00
static void free_module_param_attrs ( struct module_kobject * mk )
{
kfree ( mk - > mp - > grp . attrs ) ;
kfree ( mk - > mp ) ;
mk - > mp = NULL ;
2005-04-17 02:20:36 +04:00
}
/*
* module_param_sysfs_setup - setup sysfs support for one module
* @ mod : module
* @ kparam : module parameters ( array )
* @ num_params : number of module parameters
*
2008-10-22 19:00:22 +04:00
* Adds sysfs entries for module parameters under
* / sys / module / [ mod - > name ] / parameters /
2005-04-17 02:20:36 +04:00
*/
int module_param_sysfs_setup ( struct module * mod ,
2010-08-12 09:04:12 +04:00
const struct kernel_param * kparam ,
2005-04-17 02:20:36 +04:00
unsigned int num_params )
{
2008-10-22 19:00:22 +04:00
int i , err ;
bool params = false ;
for ( i = 0 ; i < num_params ; i + + ) {
if ( kparam [ i ] . perm = = 0 )
continue ;
err = add_sysfs_param ( & mod - > mkobj , & kparam [ i ] , kparam [ i ] . name ) ;
if ( err )
return err ;
params = true ;
}
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
if ( ! params )
return 0 ;
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
/* Create the param group. */
err = sysfs_create_group ( & mod - > mkobj . kobj , & mod - > mkobj . mp - > grp ) ;
if ( err )
free_module_param_attrs ( & mod - > mkobj ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
/*
* module_param_sysfs_remove - remove sysfs support for one module
* @ mod : module
*
* Remove sysfs entries for module parameters and the corresponding
* kobject .
*/
void module_param_sysfs_remove ( struct module * mod )
{
2008-10-22 19:00:22 +04:00
if ( mod - > mkobj . mp ) {
sysfs_remove_group ( & mod - > mkobj . kobj , & mod - > mkobj . mp - > grp ) ;
2005-04-17 02:20:36 +04:00
/* We are positive that no one is using any param
* attrs at this point . Deallocate immediately . */
2008-10-22 19:00:22 +04:00
free_module_param_attrs ( & mod - > mkobj ) ;
2005-04-17 02:20:36 +04:00
}
}
# endif
2009-03-31 23:05:29 +04:00
void destroy_params ( const struct kernel_param * params , unsigned num )
{
2010-08-12 09:04:17 +04:00
unsigned int i ;
for ( i = 0 ; i < num ; i + + )
if ( params [ i ] . ops - > free )
params [ i ] . ops - > free ( params [ i ] . arg ) ;
2009-03-31 23:05:29 +04:00
}
2010-12-16 01:00:19 +03:00
static struct module_kobject * __init locate_module_kobject ( const char * name )
2005-04-17 02:20:36 +04:00
{
struct module_kobject * mk ;
2008-10-22 19:00:22 +04:00
struct kobject * kobj ;
int err ;
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
kobj = kset_find_obj ( module_kset , name ) ;
if ( kobj ) {
mk = to_module_kobject ( kobj ) ;
} else {
mk = kzalloc ( sizeof ( struct module_kobject ) , GFP_KERNEL ) ;
BUG_ON ( ! mk ) ;
mk - > mod = THIS_MODULE ;
mk - > kobj . kset = module_kset ;
err = kobject_init_and_add ( & mk - > kobj , & module_ktype , NULL ,
" %s " , name ) ;
2011-07-24 16:36:04 +04:00
# ifdef CONFIG_MODULES
if ( ! err )
err = sysfs_create_file ( & mk - > kobj , & module_uevent . attr ) ;
# endif
2008-10-22 19:00:22 +04:00
if ( err ) {
kobject_put ( & mk - > kobj ) ;
2012-05-04 04:22:44 +04:00
pr_crit ( " Adding module '%s' to sysfs failed (%d), the system may be unstable. \n " ,
2010-12-16 01:00:19 +03:00
name , err ) ;
return NULL ;
2008-10-22 19:00:22 +04:00
}
2010-12-16 01:00:19 +03:00
/* So that we hold reference in both cases. */
2008-10-22 19:00:22 +04:00
kobject_get ( & mk - > kobj ) ;
2007-07-30 22:26:38 +04:00
}
2008-10-22 19:00:22 +04:00
2010-12-16 01:00:19 +03:00
return mk ;
}
static void __init kernel_add_sysfs_param ( const char * name ,
struct kernel_param * kparam ,
unsigned int name_skip )
{
struct module_kobject * mk ;
int err ;
mk = locate_module_kobject ( name ) ;
if ( ! mk )
return ;
/* We need to remove old parameters before adding more. */
if ( mk - > mp )
sysfs_remove_group ( & mk - > kobj , & mk - > mp - > grp ) ;
2008-10-22 19:00:22 +04:00
/* These should not fail at boot. */
err = add_sysfs_param ( mk , kparam , kparam - > name + name_skip ) ;
BUG_ON ( err ) ;
err = sysfs_create_group ( & mk - > kobj , & mk - > mp - > grp ) ;
BUG_ON ( err ) ;
2007-01-15 22:22:02 +03:00
kobject_uevent ( & mk - > kobj , KOBJ_ADD ) ;
2008-10-22 19:00:22 +04:00
kobject_put ( & mk - > kobj ) ;
2005-04-17 02:20:36 +04:00
}
/*
2013-07-02 10:05:11 +04:00
* param_sysfs_builtin - add sysfs parameters for built - in modules
2005-04-17 02:20:36 +04:00
*
* Add module_parameters to sysfs for " modules " built into the kernel .
*
* The " module " name ( KBUILD_MODNAME ) is stored before a dot , the
* " parameter " name is stored behind a dot in kernel_param - > name . So ,
* extract the " module " name for all built - in kernel_param - eters ,
2008-10-22 19:00:22 +04:00
* and for all who have the same , call kernel_add_sysfs_param .
2005-04-17 02:20:36 +04:00
*/
static void __init param_sysfs_builtin ( void )
{
2008-10-22 19:00:22 +04:00
struct kernel_param * kp ;
unsigned int name_len ;
char modname [ MODULE_NAME_LEN ] ;
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
for ( kp = __start___param ; kp < __stop___param ; kp + + ) {
2005-04-17 02:20:36 +04:00
char * dot ;
2008-10-22 19:00:22 +04:00
if ( kp - > perm = = 0 )
continue ;
2005-04-17 02:20:36 +04:00
2008-10-22 19:00:22 +04:00
dot = strchr ( kp - > name , ' . ' ) ;
2005-04-17 02:20:36 +04:00
if ( ! dot ) {
2008-10-22 19:00:23 +04:00
/* This happens for core_param() */
strcpy ( modname , " kernel " ) ;
name_len = 0 ;
} else {
name_len = dot - kp - > name + 1 ;
strlcpy ( modname , kp - > name , name_len ) ;
2005-04-17 02:20:36 +04:00
}
2008-10-22 19:00:23 +04:00
kernel_add_sysfs_param ( modname , kp , name_len ) ;
2005-04-17 02:20:36 +04:00
}
}
2010-12-16 01:00:19 +03:00
ssize_t __modver_version_show ( struct module_attribute * mattr ,
2011-07-24 16:36:04 +04:00
struct module_kobject * mk , char * buf )
2010-12-16 01:00:19 +03:00
{
struct module_version_attribute * vattr =
container_of ( mattr , struct module_version_attribute , mattr ) ;
2013-08-20 10:05:04 +04:00
return scnprintf ( buf , PAGE_SIZE , " %s \n " , vattr - > version ) ;
2010-12-16 01:00:19 +03:00
}
2011-02-08 03:02:25 +03:00
extern const struct module_version_attribute * __start___modver [ ] ;
extern const struct module_version_attribute * __stop___modver [ ] ;
2010-12-16 01:00:19 +03:00
static void __init version_sysfs_builtin ( void )
{
2011-02-08 03:02:25 +03:00
const struct module_version_attribute * * p ;
2010-12-16 01:00:19 +03:00
struct module_kobject * mk ;
int err ;
2011-02-08 03:02:25 +03:00
for ( p = __start___modver ; p < __stop___modver ; p + + ) {
const struct module_version_attribute * vattr = * p ;
2010-12-16 01:00:19 +03:00
mk = locate_module_kobject ( vattr - > module_name ) ;
if ( mk ) {
err = sysfs_create_file ( & mk - > kobj , & vattr - > mattr . attr ) ;
kobject_uevent ( & mk - > kobj , KOBJ_ADD ) ;
kobject_put ( & mk - > kobj ) ;
}
}
}
2005-04-17 02:20:36 +04:00
/* module-related sysfs stuff */
static ssize_t module_attr_show ( struct kobject * kobj ,
struct attribute * attr ,
char * buf )
{
struct module_attribute * attribute ;
struct module_kobject * mk ;
int ret ;
attribute = to_module_attr ( attr ) ;
mk = to_module_kobject ( kobj ) ;
if ( ! attribute - > show )
2005-04-29 10:27:34 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
2011-07-24 16:36:04 +04:00
ret = attribute - > show ( attribute , mk , buf ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static ssize_t module_attr_store ( struct kobject * kobj ,
struct attribute * attr ,
const char * buf , size_t len )
{
struct module_attribute * attribute ;
struct module_kobject * mk ;
int ret ;
attribute = to_module_attr ( attr ) ;
mk = to_module_kobject ( kobj ) ;
if ( ! attribute - > store )
2005-04-29 10:27:34 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
2011-07-24 16:36:04 +04:00
ret = attribute - > store ( attribute , mk , buf , len ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2010-01-19 04:58:23 +03:00
static const struct sysfs_ops module_sysfs_ops = {
2005-04-17 02:20:36 +04:00
. show = module_attr_show ,
. store = module_attr_store ,
} ;
2007-01-18 15:26:15 +03:00
static int uevent_filter ( struct kset * kset , struct kobject * kobj )
{
struct kobj_type * ktype = get_ktype ( kobj ) ;
if ( ktype = = & module_ktype )
return 1 ;
return 0 ;
}
2009-12-31 16:52:51 +03:00
static const struct kset_uevent_ops module_uevent_ops = {
2007-01-18 15:26:15 +03:00
. filter = uevent_filter ,
} ;
2007-11-01 20:39:50 +03:00
struct kset * module_kset ;
2007-04-14 00:15:19 +04:00
int module_sysfs_initialized ;
2005-04-17 02:20:36 +04:00
2013-09-03 11:03:57 +04:00
static void module_kobj_release ( struct kobject * kobj )
{
struct module_kobject * mk = to_module_kobject ( kobj ) ;
complete ( mk - > kobj_completion ) ;
}
2007-11-01 20:39:50 +03:00
struct kobj_type module_ktype = {
2013-09-03 11:03:57 +04:00
. release = module_kobj_release ,
2005-04-17 02:20:36 +04:00
. sysfs_ops = & module_sysfs_ops ,
} ;
/*
* param_sysfs_init - wrapper for built - in params support
*/
static int __init param_sysfs_init ( void )
{
2007-11-01 20:39:50 +03:00
module_kset = kset_create_and_add ( " module " , & module_uevent_ops , NULL ) ;
if ( ! module_kset ) {
printk ( KERN_WARNING " %s (%d): error creating kset \n " ,
__FILE__ , __LINE__ ) ;
return - ENOMEM ;
2006-09-29 12:58:55 +04:00
}
2007-04-14 00:15:19 +04:00
module_sysfs_initialized = 1 ;
2005-04-17 02:20:36 +04:00
2010-12-16 01:00:19 +03:00
version_sysfs_builtin ( ) ;
2005-04-17 02:20:36 +04:00
param_sysfs_builtin ( ) ;
return 0 ;
}
2006-09-29 12:59:34 +04:00
subsys_initcall ( param_sysfs_init ) ;
2005-04-17 02:20:36 +04:00
2007-11-01 20:39:50 +03:00
# endif /* CONFIG_SYSFS */