lkml.org 
[lkml]   [2004]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[RFC] [PATCH 1/2] export module parameters in sysfs for modules _and_ built-in code
Create a new /sys top-level directory named "parameters", and make all
to-be-sysfs-exported module parameters available as attributes to kobjects.
Currently, only module parameters in _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.

For modules, a symlink

brodo@mondschein param $ ls -l /sys/module/ehci_hcd/ | grep param
lrwxrwxrwx 1 brodo brodo 0 1. Aug 17:50 parameters -> ../../parameters/ehci_hcd

is added. Removal of double module parameters export for modules is sent in a second
patch, so the diffstat

include/linux/module.h | 2
kernel/module.c | 14 +
kernel/params.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 393 insertions(+)

looks worse than it is.

Much of this work is based on the current code for modules only to be found in
linux/kernel/module.c

Signed-off-by: Dominik Brodowski <linux@brodo.de>

diff -ruN linux-original/include/linux/module.h linux/include/linux/module.h
--- linux-original/include/linux/module.h 2004-08-01 18:40:25.836963920 +0200
+++ linux/include/linux/module.h 2004-08-01 18:39:01.019858080 +0200
@@ -240,6 +240,7 @@
struct module_sect_attr attrs[0];
};

+struct param_kobject;

struct module
{
@@ -253,6 +254,7 @@

/* Sysfs stuff. */
struct module_kobject *mkobj;
+ struct param_kobject *params_kobject;

/* Exported symbols */
const struct kernel_symbol *syms;
diff -ruN linux-original/kernel/module.c linux/kernel/module.c
--- linux-original/kernel/module.c 2004-08-01 18:40:25.939948264 +0200
+++ linux/kernel/module.c 2004-08-01 18:39:01.097846224 +0200
@@ -1131,6 +1131,12 @@
};
static decl_subsys(module, &module_ktype, NULL);

+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);
+
static int mod_sysfs_setup(struct module *mod,
struct kernel_param *kparam,
unsigned int num_params)
@@ -1166,6 +1172,11 @@
err = sysfs_unload_setup(mod);
if (err)
goto out_unreg;
+
+ err = module_param_sysfs_setup(mod, kparam, num_params);
+ if (err)
+ goto out_unreg;
+
return 0;

out_unreg:
@@ -1182,6 +1193,9 @@
static void mod_kobject_remove(struct module *mod)
{
unsigned int i;
+
+ module_param_sysfs_remove(mod);
+
for (i = 0; i < mod->mkobj->num_attributes; i++)
sysfs_remove_file(&mod->mkobj->kobj,&mod->mkobj->attr[i].attr);
/* Calls module_kobj_release */
diff -ruN linux-original/kernel/params.c linux/kernel/params.c
--- linux-original/kernel/params.c 2004-08-01 18:40:25.948946896 +0200
+++ linux/kernel/params.c 2004-08-01 18:39:58.243158816 +0200
@@ -20,6 +20,8 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/config.h>

#if 0
#define DEBUGP printk
@@ -339,6 +341,381 @@
return 0;
}

