diff options
Diffstat (limited to 'include/linux/moduleparam.h')
| -rw-r--r-- | include/linux/moduleparam.h | 288 | 
1 files changed, 221 insertions, 67 deletions
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 82a9124f7d75..9d2f1837b3d8 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -31,20 +31,23 @@ static const char __module_cat(name,__LINE__)[]				  \  struct kernel_param; -/* Returns 0, or -errno.  arg is in kp->arg. */ -typedef int (*param_set_fn)(const char *val, struct kernel_param *kp); -/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */ -typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp); +struct kernel_param_ops { +	/* Returns 0, or -errno.  arg is in kp->arg. */ +	int (*set)(const char *val, const struct kernel_param *kp); +	/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */ +	int (*get)(char *buffer, const struct kernel_param *kp); +	/* Optional function to free kp->arg when module unloaded. */ +	void (*free)(void *arg); +};  /* Flag bits for kernel_param.flags */  #define KPARAM_ISBOOL		2  struct kernel_param {  	const char *name; +	const struct kernel_param_ops *ops;  	u16 perm;  	u16 flags; -	param_set_fn set; -	param_get_fn get;  	union {  		void *arg;  		const struct kparam_string *str; @@ -63,12 +66,67 @@ struct kparam_array  {  	unsigned int max;  	unsigned int *num; -	param_set_fn set; -	param_get_fn get; +	const struct kernel_param_ops *ops;  	unsigned int elemsize;  	void *elem;  }; +/** + * module_param - typesafe helper for a module/cmdline parameter + * @value: the variable to alter, and exposed parameter name. + * @type: the type of the parameter + * @perm: visibility in sysfs. + * + * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a + * ".") the kernel commandline parameter.  Note that - is changed to _, so + * the user can use "foo-bar=1" even for variable "foo_bar". + * + * @perm is 0 if the the variable is not to appear in sysfs, or 0444 + * for world-readable, 0644 for root-writable, etc.  Note that if it + * is writable, you may need to use kparam_block_sysfs_write() around + * accesses (esp. charp, which can be kfreed when it changes). + * + * The @type is simply pasted to refer to a param_ops_##type and a + * param_check_##type: for convenience many standard types are provided but + * you can create your own by defining those variables. + * + * Standard types are: + *	byte, short, ushort, int, uint, long, ulong + *	charp: a character pointer + *	bool: a bool, values 0/1, y/n, Y/N. + *	invbool: the above, only sense-reversed (N = true). + */ +#define module_param(name, type, perm)				\ +	module_param_named(name, name, type, perm) + +/** + * module_param_named - typesafe helper for a renamed module/cmdline parameter + * @name: a valid C identifier which is the parameter name. + * @value: the actual lvalue to alter. + * @type: the type of the parameter + * @perm: visibility in sysfs. + * + * Usually it's a good idea to have variable names and user-exposed names the + * same, but that's harder if the variable must be non-static or is inside a + * structure.  This allows exposure under a different name. + */ +#define module_param_named(name, value, type, perm)			   \ +	param_check_##type(name, &(value));				   \ +	module_param_cb(name, ¶m_ops_##type, &value, perm);		   \ +	__MODULE_PARM_TYPE(name, #type) + +/** + * module_param_cb - general callback for a module/cmdline parameter + * @name: a valid C identifier which is the parameter name. + * @ops: the set & get operations for this parameter. + * @perm: visibility in sysfs. + * + * The ops can have NULL set or get functions. + */ +#define module_param_cb(name, ops, arg, perm)				      \ +	__module_param_call(MODULE_PARAM_PREFIX,			      \ +			    name, ops, arg, __same_type((arg), bool *), perm) +  /* On alpha, ia64 and ppc64 relocations to global data cannot go into     read-only sections (which is part of respective UNIX ABI on these     platforms). So 'const' makes no sense and even causes compile failures @@ -80,10 +138,8 @@ struct kparam_array  #endif  /* This is the fundamental function for registering boot/module -   parameters.  perm sets the visibility in sysfs: 000 means it's -   not there, read bits mean it's readable, write bits mean it's -   writable. */ -#define __module_param_call(prefix, name, set, get, arg, isbool, perm)	\ +   parameters. */ +#define __module_param_call(prefix, name, ops, arg, isbool, perm)	\  	/* Default value instead of permissions? */			\  	static int __param_perm_check_##name __attribute__((unused)) =	\  	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\ @@ -92,31 +148,87 @@ struct kparam_array  	static struct kernel_param __moduleparam_const __param_##name	\  	__used								\      __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ -	= { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0,	\ -	    set, get, { arg } } +	= { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0,	\ +	    { arg } } + +/* Obsolete - use module_param_cb() */ +#define module_param_call(name, set, get, arg, perm)			\ +	static struct kernel_param_ops __param_ops_##name =		\ +		 { (void *)set, (void *)get };				\ +	__module_param_call(MODULE_PARAM_PREFIX,			\ +			    name, &__param_ops_##name, arg,		\ +			    __same_type(arg, bool *),			\ +			    (perm) + sizeof(__check_old_set_param(set))*0) + +/* We don't get oldget: it's often a new-style param_get_uint, etc. */ +static inline int +__check_old_set_param(int (*oldset)(const char *, struct kernel_param *)) +{ +	return 0; +} -#define module_param_call(name, set, get, arg, perm)			      \ -	__module_param_call(MODULE_PARAM_PREFIX,			      \ -			    name, set, get, arg,			      \ -			    __same_type(*(arg), bool), perm) +/** + * kparam_block_sysfs_write - make sure a parameter isn't written via sysfs. + * @name: the name of the parameter + * + * There's no point blocking write on a paramter that isn't writable via sysfs! + */ +#define kparam_block_sysfs_write(name)			\ +	do {						\ +		BUG_ON(!(__param_##name.perm & 0222));	\ +		__kernel_param_lock();			\ +	} while (0) -/* Helper functions: type is byte, short, ushort, int, uint, long, -   ulong, charp, bool or invbool, or XXX if you define param_get_XXX, -   param_set_XXX and param_check_XXX. */ -#define module_param_named(name, value, type, perm)			   \ -	param_check_##type(name, &(value));				   \ -	module_param_call(name, param_set_##type, param_get_##type, &value, perm); \ -	__MODULE_PARM_TYPE(name, #type) +/** + * kparam_unblock_sysfs_write - allows sysfs to write to a parameter again. + * @name: the name of the parameter + */ +#define kparam_unblock_sysfs_write(name)		\ +	do {						\ +		BUG_ON(!(__param_##name.perm & 0222));	\ +		__kernel_param_unlock();		\ +	} while (0) -#define module_param(name, type, perm)				\ -	module_param_named(name, name, type, perm) +/** + * kparam_block_sysfs_read - make sure a parameter isn't read via sysfs. + * @name: the name of the parameter + * + * This also blocks sysfs writes. + */ +#define kparam_block_sysfs_read(name)			\ +	do {						\ +		BUG_ON(!(__param_##name.perm & 0444));	\ +		__kernel_param_lock();			\ +	} while (0) + +/** + * kparam_unblock_sysfs_read - allows sysfs to read a parameter again. + * @name: the name of the parameter + */ +#define kparam_unblock_sysfs_read(name)			\ +	do {						\ +		BUG_ON(!(__param_##name.perm & 0444));	\ +		__kernel_param_unlock();		\ +	} while (0) + +#ifdef CONFIG_SYSFS +extern void __kernel_param_lock(void); +extern void __kernel_param_unlock(void); +#else +static inline void __kernel_param_lock(void) +{ +} +static inline void __kernel_param_unlock(void) +{ +} +#endif  #ifndef MODULE  /**   * core_param - define a historical core kernel parameter.   * @name: the name of the cmdline and sysfs parameter (often the same as var)   * @var: the variable - * @type: the type (for param_set_##type and param_get_##type) + * @type: the type of the parameter   * @perm: visibility in sysfs   *   * core_param is just like module_param(), but cannot be modular and @@ -126,23 +238,32 @@ struct kparam_array   */  #define core_param(name, var, type, perm)				\  	param_check_##type(name, &(var));				\ -	__module_param_call("", name, param_set_##type, param_get_##type, \ +	__module_param_call("", name, ¶m_ops_##type,		\  			    &var, __same_type(var, bool), perm)  #endif /* !MODULE */ -/* Actually copy string: maxlen param is usually sizeof(string). */ +/** + * module_param_string - a char array parameter + * @name: the name of the parameter + * @string: the string variable + * @len: the maximum length of the string, incl. terminator + * @perm: visibility in sysfs. + * + * This actually copies the string when it's set (unlike type charp). + * @len is usually just sizeof(string). + */  #define module_param_string(name, string, len, perm)			\  	static const struct kparam_string __param_string_##name		\  		= { len, string };					\  	__module_param_call(MODULE_PARAM_PREFIX, name,			\ -			    param_set_copystring, param_get_string,	\ +			    ¶m_ops_string,				\  			    .str = &__param_string_##name, 0, perm);	\  	__MODULE_PARM_TYPE(name, "string")  /* Called on module insert or kernel boot */  extern int parse_args(const char *name,  		      char *args, -		      struct kernel_param *params, +		      const struct kernel_param *params,  		      unsigned num,  		      int (*unknown)(char *param, char *val)); @@ -162,72 +283,105 @@ static inline void destroy_params(const struct kernel_param *params,  #define __param_check(name, p, type) \  	static inline type *__check_##name(void) { return(p); } -extern int param_set_byte(const char *val, struct kernel_param *kp); -extern int param_get_byte(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_byte; +extern int param_set_byte(const char *val, const struct kernel_param *kp); +extern int param_get_byte(char *buffer, const struct kernel_param *kp);  #define param_check_byte(name, p) __param_check(name, p, unsigned char) -extern int param_set_short(const char *val, struct kernel_param *kp); -extern int param_get_short(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_short; +extern int param_set_short(const char *val, const struct kernel_param *kp); +extern int param_get_short(char *buffer, const struct kernel_param *kp);  #define param_check_short(name, p) __param_check(name, p, short) -extern int param_set_ushort(const char *val, struct kernel_param *kp); -extern int param_get_ushort(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_ushort; +extern int param_set_ushort(const char *val, const struct kernel_param *kp); +extern int param_get_ushort(char *buffer, const struct kernel_param *kp);  #define param_check_ushort(name, p) __param_check(name, p, unsigned short) -extern int param_set_int(const char *val, struct kernel_param *kp); -extern int param_get_int(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_int; +extern int param_set_int(const char *val, const struct kernel_param *kp); +extern int param_get_int(char *buffer, const struct kernel_param *kp);  #define param_check_int(name, p) __param_check(name, p, int) -extern int param_set_uint(const char *val, struct kernel_param *kp); -extern int param_get_uint(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_uint; +extern int param_set_uint(const char *val, const struct kernel_param *kp); +extern int param_get_uint(char *buffer, const struct kernel_param *kp);  #define param_check_uint(name, p) __param_check(name, p, unsigned int) -extern int param_set_long(const char *val, struct kernel_param *kp); -extern int param_get_long(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_long; +extern int param_set_long(const char *val, const struct kernel_param *kp); +extern int param_get_long(char *buffer, const struct kernel_param *kp);  #define param_check_long(name, p) __param_check(name, p, long) -extern int param_set_ulong(const char *val, struct kernel_param *kp); -extern int param_get_ulong(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_ulong; +extern int param_set_ulong(const char *val, const struct kernel_param *kp); +extern int param_get_ulong(char *buffer, const struct kernel_param *kp);  #define param_check_ulong(name, p) __param_check(name, p, unsigned long) -extern int param_set_charp(const char *val, struct kernel_param *kp); -extern int param_get_charp(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_charp; +extern int param_set_charp(const char *val, const struct kernel_param *kp); +extern int param_get_charp(char *buffer, const struct kernel_param *kp);  #define param_check_charp(name, p) __param_check(name, p, char *)  /* For historical reasons "bool" parameters can be (unsigned) "int". */ -extern int param_set_bool(const char *val, struct kernel_param *kp); -extern int param_get_bool(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_bool; +extern int param_set_bool(const char *val, const struct kernel_param *kp); +extern int param_get_bool(char *buffer, const struct kernel_param *kp);  #define param_check_bool(name, p)					\  	static inline void __check_##name(void)				\  	{								\ -		BUILD_BUG_ON(!__same_type(*(p), bool) &&		\ -			     !__same_type(*(p), unsigned int) &&	\ -			     !__same_type(*(p), int));			\ +		BUILD_BUG_ON(!__same_type((p), bool *) &&		\ +			     !__same_type((p), unsigned int *) &&	\ +			     !__same_type((p), int *));			\  	} -extern int param_set_invbool(const char *val, struct kernel_param *kp); -extern int param_get_invbool(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_invbool; +extern int param_set_invbool(const char *val, const struct kernel_param *kp); +extern int param_get_invbool(char *buffer, const struct kernel_param *kp);  #define param_check_invbool(name, p) __param_check(name, p, bool) -/* Comma-separated array: *nump is set to number they actually specified. */ +/** + * module_param_array - a parameter which is an array of some type + * @name: the name of the array variable + * @type: the type, as per module_param() + * @nump: optional pointer filled in with the number written + * @perm: visibility in sysfs + * + * Input and output are as comma-separated values.  Commas inside values + * don't work properly (eg. an array of charp). + * + * ARRAY_SIZE(@name) is used to determine the number of elements in the + * array, so the definition must be visible. + */ +#define module_param_array(name, type, nump, perm)		\ +	module_param_array_named(name, name, type, nump, perm) + +/** + * module_param_array_named - renamed parameter which is an array of some type + * @name: a valid C identifier which is the parameter name + * @array: the name of the array variable + * @type: the type, as per module_param() + * @nump: optional pointer filled in with the number written + * @perm: visibility in sysfs + * + * This exposes a different name than the actual variable name.  See + * module_param_named() for why this might be necessary. + */  #define module_param_array_named(name, array, type, nump, perm)		\  	static const struct kparam_array __param_arr_##name		\ -	= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\ +	= { ARRAY_SIZE(array), nump, ¶m_ops_##type,			\  	    sizeof(array[0]), array };					\  	__module_param_call(MODULE_PARAM_PREFIX, name,			\ -			    param_array_set, param_array_get,		\ +			    ¶m_array_ops,				\  			    .arr = &__param_arr_##name,			\  			    __same_type(array[0], bool), perm);		\  	__MODULE_PARM_TYPE(name, "array of " #type) -#define module_param_array(name, type, nump, perm)		\ -	module_param_array_named(name, name, type, nump, perm) - -extern int param_array_set(const char *val, struct kernel_param *kp); -extern int param_array_get(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_array_ops; -extern int param_set_copystring(const char *val, struct kernel_param *kp); -extern int param_get_string(char *buffer, struct kernel_param *kp); +extern struct kernel_param_ops param_ops_string; +extern int param_set_copystring(const char *val, const struct kernel_param *); +extern int param_get_string(char *buffer, const struct kernel_param *kp);  /* for exporting parameters in /sys/parameters */ @@ -235,13 +389,13 @@ struct module;  #if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES)  extern int module_param_sysfs_setup(struct module *mod, -				    struct kernel_param *kparam, +				    const struct kernel_param *kparam,  				    unsigned int num_params);  extern void module_param_sysfs_remove(struct module *mod);  #else  static inline int module_param_sysfs_setup(struct module *mod, -			     struct kernel_param *kparam, +			     const struct kernel_param *kparam,  			     unsigned int num_params)  {  	return 0;  | 
