This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / kernel / module.c
index ad5ccf7..934f5b1 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
 #include <linux/stop_machine.h>
-#include <linux/device.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
@@ -370,6 +369,22 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
 }
 #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)
@@ -577,8 +592,6 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
 
        /* Stop the machine so refcounts can't move and disable module. */
        ret = try_stop_module(mod, flags, &forced);
-       if (ret != 0)
-               goto out;
 
        /* Never wait if forced. */
        if (!forced && module_refcount(mod) != 0)
@@ -652,16 +665,22 @@ void symbol_put_addr(void *addr)
 }
 EXPORT_SYMBOL_GPL(symbol_put_addr);
 
-static ssize_t show_refcnt(struct module *mod, char *buffer)
+static int refcnt_get_fn(char *buffer, struct kernel_param *kp)
 {
-       /* sysfs holds a reference */
-       return sprintf(buffer, "%u\n", module_refcount(mod)-1);
+       struct module *mod = container_of(kp, struct module, refcnt_param);
+
+       /* sysfs holds one reference. */
+       return sprintf(buffer, "%u", module_refcount(mod)-1);
 }
 
-static struct module_attribute refcnt = {
-       .attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE },
-       .show = show_refcnt,
-};
+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);
+}
 
 #else /* !CONFIG_MODULE_UNLOAD */
 static void print_unload_info(struct seq_file *m, struct module *mod)
@@ -689,6 +708,10 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
        return -ENOSYS;
 }
 
+static inline int sysfs_unload_setup(struct module *mod)
+{
+       return 0;
+}
 #endif /* CONFIG_MODULE_UNLOAD */
 
 #ifdef CONFIG_OBSOLETE_MODPARM
@@ -1027,57 +1050,101 @@ static inline void remove_sect_attrs(struct module *mod)
 #endif /* CONFIG_KALLSYMS */
 
 
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-       return sysfs_create_file(&mod->mkobj->kobj, &refcnt.attr);
-}
-static void module_remove_refcnt_attr(struct module *mod)
+
+
+#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)
 {
-       return sysfs_remove_file(&mod->mkobj->kobj, &refcnt.attr);
+       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;
 }
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
+
+/* 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)
 {
-       return 0;
+       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;
 }
-static void module_remove_refcnt_attr(struct module *mod)
+
+static struct sysfs_ops module_sysfs_ops = {
+       .show = module_attr_show,
+       .store = module_attr_store,
+};
+
+static void module_kobj_release(struct kobject *kobj)
 {
+       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;
 
-       mod->mkobj = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
+       /* 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);
        if (!mod->mkobj)
                return -ENOMEM;
 
        memset(&mod->mkobj->kobj, 0, sizeof(mod->mkobj->kobj));
-       err = kobject_set_name(&mod->mkobj->kobj, "%s", mod->name);
+       err = kobject_set_name(&mod->mkobj->kobj, mod->name);
        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;
 
-       err = module_add_refcnt_attr(mod);
-       if (err)
-               goto out_unreg;
+       mod->mkobj->num_attributes = 0;
 
-       err = module_param_sysfs_setup(mod, kparam, num_params);
+       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);
        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;
@@ -1088,9 +1155,9 @@ out:
 
 static void mod_kobject_remove(struct module *mod)
 {
-       module_remove_refcnt_attr(mod);
-       module_param_sysfs_remove(mod);
-
+       unsigned int i;
+       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);
 }
@@ -1721,7 +1788,6 @@ static struct module *load_module(void __user *umod,
                                 / sizeof(struct kernel_param),
                                 NULL);
        }
-
        err = mod_sysfs_setup(mod, 
                              (struct kernel_param *)
                              sechdrs[setupindex].sh_addr,
@@ -1845,16 +1911,6 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
 }
 
 #ifdef CONFIG_KALLSYMS
-/*
- * This ignores the intensely annoying "mapping symbols" found
- * in ARM ELF files: $a, $t and $d.
- */
-static inline int is_arm_mapping_symbol(const char *str)
-{
-       return str[0] == '$' && strchr("atd", str[1]) 
-              && (str[2] == '\0' || str[2] == '.');
-}
-
 static const char *get_ksymbol(struct module *mod,
                               unsigned long addr,
                               unsigned long *size,
@@ -1879,13 +1935,11 @@ static const char *get_ksymbol(struct module *mod,
                 * and inserted at a whim. */
                if (mod->symtab[i].st_value <= addr
                    && mod->symtab[i].st_value > mod->symtab[best].st_value
-                   && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-                   && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
+                   && *(mod->strtab + mod->symtab[i].st_name) != '\0' )
                        best = i;
                if (mod->symtab[i].st_value > addr
                    && mod->symtab[i].st_value < nextval
-                   && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-                   && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
+                   && *(mod->strtab + mod->symtab[i].st_name) != '\0')
                        nextval = mod->symtab[i].st_value;
        }
 
@@ -2099,28 +2153,14 @@ void print_modules(void)
        printk("\n");
 }
 
-void module_add_driver(struct module *mod, struct device_driver *drv)
-{
-       if (!mod || !drv)
-               return;
-       if (!mod->mkobj)
-               return;
-
-       /* Don't check return code; this call is idempotent */
-       sysfs_create_link(&drv->kobj, &mod->mkobj->kobj, "module");
-}
-EXPORT_SYMBOL(module_add_driver);
-
-void module_remove_driver(struct device_driver *drv)
-{
-       if (!drv)
-               return;
-       sysfs_remove_link(&drv->kobj, "module");
-}
-EXPORT_SYMBOL(module_remove_driver);
-
 #ifdef CONFIG_MODVERSIONS
 /* Generate the signature for struct module here, too, for modversions. */
 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);