+
+
+/* sysfs output in /sys/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));
+ return;
+}
+
+static struct kobj_type param_ktype = {
+ .sysfs_ops = &param_sysfs_ops,
+ .release = &param_kobj_release,
+};
+
+static decl_subsys(parameters, &param_ktype, NULL);
+
+
+#ifdef CONFIG_MODULE
+#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 retval;
+
+ 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;
+ retval = sysfs_create_file(&pk->kobj, &a->attr);
+ if (!retval)
+ pk->num_attributes++;
+ return retval;
+}
+
+
+/*
+ * param_sysfs_remove - remove sysfs support for one module or KBUILD_MODNAME
+ * @pk: struct param_kobject which is to be removed
+ * @embed: where reference to struct param_kobject is stored, if anywhere
+ *
+ * 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,
+ struct param_kobject **embed)
+{
+ 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);
+
+ if (embed)
+ *embed = NULL;
+}
+
+
+/*
+ * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME
+ * @name: name of module
+ * @mod: owner of module
+ * @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"
+ * @embed: where to save allocated struct param_kobject, if anywhere
+ *
+ * Create a kobject for a (per-module) group of parameters, and create files in sysfs.
+ */
+static __modinit int param_sysfs_setup(char *name,
+ struct module *mod,
+ struct kernel_param *kparam,
+ unsigned int num_params,
+ unsigned int name_skip,
+ struct param_kobject **embed)
+{
+ 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 ENODEV;
+
+ pk = kmalloc(sizeof(struct param_kobject) + sizeof(struct param_attribute) * valid_attrs, GFP_KERNEL);
+ if (!pk)
+ return -ENOMEM;
+ memset(pk, 0, sizeof(struct param_kobject) + sizeof(struct param_attribute) * valid_attrs);
+
+ err = kobject_set_name(&pk->kobj, name);
+ if (err)
+ goto out;
+
+ kobj_set_kset_s(pk, parameters_subsys);
+ err = kobject_register(&pk->kobj);
+ if (err)
+ goto out;
+
+ for (i = 0; i < num_params; i++) {
+ if (kparam[i].perm) {
+ err = param_add_attribute(mod, pk, &kparam[i], name_skip);
+ if (err)
+ goto out_unreg;
+ }
+ }
+
+ if (embed)
+ *embed = pk;
+
+ return 0;
+
+out_unreg:
+ param_sysfs_remove(pk, embed);
+ return err;
+
+out:
+ kfree(pk);
+ return 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)
+{
+ int err;
+
+ err = param_sysfs_setup(mod->name, mod, kparam, num_params, 0, &mod->params_kobject);
+ if (err == ENODEV)
+ return 0;
+ if (err)
+ return (err);
+
+ err = sysfs_create_link(&mod->mkobj->kobj, &mod->params_kobject->kobj, "parameters");
+ if (err)
+ goto out_unreg;
+
+ return 0;
+
+out_unreg:
+ param_sysfs_remove(mod->params_kobject, &mod->params_kobject);
+ return err;
+
+}
+
+
+/*
+ * module_param_sysfs_remove - remove sysfs support for one module
+ * @mod: module
+ *
+ * Remove sysfs entries for module parameters, and remove the link from
+ * /sys/module/[mod->name]/parameters to /sys/parameters/[mod->name]/
+ */
+void module_param_sysfs_remove(struct module *mod)
+{
+ struct param_kobject *pk;
+
+ pk = mod->params_kobject;
+ if (!pk)
+ return;
+
+ sysfs_remove_link(&mod->mkobj->kobj, "parameters");
+
+ param_sysfs_remove(pk, &mod->params_kobject);
+}
+
+#endif
+
+
+/*
+ * kernel_param_sysfs_setup - wrapper for built-in params support
+ */
+static int __init kernel_param_sysfs_setup(char *name,
+ struct kernel_param *kparam,
+ unsigned int num_params,
+ unsigned int name_skip)
+{
+ return param_sysfs_setup(name, THIS_MODULE, kparam, num_params, name_skip, NULL);
+}
+
+
+/*
+ * 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 int __init param_sysfs_builtin(void)
+{
+ int err = 0;
+ struct kernel_param *kp;
+ struct kernel_param *kp_begin = NULL;
+ unsigned int num_param, i, j;
+ unsigned int stop_point;
+ unsigned int last_stop_point = 0;
+ unsigned int count = 0;
+ char *kbuild_modname;
+
+ num_param = __stop___param - __start___param;
+ if (!num_param)
+ return 0;
+
+ kbuild_modname = kmalloc(sizeof(char) * (MAX_KBUILD_MODNAME + 1), GFP_KERNEL);
+ if (!kbuild_modname)
+ return -ENOMEM;
+ memset(kbuild_modname, 0, sizeof(char) * (MAX_KBUILD_MODNAME + 1));
+
+ for (i=0; i<num_param; i++) {
+ kp = &__start___param[i];
+ stop_point = 0;
+
+ /* get KBUILD_MODNAME out of kp */
+ for (j=0; j <= MAX_KBUILD_MODNAME; j++)
+ {
+ if ((kp->name[j] == '\0') || (kp->name[j] == '\n')) {
+ DEBUGP("invalid KBUILD_MODNAME: %s\n", kp->name);
+ break;
+ }
+ if (kp->name[j] == '.') {
+ stop_point = j;
+ break;
+ }
+ }
+ if (!stop_point) {
+ DEBUGP("couldn't find stop_point\n");
+ continue;
+ }
+
+ /* add a new kobject for previous kernel_params if a new
+ * kbuild_modname is detected for this kernel_param.
+ */
+ if (kp_begin && strncmp(kbuild_modname, kp->name, stop_point))
+ {
+ kernel_param_sysfs_setup(kbuild_modname, kp_begin, count, last_stop_point);
+ }
+
+ /* first, or new kbuild_modname */
+ if (!kp_begin || strncmp(kbuild_modname, kp->name, stop_point)) {
+ strncpy(kbuild_modname, kp->name, stop_point);
+ kbuild_modname[stop_point] = '\0';
+ count = 0;
+
+ kp_begin = kp;
+ last_stop_point = stop_point + 1;
+ }
+
+ count++;
+ }
+ /* last kernel_params need to be registered as well */
+ if (kp_begin && count)
+ kernel_param_sysfs_setup(kbuild_modname, kp_begin, count, last_stop_point);
+
+ kfree (kbuild_modname);
+ return (err);
+}
+
+
+/*
+ * param_sysfs_init - wrapper for built-in params support
+ */
+static int __init param_sysfs_init(void)
+{
+ int err;
+
+ err = subsystem_register(&parameters_subsys);
+ if (err)
+ return (err);
+
+ param_sysfs_builtin();
+
+ return 0;
+}
+
+/* Needs to be before __initcall(module_init) */
+fs_initcall(param_sysfs_init);
+
+
EXPORT_SYMBOL(param_set_short);
EXPORT_SYMBOL(param_get_short);
EXPORT_SYMBOL(param_set_ushort);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 14:04    [W:0.818 / U:0.008 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site