diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2004-10-25 04:19:51 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-10-25 04:19:51 -0700 |
| commit | 1857599ace885dfb946dbdcc9a754be40a3b9c3c (patch) | |
| tree | 1499c4bc6658437b4a90eaf5b8759d7ed78a72e8 /kernel/params.c | |
| parent | 48ed3c3b2d4ed657c54b1b17cd6cf1ff9c97dcd8 (diff) | |
[PATCH] Builtin Module Parameters in sysfs too
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 <rusty@rustcorp.com.au> (modified)
Signed-off-by: Dominik Brodowski <linux@brodo.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/params.c')
| -rw-r--r-- | kernel/params.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/kernel/params.c b/kernel/params.c index ebb3031cd6cc..45dd451e17c1 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -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 <linux/config.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/device.h> +#include <linux/err.h> #if 0 #define DEBUGP printk @@ -346,6 +349,394 @@ int param_get_string(char *buffer, struct kernel_param *kp) 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; i<num_params; i++) { + if (kparam[i].perm) + valid_attrs++; + } + + if (!valid_attrs) + return NULL; + + pk = kmalloc(sizeof(struct param_kobject) + + sizeof(struct param_attribute) * valid_attrs, + GFP_KERNEL); + if (!pk) + return ERR_PTR(-ENOMEM); + memset(pk, 0, sizeof(struct param_kobject) + + sizeof(struct param_attribute) * valid_attrs); + + err = kobject_set_name(&pk->kobj, "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); |
