xref: /openbmc/linux/kernel/module/sysfs.c (revision 3cd60866)
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 = &sect_attrs->attrs[0];
9644c09535SAaron Tomlin 	gattr = &sect_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, &sect_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 					      &notes_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 = &notes_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 					  &notes_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