From: Rusty Russell Currently, only module parameters in loaded modules are exported in /sys/modules/, while those of "modules" built into the kernel can be set by the kernel command line, but not read or set via sysfs. - move module parameters from /sys/modules/$(module_name)/$(parameter_name) to /sys/modules/$(module_name)/parameters/$(parameter_name) - remove dummy kernel_param for exporting refcnt, add "struct module *"-based attribute instead - also export module paramters for "modules" which are built into the kernel, so parameters are always accessible at /sys/modules/$(KBUILD_MODNAME)/$(parameter_name) Signed-off-by: Rusty Russell (modified) Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton --- 25-akpm/include/linux/module.h | 38 +-- 25-akpm/include/linux/moduleparam.h | 11 + 25-akpm/kernel/module.c | 134 ++---------- 25-akpm/kernel/params.c | 391 ++++++++++++++++++++++++++++++++++++ 4 files changed, 449 insertions(+), 125 deletions(-) diff -puN include/linux/module.h~builtin-module-parameters-in-sysfs-too include/linux/module.h --- 25/include/linux/module.h~builtin-module-parameters-in-sysfs-too Wed Oct 20 15:56:13 2004 +++ 25-akpm/include/linux/module.h Wed Oct 20 15:56:13 2004 @@ -44,6 +44,20 @@ struct modversion_info char name[MODULE_NAME_LEN]; }; +struct module; + +struct module_attribute { + struct attribute attr; + ssize_t (*show)(struct module *, char *); + ssize_t (*store)(struct module *, const char *, size_t count); +}; + +struct module_kobject +{ + struct kobject kobj; + struct module *mod; +}; + /* These are either module local, or the kernel's dummy ones. */ extern int init_module(void); extern void cleanup_module(void); @@ -59,6 +73,8 @@ void sort_extable(struct exception_table struct exception_table_entry *finish); void sort_main_extable(void); +extern struct subsystem module_subsys; + #ifdef MODULE #define ___module_cat(a,b) __mod_ ## a ## b #define __module_cat(a,b) ___module_cat(a,b) @@ -206,23 +222,6 @@ enum module_state MODULE_STATE_GOING, }; -/* sysfs stuff */ -struct module_attribute -{ - struct attribute attr; - struct kernel_param *param; -}; - -struct module_kobject -{ - /* Everyone should have one of these. */ - struct kobject kobj; - - /* We always have refcnt, we may have others from module_param(). */ - unsigned int num_attributes; - struct module_attribute attr[0]; -}; - /* Similar stuff for section attributes. */ #define MODULE_SECT_NAME_LEN 32 struct module_sect_attr @@ -238,6 +237,7 @@ struct module_sections struct module_sect_attr attrs[0]; }; +struct param_kobject; struct module { @@ -251,6 +251,7 @@ struct module /* Sysfs stuff. */ struct module_kobject *mkobj; + struct param_kobject *params_kobject; /* Exported symbols */ const struct kernel_symbol *syms; @@ -302,9 +303,6 @@ struct module /* Destruction function. */ void (*exit)(void); - - /* Fake kernel param for refcnt. */ - struct kernel_param refcnt_param; #endif #ifdef CONFIG_KALLSYMS diff -puN include/linux/moduleparam.h~builtin-module-parameters-in-sysfs-too include/linux/moduleparam.h --- 25/include/linux/moduleparam.h~builtin-module-parameters-in-sysfs-too Wed Oct 20 15:56:13 2004 +++ 25-akpm/include/linux/moduleparam.h Wed Oct 20 15:56:13 2004 @@ -152,4 +152,15 @@ int param_array(const char *name, void *elem, int elemsize, int (*set)(const char *, struct kernel_param *kp), int *num); + +/* for exporting parameters in /sys/parameters */ + +struct module; + +extern int module_param_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params); + +extern void module_param_sysfs_remove(struct module *mod); + #endif /* _LINUX_MODULE_PARAMS_H */ diff -puN kernel/module.c~builtin-module-parameters-in-sysfs-too kernel/module.c --- 25/kernel/module.c~builtin-module-parameters-in-sysfs-too Wed Oct 20 15:56:13 2004 +++ 25-akpm/kernel/module.c Wed Oct 20 15:56:13 2004 @@ -369,22 +369,6 @@ static inline void percpu_modcopy(void * } #endif /* CONFIG_SMP */ -static int add_attribute(struct module *mod, struct kernel_param *kp) -{ - struct module_attribute *a; - int retval; - - a = &mod->mkobj->attr[mod->mkobj->num_attributes]; - a->attr.name = (char *)kp->name; - a->attr.owner = mod; - a->attr.mode = kp->perm; - a->param = kp; - retval = sysfs_create_file(&mod->mkobj->kobj, &a->attr); - if (!retval) - mod->mkobj->num_attributes++; - return retval; -} - #ifdef CONFIG_MODULE_UNLOAD /* Init the unload section of the module. */ static void module_unload_init(struct module *mod) @@ -665,22 +649,16 @@ void symbol_put_addr(void *addr) } EXPORT_SYMBOL_GPL(symbol_put_addr); -static int refcnt_get_fn(char *buffer, struct kernel_param *kp) +static int show_refcnt(struct module *mod, char *buffer) { - struct module *mod = container_of(kp, struct module, refcnt_param); - - /* sysfs holds one reference. */ - return sprintf(buffer, "%u", module_refcount(mod)-1); + /* sysfs holds a reference */ + return sprintf(buffer, "%u\n", module_refcount(mod)-1); } -static inline int sysfs_unload_setup(struct module *mod) -{ - mod->refcnt_param.name = "refcnt"; - mod->refcnt_param.perm = 0444; - mod->refcnt_param.get = refcnt_get_fn; - - return add_attribute(mod, &mod->refcnt_param); -} +static struct module_attribute refcnt = { + .attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE }, + .show = show_refcnt, +}; #else /* !CONFIG_MODULE_UNLOAD */ static void print_unload_info(struct seq_file *m, struct module *mod) @@ -708,10 +686,6 @@ sys_delete_module(const char __user *nam return -ENOSYS; } -static inline int sysfs_unload_setup(struct module *mod) -{ - return 0; -} #endif /* CONFIG_MODULE_UNLOAD */ #ifdef CONFIG_OBSOLETE_MODPARM @@ -1050,72 +1024,33 @@ static inline void remove_sect_attrs(str #endif /* CONFIG_KALLSYMS */ - - -#define to_module_attr(n) container_of(n, struct module_attribute, attr); - -static ssize_t module_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) +#ifdef CONFIG_MODULE_UNLOAD +static inline int module_add_refcnt_attr(struct module *mod) { - int count; - struct module_attribute *attribute = to_module_attr(attr); - - if (!attribute->param->get) - return -EPERM; - - count = attribute->param->get(buf, attribute->param); - if (count > 0) { - strcat(buf, "\n"); - ++count; - } - return count; + return sysfs_create_file(&mod->mkobj->kobj, &refcnt.attr); } - -/* sysfs always hands a nul-terminated string in buf. We rely on that. */ -static ssize_t module_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t len) +static void module_remove_refcnt_attr(struct module *mod) { - int err; - struct module_attribute *attribute = to_module_attr(attr); - - if (!attribute->param->set) - return -EPERM; - - err = attribute->param->set(buf, attribute->param); - if (!err) - return len; - return err; + return sysfs_remove_file(&mod->mkobj->kobj, &refcnt.attr); } - -static struct sysfs_ops module_sysfs_ops = { - .show = module_attr_show, - .store = module_attr_store, -}; - -static void module_kobj_release(struct kobject *kobj) +#else +static inline int module_add_refcnt_attr(struct module *mod) +{ + return 0; +} +static void module_remove_refcnt_attr(struct module *mod) { - kfree(container_of(kobj, struct module_kobject, kobj)); } +#endif -static struct kobj_type module_ktype = { - .sysfs_ops = &module_sysfs_ops, - .release = &module_kobj_release, -}; -static decl_subsys(module, &module_ktype, NULL); static int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params) { - unsigned int i; int err; - /* We overallocate: not every param is in sysfs, and maybe no refcnt */ - mod->mkobj = kmalloc(sizeof(*mod->mkobj) - + sizeof(mod->mkobj->attr[0]) * (num_params+1), - GFP_KERNEL); + mod->mkobj = kmalloc(sizeof(struct module_kobject), GFP_KERNEL); if (!mod->mkobj) return -ENOMEM; @@ -1124,27 +1059,22 @@ static int mod_sysfs_setup(struct module if (err) goto out; kobj_set_kset_s(mod->mkobj, module_subsys); + mod->mkobj->mod = mod; err = kobject_register(&mod->mkobj->kobj); if (err) goto out; - mod->mkobj->num_attributes = 0; + err = module_add_refcnt_attr(mod); + if (err) + goto out_unreg; - for (i = 0; i < num_params; i++) { - if (kparam[i].perm) { - err = add_attribute(mod, &kparam[i]); - if (err) - goto out_unreg; - } - } - err = sysfs_unload_setup(mod); + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg; + return 0; out_unreg: - for (i = 0; i < mod->mkobj->num_attributes; i++) - sysfs_remove_file(&mod->mkobj->kobj,&mod->mkobj->attr[i].attr); /* Calls module_kobj_release */ kobject_unregister(&mod->mkobj->kobj); return err; @@ -1155,9 +1085,9 @@ out: static void mod_kobject_remove(struct module *mod) { - unsigned int i; - for (i = 0; i < mod->mkobj->num_attributes; i++) - sysfs_remove_file(&mod->mkobj->kobj,&mod->mkobj->attr[i].attr); + module_remove_refcnt_attr(mod); + module_param_sysfs_remove(mod); + /* Calls module_kobj_release */ kobject_unregister(&mod->mkobj->kobj); } @@ -2183,9 +2113,3 @@ EXPORT_SYMBOL(module_remove_driver); void struct_module(struct module *mod) { return; } EXPORT_SYMBOL(struct_module); #endif - -static int __init modules_init(void) -{ - return subsystem_register(&module_subsys); -} -__initcall(modules_init); diff -puN kernel/params.c~builtin-module-parameters-in-sysfs-too kernel/params.c --- 25/kernel/params.c~builtin-module-parameters-in-sysfs-too Wed Oct 20 15:56:13 2004 +++ 25-akpm/kernel/params.c Wed Oct 20 15:56:13 2004 @@ -15,11 +15,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include #include #include +#include +#include #if 0 #define DEBUGP printk @@ -346,6 +349,394 @@ int param_get_string(char *buffer, struc return strlcpy(buffer, kps->string, kps->maxlen); } +/* sysfs output in /sys/modules/XYZ/parameters/ */ + +extern struct kernel_param __start___param[], __stop___param[]; + +#define MAX_KBUILD_MODNAME KOBJ_NAME_LEN + +struct param_attribute +{ + struct attribute attr; + struct kernel_param *param; +}; + +struct param_kobject +{ + struct kobject kobj; + + unsigned int num_attributes; + struct param_attribute attr[0]; +}; + +#define to_param_attr(n) container_of(n, struct param_attribute, attr); + +static ssize_t param_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + int count; + struct param_attribute *attribute = to_param_attr(attr); + + if (!attribute->param->get) + return -EPERM; + + count = attribute->param->get(buf, attribute->param); + 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 kobject *kobj, + struct attribute *attr, + const char *buf, size_t len) +{ + int err; + struct param_attribute *attribute = to_param_attr(attr); + + if (!attribute->param->set) + return -EPERM; + + err = attribute->param->set(buf, attribute->param); + if (!err) + return len; + return err; +} + + +static struct sysfs_ops param_sysfs_ops = { + .show = param_attr_show, + .store = param_attr_store, +}; + +static void param_kobj_release(struct kobject *kobj) +{ + kfree(container_of(kobj, struct param_kobject, kobj)); +} + +static struct kobj_type param_ktype = { + .sysfs_ops = ¶m_sysfs_ops, + .release = ¶m_kobj_release, +}; + +static struct kset param_kset = { + .subsys = &module_subsys, + .ktype = ¶m_ktype, +}; + +#ifdef CONFIG_MODULES +#define __modinit +#else +#define __modinit __init +#endif + +/* + * param_add_attribute - actually adds an parameter to sysfs + * @mod: owner of parameter + * @pk: param_kobject the attribute shall be assigned to. + * One per module, one per KBUILD_MODNAME. + * @kp: kernel_param to be added + * @skip: offset where the parameter name start in kp->name. + * Needed for built-in modules + * + * Fill in data into appropriate &pk->attr[], and create sysfs file. + */ +static __modinit int param_add_attribute(struct module *mod, + struct param_kobject *pk, + struct kernel_param *kp, + unsigned int skip) +{ + struct param_attribute *a; + int err; + + a = &pk->attr[pk->num_attributes]; + a->attr.name = (char *) &kp->name[skip]; + a->attr.owner = mod; + a->attr.mode = kp->perm; + a->param = kp; + err = sysfs_create_file(&pk->kobj, &a->attr); + if (!err) + pk->num_attributes++; + return err; +} + +/* + * param_sysfs_remove - remove sysfs support for one module or KBUILD_MODNAME + * @pk: struct param_kobject which is to be removed + * + * Called when an error in registration occurs or a module is removed + * from the system. + */ +static __modinit void param_sysfs_remove(struct param_kobject *pk) +{ + unsigned int i; + for (i = 0; i < pk->num_attributes; i++) + sysfs_remove_file(&pk->kobj,&pk->attr[i].attr); + + /* Calls param_kobj_release */ + kobject_unregister(&pk->kobj); +} + + +/* + * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME + * @mk: struct module_kobject (contains parent kobject) + * @kparam: array of struct kernel_param, the actual parameter definitions + * @num_params: number of entries in array + * @name_skip: offset where the parameter name start in kparam[].name. Needed for built-in "modules" + * + * Create a kobject for a (per-module) group of parameters, and create files + * in sysfs. A pointer to the param_kobject is returned on success, + * NULL if there's no parameter to export, or other ERR_PTR(err). + */ +static __modinit struct param_kobject * +param_sysfs_setup(struct module_kobject *mk, + struct kernel_param *kparam, + unsigned int num_params, + unsigned int name_skip) +{ + struct param_kobject *pk; + unsigned int valid_attrs = 0; + unsigned int i; + int err; + + for (i=0; ikobj, "parameters"); + if (err) + goto out; + + pk->kobj.kset = ¶m_kset; + pk->kobj.parent = &mk->kobj; + err = kobject_register(&pk->kobj); + if (err) + goto out; + + for (i = 0; i < num_params; i++) { + if (kparam[i].perm) { + err = param_add_attribute(mk->mod, pk, + &kparam[i], name_skip); + if (err) + goto out_unreg; + } + } + + return pk; + +out_unreg: + param_sysfs_remove(pk); + return ERR_PTR(err); + +out: + kfree(pk); + return ERR_PTR(err); +} + + +#ifdef CONFIG_MODULES + +/* + * module_param_sysfs_setup - setup sysfs support for one module + * @mod: module + * @kparam: module parameters (array) + * @num_params: number of module parameters + * + * Adds sysfs entries for module parameters, and creates a link from + * /sys/module/[mod->name]/parameters to /sys/parameters/[mod->name]/ + */ +int module_param_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) +{ + struct param_kobject *pk; + + pk = param_sysfs_setup(mod->mkobj, kparam, num_params, 0); + if (IS_ERR(pk)) + return PTR_ERR(pk); + + mod->params_kobject = pk; + return 0; +} + +/* + * 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) +{ + if (mod->params_kobject) { + param_sysfs_remove(mod->params_kobject); + mod->params_kobject = NULL; + } +} +#endif + +/* + * kernel_param_sysfs_setup - wrapper for built-in params support + */ +static void __init kernel_param_sysfs_setup(const char *name, + struct kernel_param *kparam, + unsigned int num_params, + unsigned int name_skip) +{ + struct module_kobject *mk; + + mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL); + memset(mk, 0, sizeof(struct module_kobject)); + + mk->mod = THIS_MODULE; + kobj_set_kset_s(mk, module_subsys); + kobject_set_name(&mk->kobj, name); + kobject_register(&mk->kobj); + + /* no need to keep the kobject if no parameter is exported */ + if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) + kobject_unregister(&mk->kobj); +} + +/* + * param_sysfs_builtin - add contents in /sys/parameters for built-in modules + * + * 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, + * and for all who have the same, call kernel_param_sysfs_setup. + */ +static void __init param_sysfs_builtin(void) +{ + struct kernel_param *kp, *kp_begin = NULL; + unsigned int i, name_len, count = 0; + char modname[MAX_KBUILD_MODNAME + 1] = ""; + + for (i=0; i < __stop___param - __start___param; i++) { + char *dot; + + kp = &__start___param[i]; + + /* We do not handle args without periods. */ + dot = memchr(kp->name, '.', MAX_KBUILD_MODNAME); + if (!dot) { + DEBUGP("couldn't find period in %s\n", kp->name); + continue; + } + name_len = dot - kp->name; + + /* new kbuild_modname? */ + if (strlen(modname) != name_len + || strncmp(modname, kp->name, name_len) != 0) { + /* add a new kobject for previous kernel_params. */ + if (count) + kernel_param_sysfs_setup(modname, + kp_begin, + count, + strlen(modname)+1); + + strncpy(modname, kp->name, name_len); + modname[name_len] = '\0'; + count = 0; + kp_begin = kp; + } + count++; + } + + /* last kernel_params need to be registered as well */ + if (count) + kernel_param_sysfs_setup(modname, kp_begin, count, + strlen(modname)+1); +} + + +/* module-related sysfs stuff */ +#ifdef CONFIG_MODULES + +#define to_module_attr(n) container_of(n, struct module_attribute, attr); +#define to_module_kobject(n) container_of(n, struct module_kobject, kobj); + +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) + return -EPERM; + + if (!try_module_get(mk->mod)) + return -ENODEV; + + ret = attribute->show(mk->mod, buf); + + module_put(mk->mod); + + return ret; +} + +static struct sysfs_ops module_sysfs_ops = { + .show = module_attr_show, + .store = NULL, +}; + +#else +static struct sysfs_ops module_sysfs_ops = { + .show = NULL, + .store = NULL, +}; +#endif + +static void module_kobj_release(struct kobject *kobj) +{ + kfree(container_of(kobj, struct module_kobject, kobj)); +} + +static struct kobj_type module_ktype = { + .sysfs_ops = &module_sysfs_ops, + .release = &module_kobj_release, +}; + +decl_subsys(module, &module_ktype, NULL); + +/* + * param_sysfs_init - wrapper for built-in params support + */ +static int __init param_sysfs_init(void) +{ + subsystem_register(&module_subsys); + kobject_set_name(¶m_kset.kobj, "parameters"); + kset_init(¶m_kset); + + param_sysfs_builtin(); + + return 0; +} +__initcall(param_sysfs_init); + EXPORT_SYMBOL(param_set_byte); EXPORT_SYMBOL(param_get_byte); EXPORT_SYMBOL(param_set_short); _