144c09535SAaron Tomlin // SPDX-License-Identifier: GPL-2.0-or-later
244c09535SAaron Tomlin /*
344c09535SAaron Tomlin * Module sysfs support
444c09535SAaron Tomlin *
544c09535SAaron Tomlin * Copyright (C) 2008 Rusty Russell
644c09535SAaron Tomlin */
744c09535SAaron Tomlin
844c09535SAaron Tomlin #include <linux/module.h>
944c09535SAaron Tomlin #include <linux/kernel.h>
1044c09535SAaron Tomlin #include <linux/fs.h>
1144c09535SAaron Tomlin #include <linux/sysfs.h>
1244c09535SAaron Tomlin #include <linux/slab.h>
1344c09535SAaron Tomlin #include <linux/kallsyms.h>
1444c09535SAaron Tomlin #include <linux/mutex.h>
1544c09535SAaron Tomlin #include "internal.h"
1644c09535SAaron Tomlin
1744c09535SAaron Tomlin /*
1844c09535SAaron Tomlin * /sys/module/foo/sections stuff
1944c09535SAaron Tomlin * J. Corbet <corbet@lwn.net>
2044c09535SAaron Tomlin */
2144c09535SAaron Tomlin #ifdef CONFIG_KALLSYMS
2244c09535SAaron Tomlin struct module_sect_attr {
2344c09535SAaron Tomlin struct bin_attribute battr;
2444c09535SAaron Tomlin unsigned long address;
2544c09535SAaron Tomlin };
2644c09535SAaron Tomlin
2744c09535SAaron Tomlin struct module_sect_attrs {
2844c09535SAaron Tomlin struct attribute_group grp;
2944c09535SAaron Tomlin unsigned int nsections;
3044c09535SAaron Tomlin struct module_sect_attr attrs[];
3144c09535SAaron Tomlin };
3244c09535SAaron Tomlin
3344c09535SAaron Tomlin #define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
module_sect_read(struct file * file,struct kobject * kobj,struct bin_attribute * battr,char * buf,loff_t pos,size_t count)3444c09535SAaron Tomlin static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
3544c09535SAaron Tomlin struct bin_attribute *battr,
3644c09535SAaron Tomlin char *buf, loff_t pos, size_t count)
3744c09535SAaron Tomlin {
3844c09535SAaron Tomlin struct module_sect_attr *sattr =
3944c09535SAaron Tomlin container_of(battr, struct module_sect_attr, battr);
4044c09535SAaron Tomlin char bounce[MODULE_SECT_READ_SIZE + 1];
4144c09535SAaron Tomlin size_t wrote;
4244c09535SAaron Tomlin
4344c09535SAaron Tomlin if (pos != 0)
4444c09535SAaron Tomlin return -EINVAL;
4544c09535SAaron Tomlin
4644c09535SAaron Tomlin /*
4744c09535SAaron Tomlin * Since we're a binary read handler, we must account for the
4844c09535SAaron Tomlin * trailing NUL byte that sprintf will write: if "buf" is
4944c09535SAaron Tomlin * too small to hold the NUL, or the NUL is exactly the last
5044c09535SAaron Tomlin * byte, the read will look like it got truncated by one byte.
5144c09535SAaron Tomlin * Since there is no way to ask sprintf nicely to not write
5244c09535SAaron Tomlin * the NUL, we have to use a bounce buffer.
5344c09535SAaron Tomlin */
5444c09535SAaron Tomlin wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
5544c09535SAaron Tomlin kallsyms_show_value(file->f_cred)
5644c09535SAaron Tomlin ? (void *)sattr->address : NULL);
5744c09535SAaron Tomlin count = min(count, wrote);
5844c09535SAaron Tomlin memcpy(buf, bounce, count);
5944c09535SAaron Tomlin
6044c09535SAaron Tomlin return count;
6144c09535SAaron Tomlin }
6244c09535SAaron Tomlin
free_sect_attrs(struct module_sect_attrs * sect_attrs)6344c09535SAaron Tomlin static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
6444c09535SAaron Tomlin {
6544c09535SAaron Tomlin unsigned int section;
6644c09535SAaron Tomlin
6744c09535SAaron Tomlin for (section = 0; section < sect_attrs->nsections; section++)
6844c09535SAaron Tomlin kfree(sect_attrs->attrs[section].battr.attr.name);
6944c09535SAaron Tomlin kfree(sect_attrs);
7044c09535SAaron Tomlin }
7144c09535SAaron Tomlin
add_sect_attrs(struct module * mod,const struct load_info * info)7244c09535SAaron Tomlin static void add_sect_attrs(struct module *mod, const struct load_info *info)
7344c09535SAaron Tomlin {
7444c09535SAaron Tomlin unsigned int nloaded = 0, i, size[2];
7544c09535SAaron Tomlin struct module_sect_attrs *sect_attrs;
7644c09535SAaron Tomlin struct module_sect_attr *sattr;
7744c09535SAaron Tomlin struct bin_attribute **gattr;
7844c09535SAaron Tomlin
7944c09535SAaron Tomlin /* Count loaded sections and allocate structures */
8044c09535SAaron Tomlin for (i = 0; i < info->hdr->e_shnum; i++)
8144c09535SAaron Tomlin if (!sect_empty(&info->sechdrs[i]))
8244c09535SAaron Tomlin nloaded++;
8344c09535SAaron Tomlin size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
8444c09535SAaron Tomlin sizeof(sect_attrs->grp.bin_attrs[0]));
8544c09535SAaron Tomlin size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
8644c09535SAaron Tomlin sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
8744c09535SAaron Tomlin if (!sect_attrs)
8844c09535SAaron Tomlin return;
8944c09535SAaron Tomlin
9044c09535SAaron Tomlin /* Setup section attributes. */
9144c09535SAaron Tomlin sect_attrs->grp.name = "sections";
9244c09535SAaron Tomlin sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
9344c09535SAaron Tomlin
9444c09535SAaron Tomlin sect_attrs->nsections = 0;
9544c09535SAaron Tomlin sattr = §_attrs->attrs[0];
9644c09535SAaron Tomlin gattr = §_attrs->grp.bin_attrs[0];
9744c09535SAaron Tomlin for (i = 0; i < info->hdr->e_shnum; i++) {
9844c09535SAaron Tomlin Elf_Shdr *sec = &info->sechdrs[i];
9944c09535SAaron Tomlin
10044c09535SAaron Tomlin if (sect_empty(sec))
10144c09535SAaron Tomlin continue;
10244c09535SAaron Tomlin sysfs_bin_attr_init(&sattr->battr);
10344c09535SAaron Tomlin sattr->address = sec->sh_addr;
10444c09535SAaron Tomlin sattr->battr.attr.name =
10544c09535SAaron Tomlin kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
10644c09535SAaron Tomlin if (!sattr->battr.attr.name)
10744c09535SAaron Tomlin goto out;
10844c09535SAaron Tomlin sect_attrs->nsections++;
10944c09535SAaron Tomlin sattr->battr.read = module_sect_read;
11044c09535SAaron Tomlin sattr->battr.size = MODULE_SECT_READ_SIZE;
11144c09535SAaron Tomlin sattr->battr.attr.mode = 0400;
11244c09535SAaron Tomlin *(gattr++) = &(sattr++)->battr;
11344c09535SAaron Tomlin }
11444c09535SAaron Tomlin *gattr = NULL;
11544c09535SAaron Tomlin
11644c09535SAaron Tomlin if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp))
11744c09535SAaron Tomlin goto out;
11844c09535SAaron Tomlin
11944c09535SAaron Tomlin mod->sect_attrs = sect_attrs;
12044c09535SAaron Tomlin return;
12144c09535SAaron Tomlin out:
12244c09535SAaron Tomlin free_sect_attrs(sect_attrs);
12344c09535SAaron Tomlin }
12444c09535SAaron Tomlin
remove_sect_attrs(struct module * mod)12544c09535SAaron Tomlin static void remove_sect_attrs(struct module *mod)
12644c09535SAaron Tomlin {
12744c09535SAaron Tomlin if (mod->sect_attrs) {
12844c09535SAaron Tomlin sysfs_remove_group(&mod->mkobj.kobj,
12944c09535SAaron Tomlin &mod->sect_attrs->grp);
13044c09535SAaron Tomlin /*
13144c09535SAaron Tomlin * We are positive that no one is using any sect attrs
13244c09535SAaron Tomlin * at this point. Deallocate immediately.
13344c09535SAaron Tomlin */
13444c09535SAaron Tomlin free_sect_attrs(mod->sect_attrs);
13544c09535SAaron Tomlin mod->sect_attrs = NULL;
13644c09535SAaron Tomlin }
13744c09535SAaron Tomlin }
13844c09535SAaron Tomlin
13944c09535SAaron Tomlin /*
14044c09535SAaron Tomlin * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
14144c09535SAaron Tomlin */
14244c09535SAaron Tomlin
14344c09535SAaron Tomlin struct module_notes_attrs {
14444c09535SAaron Tomlin struct kobject *dir;
14544c09535SAaron Tomlin unsigned int notes;
14644c09535SAaron Tomlin struct bin_attribute attrs[];
14744c09535SAaron Tomlin };
14844c09535SAaron Tomlin
module_notes_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)14944c09535SAaron Tomlin static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
15044c09535SAaron Tomlin struct bin_attribute *bin_attr,
15144c09535SAaron Tomlin char *buf, loff_t pos, size_t count)
15244c09535SAaron Tomlin {
15344c09535SAaron Tomlin /*
15444c09535SAaron Tomlin * The caller checked the pos and count against our size.
15544c09535SAaron Tomlin */
15644c09535SAaron Tomlin memcpy(buf, bin_attr->private + pos, count);
15744c09535SAaron Tomlin return count;
15844c09535SAaron Tomlin }
15944c09535SAaron Tomlin
free_notes_attrs(struct module_notes_attrs * notes_attrs,unsigned int i)16044c09535SAaron Tomlin static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
16144c09535SAaron Tomlin unsigned int i)
16244c09535SAaron Tomlin {
16344c09535SAaron Tomlin if (notes_attrs->dir) {
16444c09535SAaron Tomlin while (i-- > 0)
16544c09535SAaron Tomlin sysfs_remove_bin_file(notes_attrs->dir,
16644c09535SAaron Tomlin ¬es_attrs->attrs[i]);
16744c09535SAaron Tomlin kobject_put(notes_attrs->dir);
16844c09535SAaron Tomlin }
16944c09535SAaron Tomlin kfree(notes_attrs);
17044c09535SAaron Tomlin }
17144c09535SAaron Tomlin
add_notes_attrs(struct module * mod,const struct load_info * info)17244c09535SAaron Tomlin static void add_notes_attrs(struct module *mod, const struct load_info *info)
17344c09535SAaron Tomlin {
17444c09535SAaron Tomlin unsigned int notes, loaded, i;
17544c09535SAaron Tomlin struct module_notes_attrs *notes_attrs;
17644c09535SAaron Tomlin struct bin_attribute *nattr;
17744c09535SAaron Tomlin
17844c09535SAaron Tomlin /* failed to create section attributes, so can't create notes */
17944c09535SAaron Tomlin if (!mod->sect_attrs)
18044c09535SAaron Tomlin return;
18144c09535SAaron Tomlin
18244c09535SAaron Tomlin /* Count notes sections and allocate structures. */
18344c09535SAaron Tomlin notes = 0;
18444c09535SAaron Tomlin for (i = 0; i < info->hdr->e_shnum; i++)
18544c09535SAaron Tomlin if (!sect_empty(&info->sechdrs[i]) &&
18644c09535SAaron Tomlin info->sechdrs[i].sh_type == SHT_NOTE)
18744c09535SAaron Tomlin ++notes;
18844c09535SAaron Tomlin
18944c09535SAaron Tomlin if (notes == 0)
19044c09535SAaron Tomlin return;
19144c09535SAaron Tomlin
19244c09535SAaron Tomlin notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
19344c09535SAaron Tomlin GFP_KERNEL);
19444c09535SAaron Tomlin if (!notes_attrs)
19544c09535SAaron Tomlin return;
19644c09535SAaron Tomlin
19744c09535SAaron Tomlin notes_attrs->notes = notes;
19844c09535SAaron Tomlin nattr = ¬es_attrs->attrs[0];
19944c09535SAaron Tomlin for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
20044c09535SAaron Tomlin if (sect_empty(&info->sechdrs[i]))
20144c09535SAaron Tomlin continue;
20244c09535SAaron Tomlin if (info->sechdrs[i].sh_type == SHT_NOTE) {
20344c09535SAaron Tomlin sysfs_bin_attr_init(nattr);
20444c09535SAaron Tomlin nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
20544c09535SAaron Tomlin nattr->attr.mode = 0444;
20644c09535SAaron Tomlin nattr->size = info->sechdrs[i].sh_size;
20744c09535SAaron Tomlin nattr->private = (void *)info->sechdrs[i].sh_addr;
20844c09535SAaron Tomlin nattr->read = module_notes_read;
20944c09535SAaron Tomlin ++nattr;
21044c09535SAaron Tomlin }
21144c09535SAaron Tomlin ++loaded;
21244c09535SAaron Tomlin }
21344c09535SAaron Tomlin
21444c09535SAaron Tomlin notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
21544c09535SAaron Tomlin if (!notes_attrs->dir)
21644c09535SAaron Tomlin goto out;
21744c09535SAaron Tomlin
21844c09535SAaron Tomlin for (i = 0; i < notes; ++i)
21944c09535SAaron Tomlin if (sysfs_create_bin_file(notes_attrs->dir,
22044c09535SAaron Tomlin ¬es_attrs->attrs[i]))
22144c09535SAaron Tomlin goto out;
22244c09535SAaron Tomlin
22344c09535SAaron Tomlin mod->notes_attrs = notes_attrs;
22444c09535SAaron Tomlin return;
22544c09535SAaron Tomlin
22644c09535SAaron Tomlin out:
22744c09535SAaron Tomlin free_notes_attrs(notes_attrs, i);
22844c09535SAaron Tomlin }
22944c09535SAaron Tomlin
remove_notes_attrs(struct module * mod)23044c09535SAaron Tomlin static void remove_notes_attrs(struct module *mod)
23144c09535SAaron Tomlin {
23244c09535SAaron Tomlin if (mod->notes_attrs)
23344c09535SAaron Tomlin free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
23444c09535SAaron Tomlin }
23544c09535SAaron Tomlin
23644c09535SAaron Tomlin #else /* !CONFIG_KALLSYMS */
add_sect_attrs(struct module * mod,const struct load_info * info)23744c09535SAaron Tomlin static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }
remove_sect_attrs(struct module * mod)23844c09535SAaron Tomlin static inline void remove_sect_attrs(struct module *mod) { }
add_notes_attrs(struct module * mod,const struct load_info * info)23944c09535SAaron Tomlin static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }
remove_notes_attrs(struct module * mod)24044c09535SAaron Tomlin static inline void remove_notes_attrs(struct module *mod) { }
24144c09535SAaron Tomlin #endif /* CONFIG_KALLSYMS */
24244c09535SAaron Tomlin
del_usage_links(struct module * mod)24344c09535SAaron Tomlin static void del_usage_links(struct module *mod)
24444c09535SAaron Tomlin {
24544c09535SAaron Tomlin #ifdef CONFIG_MODULE_UNLOAD
24644c09535SAaron Tomlin struct module_use *use;
24744c09535SAaron Tomlin
24844c09535SAaron Tomlin mutex_lock(&module_mutex);
24944c09535SAaron Tomlin list_for_each_entry(use, &mod->target_list, target_list)
25044c09535SAaron Tomlin sysfs_remove_link(use->target->holders_dir, mod->name);
25144c09535SAaron Tomlin mutex_unlock(&module_mutex);
25244c09535SAaron Tomlin #endif
25344c09535SAaron Tomlin }
25444c09535SAaron Tomlin
add_usage_links(struct module * mod)25544c09535SAaron Tomlin static int add_usage_links(struct module *mod)
25644c09535SAaron Tomlin {
25744c09535SAaron Tomlin int ret = 0;
25844c09535SAaron Tomlin #ifdef CONFIG_MODULE_UNLOAD
25944c09535SAaron Tomlin struct module_use *use;
26044c09535SAaron Tomlin
26144c09535SAaron Tomlin mutex_lock(&module_mutex);
26244c09535SAaron Tomlin list_for_each_entry(use, &mod->target_list, target_list) {
26344c09535SAaron Tomlin ret = sysfs_create_link(use->target->holders_dir,
26444c09535SAaron Tomlin &mod->mkobj.kobj, mod->name);
26544c09535SAaron Tomlin if (ret)
26644c09535SAaron Tomlin break;
26744c09535SAaron Tomlin }
26844c09535SAaron Tomlin mutex_unlock(&module_mutex);
26944c09535SAaron Tomlin if (ret)
27044c09535SAaron Tomlin del_usage_links(mod);
27144c09535SAaron Tomlin #endif
27244c09535SAaron Tomlin return ret;
27344c09535SAaron Tomlin }
27444c09535SAaron Tomlin
module_remove_modinfo_attrs(struct module * mod,int end)27544c09535SAaron Tomlin static void module_remove_modinfo_attrs(struct module *mod, int end)
27644c09535SAaron Tomlin {
27744c09535SAaron Tomlin struct module_attribute *attr;
27844c09535SAaron Tomlin int i;
27944c09535SAaron Tomlin
28044c09535SAaron Tomlin for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
28144c09535SAaron Tomlin if (end >= 0 && i > end)
28244c09535SAaron Tomlin break;
28344c09535SAaron Tomlin /* pick a field to test for end of list */
28444c09535SAaron Tomlin if (!attr->attr.name)
28544c09535SAaron Tomlin break;
28644c09535SAaron Tomlin sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
28744c09535SAaron Tomlin if (attr->free)
28844c09535SAaron Tomlin attr->free(mod);
28944c09535SAaron Tomlin }
29044c09535SAaron Tomlin kfree(mod->modinfo_attrs);
29144c09535SAaron Tomlin }
29244c09535SAaron Tomlin
module_add_modinfo_attrs(struct module * mod)29344c09535SAaron Tomlin static int module_add_modinfo_attrs(struct module *mod)
29444c09535SAaron Tomlin {
29544c09535SAaron Tomlin struct module_attribute *attr;
29644c09535SAaron Tomlin struct module_attribute *temp_attr;
29744c09535SAaron Tomlin int error = 0;
29844c09535SAaron Tomlin int i;
29944c09535SAaron Tomlin
30044c09535SAaron Tomlin mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
30144c09535SAaron Tomlin (modinfo_attrs_count + 1)),
30244c09535SAaron Tomlin GFP_KERNEL);
30344c09535SAaron Tomlin if (!mod->modinfo_attrs)
30444c09535SAaron Tomlin return -ENOMEM;
30544c09535SAaron Tomlin
30644c09535SAaron Tomlin temp_attr = mod->modinfo_attrs;
30744c09535SAaron Tomlin for (i = 0; (attr = modinfo_attrs[i]); i++) {
30844c09535SAaron Tomlin if (!attr->test || attr->test(mod)) {
30944c09535SAaron Tomlin memcpy(temp_attr, attr, sizeof(*temp_attr));
31044c09535SAaron Tomlin sysfs_attr_init(&temp_attr->attr);
31144c09535SAaron Tomlin error = sysfs_create_file(&mod->mkobj.kobj,
31244c09535SAaron Tomlin &temp_attr->attr);
31344c09535SAaron Tomlin if (error)
31444c09535SAaron Tomlin goto error_out;
31544c09535SAaron Tomlin ++temp_attr;
31644c09535SAaron Tomlin }
31744c09535SAaron Tomlin }
31844c09535SAaron Tomlin
31944c09535SAaron Tomlin return 0;
32044c09535SAaron Tomlin
32144c09535SAaron Tomlin error_out:
32244c09535SAaron Tomlin if (i > 0)
32344c09535SAaron Tomlin module_remove_modinfo_attrs(mod, --i);
32444c09535SAaron Tomlin else
32544c09535SAaron Tomlin kfree(mod->modinfo_attrs);
32644c09535SAaron Tomlin return error;
32744c09535SAaron Tomlin }
32844c09535SAaron Tomlin
mod_kobject_put(struct module * mod)32944c09535SAaron Tomlin static void mod_kobject_put(struct module *mod)
33044c09535SAaron Tomlin {
33144c09535SAaron Tomlin DECLARE_COMPLETION_ONSTACK(c);
33244c09535SAaron Tomlin
33344c09535SAaron Tomlin mod->mkobj.kobj_completion = &c;
33444c09535SAaron Tomlin kobject_put(&mod->mkobj.kobj);
33544c09535SAaron Tomlin wait_for_completion(&c);
33644c09535SAaron Tomlin }
33744c09535SAaron Tomlin
mod_sysfs_init(struct module * mod)33844c09535SAaron Tomlin static int mod_sysfs_init(struct module *mod)
33944c09535SAaron Tomlin {
34044c09535SAaron Tomlin int err;
34144c09535SAaron Tomlin struct kobject *kobj;
34244c09535SAaron Tomlin
343*3cd60866SRasmus Villemoes if (!module_kset) {
34444c09535SAaron Tomlin pr_err("%s: module sysfs not initialized\n", mod->name);
34544c09535SAaron Tomlin err = -EINVAL;
34644c09535SAaron Tomlin goto out;
34744c09535SAaron Tomlin }
34844c09535SAaron Tomlin
34944c09535SAaron Tomlin kobj = kset_find_obj(module_kset, mod->name);
35044c09535SAaron Tomlin if (kobj) {
35144c09535SAaron Tomlin pr_err("%s: module is already loaded\n", mod->name);
35244c09535SAaron Tomlin kobject_put(kobj);
35344c09535SAaron Tomlin err = -EINVAL;
35444c09535SAaron Tomlin goto out;
35544c09535SAaron Tomlin }
35644c09535SAaron Tomlin
35744c09535SAaron Tomlin mod->mkobj.mod = mod;
35844c09535SAaron Tomlin
35944c09535SAaron Tomlin memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
36044c09535SAaron Tomlin mod->mkobj.kobj.kset = module_kset;
36144c09535SAaron Tomlin err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
36244c09535SAaron Tomlin "%s", mod->name);
36344c09535SAaron Tomlin if (err)
36444c09535SAaron Tomlin mod_kobject_put(mod);
36544c09535SAaron Tomlin
36644c09535SAaron Tomlin out:
36744c09535SAaron Tomlin return err;
36844c09535SAaron Tomlin }
36944c09535SAaron Tomlin
mod_sysfs_setup(struct module * mod,const struct load_info * info,struct kernel_param * kparam,unsigned int num_params)37044c09535SAaron Tomlin int mod_sysfs_setup(struct module *mod,
37144c09535SAaron Tomlin const struct load_info *info,
37244c09535SAaron Tomlin struct kernel_param *kparam,
37344c09535SAaron Tomlin unsigned int num_params)
37444c09535SAaron Tomlin {
37544c09535SAaron Tomlin int err;
37644c09535SAaron Tomlin
37744c09535SAaron Tomlin err = mod_sysfs_init(mod);
37844c09535SAaron Tomlin if (err)
37944c09535SAaron Tomlin goto out;
38044c09535SAaron Tomlin
38144c09535SAaron Tomlin mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
38244c09535SAaron Tomlin if (!mod->holders_dir) {
38344c09535SAaron Tomlin err = -ENOMEM;
38444c09535SAaron Tomlin goto out_unreg;
38544c09535SAaron Tomlin }
38644c09535SAaron Tomlin
38744c09535SAaron Tomlin err = module_param_sysfs_setup(mod, kparam, num_params);
38844c09535SAaron Tomlin if (err)
38944c09535SAaron Tomlin goto out_unreg_holders;
39044c09535SAaron Tomlin
39144c09535SAaron Tomlin err = module_add_modinfo_attrs(mod);
39244c09535SAaron Tomlin if (err)
39344c09535SAaron Tomlin goto out_unreg_param;
39444c09535SAaron Tomlin
39544c09535SAaron Tomlin err = add_usage_links(mod);
39644c09535SAaron Tomlin if (err)
39744c09535SAaron Tomlin goto out_unreg_modinfo_attrs;
39844c09535SAaron Tomlin
39944c09535SAaron Tomlin add_sect_attrs(mod, info);
40044c09535SAaron Tomlin add_notes_attrs(mod, info);
40144c09535SAaron Tomlin
40244c09535SAaron Tomlin return 0;
40344c09535SAaron Tomlin
40444c09535SAaron Tomlin out_unreg_modinfo_attrs:
40544c09535SAaron Tomlin module_remove_modinfo_attrs(mod, -1);
40644c09535SAaron Tomlin out_unreg_param:
40744c09535SAaron Tomlin module_param_sysfs_remove(mod);
40844c09535SAaron Tomlin out_unreg_holders:
40944c09535SAaron Tomlin kobject_put(mod->holders_dir);
41044c09535SAaron Tomlin out_unreg:
41144c09535SAaron Tomlin mod_kobject_put(mod);
41244c09535SAaron Tomlin out:
41344c09535SAaron Tomlin return err;
41444c09535SAaron Tomlin }
41544c09535SAaron Tomlin
mod_sysfs_fini(struct module * mod)41644c09535SAaron Tomlin static void mod_sysfs_fini(struct module *mod)
41744c09535SAaron Tomlin {
41844c09535SAaron Tomlin remove_notes_attrs(mod);
41944c09535SAaron Tomlin remove_sect_attrs(mod);
42044c09535SAaron Tomlin mod_kobject_put(mod);
42144c09535SAaron Tomlin }
42244c09535SAaron Tomlin
mod_sysfs_teardown(struct module * mod)42344c09535SAaron Tomlin void mod_sysfs_teardown(struct module *mod)
42444c09535SAaron Tomlin {
42544c09535SAaron Tomlin del_usage_links(mod);
42644c09535SAaron Tomlin module_remove_modinfo_attrs(mod, -1);
42744c09535SAaron Tomlin module_param_sysfs_remove(mod);
42844c09535SAaron Tomlin kobject_put(mod->mkobj.drivers_dir);
42944c09535SAaron Tomlin kobject_put(mod->holders_dir);
43044c09535SAaron Tomlin mod_sysfs_fini(mod);
43144c09535SAaron Tomlin }
43244c09535SAaron Tomlin
init_param_lock(struct module * mod)43344c09535SAaron Tomlin void init_param_lock(struct module *mod)
43444c09535SAaron Tomlin {
43544c09535SAaron Tomlin mutex_init(&mod->param_lock);
43644c09535SAaron Tomlin }
437