All of lore.kernel.org
 help / color / mirror / Atom feed
From: Christophe Leroy <christophe.leroy@csgroup.eu>
To: Aaron Tomlin <atomlin@redhat.com>,
	"mcgrof@kernel.org" <mcgrof@kernel.org>
Cc: "cl@linux.com" <cl@linux.com>,
	"pmladek@suse.com" <pmladek@suse.com>,
	"mbenes@suse.cz" <mbenes@suse.cz>,
	"akpm@linux-foundation.org" <akpm@linux-foundation.org>,
	"jeyu@kernel.org" <jeyu@kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linux-modules@vger.kernel.org" <linux-modules@vger.kernel.org>,
	"void@manifault.com" <void@manifault.com>,
	"atomlin@atomlin.com" <atomlin@atomlin.com>,
	"allen.lkml@gmail.com" <allen.lkml@gmail.com>,
	"joe@perches.com" <joe@perches.com>,
	"msuchanek@suse.de" <msuchanek@suse.de>,
	"oleksandr@natalenko.name" <oleksandr@natalenko.name>
Subject: Re: [PATCH v8 11/13] module: Move sysfs support into a separate file
Date: Tue, 22 Feb 2022 17:59:55 +0000	[thread overview]
Message-ID: <d5f11de3-a469-03aa-540f-ac0b803ea5c1@csgroup.eu> (raw)
In-Reply-To: <20220222141303.1392190-12-atomlin@redhat.com>



Le 22/02/2022 à 15:13, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates module sysfs support out of core code into
> kernel/module/sysfs.c. In addition simple code refactoring to
> make this possible.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |  21 ++
>   kernel/module/main.c     | 469 +--------------------------------------
>   kernel/module/sysfs.c    | 436 ++++++++++++++++++++++++++++++++++++
>   4 files changed, 461 insertions(+), 466 deletions(-)
>   create mode 100644 kernel/module/sysfs.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 94296c98a67f..cf8dcdc6b55f 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
>   obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
>   obj-$(CONFIG_KALLSYMS) += kallsyms.o
>   obj-$(CONFIG_PROC_FS) += procfs.o
> +obj-$(CONFIG_SYSFS) += sysfs.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 6af40c2d145f..62d749ef695e 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -34,6 +34,9 @@
>   extern struct mutex module_mutex;
>   extern struct list_head modules;
>   
> +extern struct module_attribute *modinfo_attrs[];
> +extern size_t modinfo_attrs_count;
> +
>   /* Provided by the linker */
>   extern const struct kernel_symbol __start___ksymtab[];
>   extern const struct kernel_symbol __stop___ksymtab[];
> @@ -204,3 +207,21 @@ static inline void init_build_id(struct module *mod, const struct load_info *inf
>   static inline void layout_symtab(struct module *mod, struct load_info *info) { }
>   static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
>   #endif /* CONFIG_KALLSYMS */
> +
> +#ifdef CONFIG_SYSFS
> +int mod_sysfs_setup(struct module *mod, const struct load_info *info,
> +		    struct kernel_param *kparam, unsigned int num_params);
> +void mod_sysfs_teardown(struct module *mod);
> +void init_param_lock(struct module *mod);
> +#else /* !CONFIG_SYSFS */
> +static inline int mod_sysfs_setup(struct module *mod,
> +			   	  const struct load_info *info,
> +			   	  struct kernel_param *kparam,
> +			   	  unsigned int num_params)
> +{
> +	return 0;
> +}
> +
> +static inline void mod_sysfs_teardown(struct module *mod) { }
> +static inline void init_param_lock(struct module *mod) { }
> +#endif /* CONFIG_SYSFS */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 44b6fd1acc44..b8a59b5c3e3a 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -14,9 +14,7 @@
>   #include <linux/init.h>
>   #include <linux/kallsyms.h>
>   #include <linux/buildid.h>
> -#include <linux/file.h>
>   #include <linux/fs.h>
> -#include <linux/sysfs.h>
>   #include <linux/kernel.h>
>   #include <linux/kernel_read_file.h>
>   #include <linux/slab.h>
> @@ -989,7 +987,7 @@ static ssize_t show_taint(struct module_attribute *mattr,
>   static struct module_attribute modinfo_taint =
>   	__ATTR(taint, 0444, show_taint, NULL);
>   
> -static struct module_attribute *modinfo_attrs[] = {
> +struct module_attribute *modinfo_attrs[] = {
>   	&module_uevent,
>   	&modinfo_version,
>   	&modinfo_srcversion,
> @@ -1003,6 +1001,8 @@ static struct module_attribute *modinfo_attrs[] = {
>   	NULL,
>   };
>   
> +size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs);
> +
>   static const char vermagic[] = VERMAGIC_STRING;
>   
>   static int try_to_force_load(struct module *mod, const char *reason)
> @@ -1253,469 +1253,6 @@ resolve_symbol_wait(struct module *mod,
>   	return ksym;
>   }
>   
> -/*
> - * /sys/module/foo/sections stuff
> - * J. Corbet <corbet@lwn.net>
> - */
> -#ifdef CONFIG_SYSFS
> -
> -#ifdef CONFIG_KALLSYMS
> -struct module_sect_attr {
> -	struct bin_attribute battr;
> -	unsigned long address;
> -};
> -
> -struct module_sect_attrs {
> -	struct attribute_group grp;
> -	unsigned int nsections;
> -	struct module_sect_attr attrs[];
> -};
> -
> -#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
> -static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
> -				struct bin_attribute *battr,
> -				char *buf, loff_t pos, size_t count)
> -{
> -	struct module_sect_attr *sattr =
> -		container_of(battr, struct module_sect_attr, battr);
> -	char bounce[MODULE_SECT_READ_SIZE + 1];
> -	size_t wrote;
> -
> -	if (pos != 0)
> -		return -EINVAL;
> -
> -	/*
> -	 * Since we're a binary read handler, we must account for the
> -	 * trailing NUL byte that sprintf will write: if "buf" is
> -	 * too small to hold the NUL, or the NUL is exactly the last
> -	 * byte, the read will look like it got truncated by one byte.
> -	 * Since there is no way to ask sprintf nicely to not write
> -	 * the NUL, we have to use a bounce buffer.
> -	 */
> -	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
> -			 kallsyms_show_value(file->f_cred)
> -				? (void *)sattr->address : NULL);
> -	count = min(count, wrote);
> -	memcpy(buf, bounce, count);
> -
> -	return count;
> -}
> -
> -static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
> -{
> -	unsigned int section;
> -
> -	for (section = 0; section < sect_attrs->nsections; section++)
> -		kfree(sect_attrs->attrs[section].battr.attr.name);
> -	kfree(sect_attrs);
> -}
> -
> -static void add_sect_attrs(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int nloaded = 0, i, size[2];
> -	struct module_sect_attrs *sect_attrs;
> -	struct module_sect_attr *sattr;
> -	struct bin_attribute **gattr;
> -
> -	/* Count loaded sections and allocate structures */
> -	for (i = 0; i < info->hdr->e_shnum; i++)
> -		if (!sect_empty(&info->sechdrs[i]))
> -			nloaded++;
> -	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
> -			sizeof(sect_attrs->grp.bin_attrs[0]));
> -	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
> -	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
> -	if (sect_attrs == NULL)
> -		return;
> -
> -	/* Setup section attributes. */
> -	sect_attrs->grp.name = "sections";
> -	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
> -
> -	sect_attrs->nsections = 0;
> -	sattr = &sect_attrs->attrs[0];
> -	gattr = &sect_attrs->grp.bin_attrs[0];
> -	for (i = 0; i < info->hdr->e_shnum; i++) {
> -		Elf_Shdr *sec = &info->sechdrs[i];
> -		if (sect_empty(sec))
> -			continue;
> -		sysfs_bin_attr_init(&sattr->battr);
> -		sattr->address = sec->sh_addr;
> -		sattr->battr.attr.name =
> -			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
> -		if (sattr->battr.attr.name == NULL)
> -			goto out;
> -		sect_attrs->nsections++;
> -		sattr->battr.read = module_sect_read;
> -		sattr->battr.size = MODULE_SECT_READ_SIZE;
> -		sattr->battr.attr.mode = 0400;
> -		*(gattr++) = &(sattr++)->battr;
> -	}
> -	*gattr = NULL;
> -
> -	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
> -		goto out;
> -
> -	mod->sect_attrs = sect_attrs;
> -	return;
> -  out:
> -	free_sect_attrs(sect_attrs);
> -}
> -
> -static void remove_sect_attrs(struct module *mod)
> -{
> -	if (mod->sect_attrs) {
> -		sysfs_remove_group(&mod->mkobj.kobj,
> -				   &mod->sect_attrs->grp);
> -		/*
> -		 * We are positive that no one is using any sect attrs
> -		 * at this point.  Deallocate immediately.
> -		 */
> -		free_sect_attrs(mod->sect_attrs);
> -		mod->sect_attrs = NULL;
> -	}
> -}
> -
> -/*
> - * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
> - */
> -
> -struct module_notes_attrs {
> -	struct kobject *dir;
> -	unsigned int notes;
> -	struct bin_attribute attrs[];
> -};
> -
> -static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
> -				 struct bin_attribute *bin_attr,
> -				 char *buf, loff_t pos, size_t count)
> -{
> -	/*
> -	 * The caller checked the pos and count against our size.
> -	 */
> -	memcpy(buf, bin_attr->private + pos, count);
> -	return count;
> -}
> -
> -static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
> -			     unsigned int i)
> -{
> -	if (notes_attrs->dir) {
> -		while (i-- > 0)
> -			sysfs_remove_bin_file(notes_attrs->dir,
> -					      &notes_attrs->attrs[i]);
> -		kobject_put(notes_attrs->dir);
> -	}
> -	kfree(notes_attrs);
> -}
> -
> -static void add_notes_attrs(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int notes, loaded, i;
> -	struct module_notes_attrs *notes_attrs;
> -	struct bin_attribute *nattr;
> -
> -	/* failed to create section attributes, so can't create notes */
> -	if (!mod->sect_attrs)
> -		return;
> -
> -	/* Count notes sections and allocate structures.  */
> -	notes = 0;
> -	for (i = 0; i < info->hdr->e_shnum; i++)
> -		if (!sect_empty(&info->sechdrs[i]) &&
> -		    (info->sechdrs[i].sh_type == SHT_NOTE))
> -			++notes;
> -
> -	if (notes == 0)
> -		return;
> -
> -	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
> -			      GFP_KERNEL);
> -	if (notes_attrs == NULL)
> -		return;
> -
> -	notes_attrs->notes = notes;
> -	nattr = &notes_attrs->attrs[0];
> -	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
> -		if (sect_empty(&info->sechdrs[i]))
> -			continue;
> -		if (info->sechdrs[i].sh_type == SHT_NOTE) {
> -			sysfs_bin_attr_init(nattr);
> -			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
> -			nattr->attr.mode = S_IRUGO;
> -			nattr->size = info->sechdrs[i].sh_size;
> -			nattr->private = (void *) info->sechdrs[i].sh_addr;
> -			nattr->read = module_notes_read;
> -			++nattr;
> -		}
> -		++loaded;
> -	}
> -
> -	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
> -	if (!notes_attrs->dir)
> -		goto out;
> -
> -	for (i = 0; i < notes; ++i)
> -		if (sysfs_create_bin_file(notes_attrs->dir,
> -					  &notes_attrs->attrs[i]))
> -			goto out;
> -
> -	mod->notes_attrs = notes_attrs;
> -	return;
> -
> -  out:
> -	free_notes_attrs(notes_attrs, i);
> -}
> -
> -static void remove_notes_attrs(struct module *mod)
> -{
> -	if (mod->notes_attrs)
> -		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
> -}
> -
> -#else
> -
> -static inline void add_sect_attrs(struct module *mod,
> -				  const struct load_info *info)
> -{
> -}
> -
> -static inline void remove_sect_attrs(struct module *mod)
> -{
> -}
> -
> -static inline void add_notes_attrs(struct module *mod,
> -				   const struct load_info *info)
> -{
> -}
> -
> -static inline void remove_notes_attrs(struct module *mod)
> -{
> -}
> -#endif /* CONFIG_KALLSYMS */
> -
> -static void del_usage_links(struct module *mod)
> -{
> -#ifdef CONFIG_MODULE_UNLOAD
> -	struct module_use *use;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(use, &mod->target_list, target_list)
> -		sysfs_remove_link(use->target->holders_dir, mod->name);
> -	mutex_unlock(&module_mutex);
> -#endif
> -}
> -
> -static int add_usage_links(struct module *mod)
> -{
> -	int ret = 0;
> -#ifdef CONFIG_MODULE_UNLOAD
> -	struct module_use *use;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(use, &mod->target_list, target_list) {
> -		ret = sysfs_create_link(use->target->holders_dir,
> -					&mod->mkobj.kobj, mod->name);
> -		if (ret)
> -			break;
> -	}
> -	mutex_unlock(&module_mutex);
> -	if (ret)
> -		del_usage_links(mod);
> -#endif
> -	return ret;
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end);
> -
> -static int module_add_modinfo_attrs(struct module *mod)
> -{
> -	struct module_attribute *attr;
> -	struct module_attribute *temp_attr;
> -	int error = 0;
> -	int i;
> -
> -	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
> -					(ARRAY_SIZE(modinfo_attrs) + 1)),
> -					GFP_KERNEL);
> -	if (!mod->modinfo_attrs)
> -		return -ENOMEM;
> -
> -	temp_attr = mod->modinfo_attrs;
> -	for (i = 0; (attr = modinfo_attrs[i]); i++) {
> -		if (!attr->test || attr->test(mod)) {
> -			memcpy(temp_attr, attr, sizeof(*temp_attr));
> -			sysfs_attr_init(&temp_attr->attr);
> -			error = sysfs_create_file(&mod->mkobj.kobj,
> -					&temp_attr->attr);
> -			if (error)
> -				goto error_out;
> -			++temp_attr;
> -		}
> -	}
> -
> -	return 0;
> -
> -error_out:
> -	if (i > 0)
> -		module_remove_modinfo_attrs(mod, --i);
> -	else
> -		kfree(mod->modinfo_attrs);
> -	return error;
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end)
> -{
> -	struct module_attribute *attr;
> -	int i;
> -
> -	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
> -		if (end >= 0 && i > end)
> -			break;
> -		/* pick a field to test for end of list */
> -		if (!attr->attr.name)
> -			break;
> -		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
> -		if (attr->free)
> -			attr->free(mod);
> -	}
> -	kfree(mod->modinfo_attrs);
> -}
> -
> -static void mod_kobject_put(struct module *mod)
> -{
> -	DECLARE_COMPLETION_ONSTACK(c);
> -	mod->mkobj.kobj_completion = &c;
> -	kobject_put(&mod->mkobj.kobj);
> -	wait_for_completion(&c);
> -}
> -
> -static int mod_sysfs_init(struct module *mod)
> -{
> -	int err;
> -	struct kobject *kobj;
> -
> -	if (!module_sysfs_initialized) {
> -		pr_err("%s: module sysfs not initialized\n", mod->name);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	kobj = kset_find_obj(module_kset, mod->name);
> -	if (kobj) {
> -		pr_err("%s: module is already loaded\n", mod->name);
> -		kobject_put(kobj);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	mod->mkobj.mod = mod;
> -
> -	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
> -	mod->mkobj.kobj.kset = module_kset;
> -	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
> -				   "%s", mod->name);
> -	if (err)
> -		mod_kobject_put(mod);
> -
> -out:
> -	return err;
> -}
> -
> -static int mod_sysfs_setup(struct module *mod,
> -			   const struct load_info *info,
> -			   struct kernel_param *kparam,
> -			   unsigned int num_params)
> -{
> -	int err;
> -
> -	err = mod_sysfs_init(mod);
> -	if (err)
> -		goto out;
> -
> -	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
> -	if (!mod->holders_dir) {
> -		err = -ENOMEM;
> -		goto out_unreg;
> -	}
> -
> -	err = module_param_sysfs_setup(mod, kparam, num_params);
> -	if (err)
> -		goto out_unreg_holders;
> -
> -	err = module_add_modinfo_attrs(mod);
> -	if (err)
> -		goto out_unreg_param;
> -
> -	err = add_usage_links(mod);
> -	if (err)
> -		goto out_unreg_modinfo_attrs;
> -
> -	add_sect_attrs(mod, info);
> -	add_notes_attrs(mod, info);
> -
> -	return 0;
> -
> -out_unreg_modinfo_attrs:
> -	module_remove_modinfo_attrs(mod, -1);
> -out_unreg_param:
> -	module_param_sysfs_remove(mod);
> -out_unreg_holders:
> -	kobject_put(mod->holders_dir);
> -out_unreg:
> -	mod_kobject_put(mod);
> -out:
> -	return err;
> -}
> -
> -static void mod_sysfs_fini(struct module *mod)
> -{
> -	remove_notes_attrs(mod);
> -	remove_sect_attrs(mod);
> -	mod_kobject_put(mod);
> -}
> -
> -static void init_param_lock(struct module *mod)
> -{
> -	mutex_init(&mod->param_lock);
> -}
> -#else /* !CONFIG_SYSFS */
> -
> -static int mod_sysfs_setup(struct module *mod,
> -			   const struct load_info *info,
> -			   struct kernel_param *kparam,
> -			   unsigned int num_params)
> -{
> -	return 0;
> -}
> -
> -static void mod_sysfs_fini(struct module *mod)
> -{
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end)
> -{
> -}
> -
> -static void del_usage_links(struct module *mod)
> -{
> -}
> -
> -static void init_param_lock(struct module *mod)
> -{
> -}
> -#endif /* CONFIG_SYSFS */
> -
> -static void mod_sysfs_teardown(struct module *mod)
> -{
> -	del_usage_links(mod);
> -	module_remove_modinfo_attrs(mod, -1);
> -	module_param_sysfs_remove(mod);
> -	kobject_put(mod->mkobj.drivers_dir);
> -	kobject_put(mod->holders_dir);
> -	mod_sysfs_fini(mod);
> -}
> -
>   /*
>    * LKM RO/NX protection: protect module's text/ro-data
>    * from modification and any data from execution.
> diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c
> new file mode 100644
> index 000000000000..ce68f821dcd1
> --- /dev/null
> +++ b/kernel/module/sysfs.c
> @@ -0,0 +1,436 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module sysfs support
> + *
> + * Copyright (C) 2008 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/fs.h>
> +#include <linux/sysfs.h>
> +#include <linux/slab.h>
> +#include <linux/kallsyms.h>
> +#include <linux/mutex.h>
> +#include "internal.h"
> +
> +/*
> + * /sys/module/foo/sections stuff
> + * J. Corbet <corbet@lwn.net>
> + */
> +#ifdef CONFIG_KALLSYMS
> +struct module_sect_attr {
> +	struct bin_attribute battr;
> +	unsigned long address;
> +};
> +
> +struct module_sect_attrs {
> +	struct attribute_group grp;
> +	unsigned int nsections;
> +	struct module_sect_attr attrs[];
> +};
> +
> +#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
> +static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
> +				struct bin_attribute *battr,
> +				char *buf, loff_t pos, size_t count)
> +{
> +	struct module_sect_attr *sattr =
> +		container_of(battr, struct module_sect_attr, battr);
> +	char bounce[MODULE_SECT_READ_SIZE + 1];
> +	size_t wrote;
> +
> +	if (pos != 0)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since we're a binary read handler, we must account for the
> +	 * trailing NUL byte that sprintf will write: if "buf" is
> +	 * too small to hold the NUL, or the NUL is exactly the last
> +	 * byte, the read will look like it got truncated by one byte.
> +	 * Since there is no way to ask sprintf nicely to not write
> +	 * the NUL, we have to use a bounce buffer.
> +	 */
> +	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
> +			  kallsyms_show_value(file->f_cred)
> +				? (void *)sattr->address : NULL);
> +	count = min(count, wrote);
> +	memcpy(buf, bounce, count);
> +
> +	return count;
> +}
> +
> +static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
> +{
> +	unsigned int section;
> +
> +	for (section = 0; section < sect_attrs->nsections; section++)
> +		kfree(sect_attrs->attrs[section].battr.attr.name);
> +	kfree(sect_attrs);
> +}
> +
> +static void add_sect_attrs(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int nloaded = 0, i, size[2];
> +	struct module_sect_attrs *sect_attrs;
> +	struct module_sect_attr *sattr;
> +	struct bin_attribute **gattr;
> +
> +	/* Count loaded sections and allocate structures */
> +	for (i = 0; i < info->hdr->e_shnum; i++)
> +		if (!sect_empty(&info->sechdrs[i]))
> +			nloaded++;
> +	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
> +			sizeof(sect_attrs->grp.bin_attrs[0]));
> +	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
> +	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
> +	if (!sect_attrs)
> +		return;
> +
> +	/* Setup section attributes. */
> +	sect_attrs->grp.name = "sections";
> +	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
> +
> +	sect_attrs->nsections = 0;
> +	sattr = &sect_attrs->attrs[0];
> +	gattr = &sect_attrs->grp.bin_attrs[0];
> +	for (i = 0; i < info->hdr->e_shnum; i++) {
> +		Elf_Shdr *sec = &info->sechdrs[i];
> +
> +		if (sect_empty(sec))
> +			continue;
> +		sysfs_bin_attr_init(&sattr->battr);
> +		sattr->address = sec->sh_addr;
> +		sattr->battr.attr.name =
> +			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
> +		if (!sattr->battr.attr.name)
> +			goto out;
> +		sect_attrs->nsections++;
> +		sattr->battr.read = module_sect_read;
> +		sattr->battr.size = MODULE_SECT_READ_SIZE;
> +		sattr->battr.attr.mode = 0400;
> +		*(gattr++) = &(sattr++)->battr;
> +	}
> +	*gattr = NULL;
> +
> +	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
> +		goto out;
> +
> +	mod->sect_attrs = sect_attrs;
> +	return;
> +out:
> +	free_sect_attrs(sect_attrs);
> +}
> +
> +static void remove_sect_attrs(struct module *mod)
> +{
> +	if (mod->sect_attrs) {
> +		sysfs_remove_group(&mod->mkobj.kobj,
> +				   &mod->sect_attrs->grp);
> +		/*
> +		 * We are positive that no one is using any sect attrs
> +		 * at this point.  Deallocate immediately.
> +		 */
> +		free_sect_attrs(mod->sect_attrs);
> +		mod->sect_attrs = NULL;
> +	}
> +}
> +
> +/*
> + * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
> + */
> +
> +struct module_notes_attrs {
> +	struct kobject *dir;
> +	unsigned int notes;
> +	struct bin_attribute attrs[];
> +};
> +
> +static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
> +				 struct bin_attribute *bin_attr,
> +				 char *buf, loff_t pos, size_t count)
> +{
> +	/*
> +	 * The caller checked the pos and count against our size.
> +	 */
> +	memcpy(buf, bin_attr->private + pos, count);
> +	return count;
> +}
> +
> +static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
> +			     unsigned int i)
> +{
> +	if (notes_attrs->dir) {
> +		while (i-- > 0)
> +			sysfs_remove_bin_file(notes_attrs->dir,
> +					      &notes_attrs->attrs[i]);
> +		kobject_put(notes_attrs->dir);
> +	}
> +	kfree(notes_attrs);
> +}
> +
> +static void add_notes_attrs(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int notes, loaded, i;
> +	struct module_notes_attrs *notes_attrs;
> +	struct bin_attribute *nattr;
> +
> +	/* failed to create section attributes, so can't create notes */
> +	if (!mod->sect_attrs)
> +		return;
> +
> +	/* Count notes sections and allocate structures.  */
> +	notes = 0;
> +	for (i = 0; i < info->hdr->e_shnum; i++)
> +		if (!sect_empty(&info->sechdrs[i]) &&
> +		    info->sechdrs[i].sh_type == SHT_NOTE)
> +			++notes;
> +
> +	if (notes == 0)
> +		return;
> +
> +	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
> +			      GFP_KERNEL);
> +	if (!notes_attrs)
> +		return;
> +
> +	notes_attrs->notes = notes;
> +	nattr = &notes_attrs->attrs[0];
> +	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
> +		if (sect_empty(&info->sechdrs[i]))
> +			continue;
> +		if (info->sechdrs[i].sh_type == SHT_NOTE) {
> +			sysfs_bin_attr_init(nattr);
> +			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
> +			nattr->attr.mode = 0444;
> +			nattr->size = info->sechdrs[i].sh_size;
> +			nattr->private = (void *)info->sechdrs[i].sh_addr;
> +			nattr->read = module_notes_read;
> +			++nattr;
> +		}
> +		++loaded;
> +	}
> +
> +	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
> +	if (!notes_attrs->dir)
> +		goto out;
> +
> +	for (i = 0; i < notes; ++i)
> +		if (sysfs_create_bin_file(notes_attrs->dir,
> +					  &notes_attrs->attrs[i]))
> +			goto out;
> +
> +	mod->notes_attrs = notes_attrs;
> +	return;
> +
> +out:
> +	free_notes_attrs(notes_attrs, i);
> +}
> +
> +static void remove_notes_attrs(struct module *mod)
> +{
> +	if (mod->notes_attrs)
> +		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
> +}
> +
> +#else /* !CONFIG_KALLSYMS */
> +static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }
> +static inline void remove_sect_attrs(struct module *mod) { }
> +static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }
> +static inline void remove_notes_attrs(struct module *mod) { }
> +#endif /* CONFIG_KALLSYMS */
> +
> +static void del_usage_links(struct module *mod)
> +{
> +#ifdef CONFIG_MODULE_UNLOAD
> +	struct module_use *use;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(use, &mod->target_list, target_list)
> +		sysfs_remove_link(use->target->holders_dir, mod->name);
> +	mutex_unlock(&module_mutex);
> +#endif
> +}
> +
> +static int add_usage_links(struct module *mod)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_MODULE_UNLOAD
> +	struct module_use *use;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(use, &mod->target_list, target_list) {
> +		ret = sysfs_create_link(use->target->holders_dir,
> +					&mod->mkobj.kobj, mod->name);
> +		if (ret)
> +			break;
> +	}
> +	mutex_unlock(&module_mutex);
> +	if (ret)
> +		del_usage_links(mod);
> +#endif
> +	return ret;
> +}
> +
> +static void module_remove_modinfo_attrs(struct module *mod, int end)
> +{
> +	struct module_attribute *attr;
> +	int i;
> +
> +	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
> +		if (end >= 0 && i > end)
> +			break;
> +		/* pick a field to test for end of list */
> +		if (!attr->attr.name)
> +			break;
> +		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
> +		if (attr->free)
> +			attr->free(mod);
> +	}
> +	kfree(mod->modinfo_attrs);
> +}
> +
> +static int module_add_modinfo_attrs(struct module *mod)
> +{
> +	struct module_attribute *attr;
> +	struct module_attribute *temp_attr;
> +	int error = 0;
> +	int i;
> +
> +	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
> +					(modinfo_attrs_count + 1)),
> +					GFP_KERNEL);
> +	if (!mod->modinfo_attrs)
> +		return -ENOMEM;
> +
> +	temp_attr = mod->modinfo_attrs;
> +	for (i = 0; (attr = modinfo_attrs[i]); i++) {
> +		if (!attr->test || attr->test(mod)) {
> +			memcpy(temp_attr, attr, sizeof(*temp_attr));
> +			sysfs_attr_init(&temp_attr->attr);
> +			error = sysfs_create_file(&mod->mkobj.kobj,
> +						  &temp_attr->attr);
> +			if (error)
> +				goto error_out;
> +			++temp_attr;
> +		}
> +	}
> +
> +	return 0;
> +
> +error_out:
> +	if (i > 0)
> +		module_remove_modinfo_attrs(mod, --i);
> +	else
> +		kfree(mod->modinfo_attrs);
> +	return error;
> +}
> +
> +static void mod_kobject_put(struct module *mod)
> +{
> +	DECLARE_COMPLETION_ONSTACK(c);
> +
> +	mod->mkobj.kobj_completion = &c;
> +	kobject_put(&mod->mkobj.kobj);
> +	wait_for_completion(&c);
> +}
> +
> +static int mod_sysfs_init(struct module *mod)
> +{
> +	int err;
> +	struct kobject *kobj;
> +
> +	if (!module_sysfs_initialized) {
> +		pr_err("%s: module sysfs not initialized\n", mod->name);
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	kobj = kset_find_obj(module_kset, mod->name);
> +	if (kobj) {
> +		pr_err("%s: module is already loaded\n", mod->name);
> +		kobject_put(kobj);
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	mod->mkobj.mod = mod;
> +
> +	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
> +	mod->mkobj.kobj.kset = module_kset;
> +	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
> +				   "%s", mod->name);
> +	if (err)
> +		mod_kobject_put(mod);
> +
> +out:
> +	return err;
> +}
> +
> +int mod_sysfs_setup(struct module *mod,
> +		    const struct load_info *info,
> +			   struct kernel_param *kparam,
> +			   unsigned int num_params)
> +{
> +	int err;
> +
> +	err = mod_sysfs_init(mod);
> +	if (err)
> +		goto out;
> +
> +	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
> +	if (!mod->holders_dir) {
> +		err = -ENOMEM;
> +		goto out_unreg;
> +	}
> +
> +	err = module_param_sysfs_setup(mod, kparam, num_params);
> +	if (err)
> +		goto out_unreg_holders;
> +
> +	err = module_add_modinfo_attrs(mod);
> +	if (err)
> +		goto out_unreg_param;
> +
> +	err = add_usage_links(mod);
> +	if (err)
> +		goto out_unreg_modinfo_attrs;
> +
> +	add_sect_attrs(mod, info);
> +	add_notes_attrs(mod, info);
> +
> +	return 0;
> +
> +out_unreg_modinfo_attrs:
> +	module_remove_modinfo_attrs(mod, -1);
> +out_unreg_param:
> +	module_param_sysfs_remove(mod);
> +out_unreg_holders:
> +	kobject_put(mod->holders_dir);
> +out_unreg:
> +	mod_kobject_put(mod);
> +out:
> +	return err;
> +}
> +
> +static void mod_sysfs_fini(struct module *mod)
> +{
> +	remove_notes_attrs(mod);
> +	remove_sect_attrs(mod);
> +	mod_kobject_put(mod);
> +}
> +
> +void mod_sysfs_teardown(struct module *mod)
> +{
> +	del_usage_links(mod);
> +	module_remove_modinfo_attrs(mod, -1);
> +	module_param_sysfs_remove(mod);
> +	kobject_put(mod->mkobj.drivers_dir);
> +	kobject_put(mod->holders_dir);
> +	mod_sysfs_fini(mod);
> +}
> +
> +void init_param_lock(struct module *mod)
> +{
> +	mutex_init(&mod->param_lock);
> +}

  reply	other threads:[~2022-02-22 18:00 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 20:00   ` Allen
2022-02-22 14:12 ` [PATCH v8 02/13] module: Simple refactor in preparation for split Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 03/13] module: Make internal.h and decompress.c more compliant Aaron Tomlin
2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-25  9:34   ` Petr Mladek
2022-02-25 10:33     ` Aaron Tomlin
2022-02-25 16:49     ` Christophe Leroy
2022-02-28 10:56       ` Petr Mladek
2022-02-28 11:46         ` Christophe Leroy
2022-02-28 13:05           ` Petr Mladek
2022-02-22 14:12 ` [PATCH v8 05/13] module: Move latched RB-tree " Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 06/13] module: Move strict rwx " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 07/13] module: Move extra signature support out of core code Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 08/13] module: Move kmemleak support to a separate file Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-25  9:15   ` Petr Mladek
2022-02-25  9:27     ` Christophe Leroy
2022-02-25 10:15       ` Petr Mladek
2022-02-25 10:27         ` Aaron Tomlin
2022-02-25 12:21           ` Aaron Tomlin
2022-02-25 12:57             ` Christophe Leroy
2022-02-26 20:27               ` Luis Chamberlain
2022-02-28  9:02                 ` Christophe Leroy
2022-02-28  9:31                   ` Aaron Tomlin
2022-02-28  9:33                     ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 10/13] module: Move procfs " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 11/13] module: Move sysfs " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy [this message]
2022-02-22 14:13 ` [PATCH v8 12/13] module: Move kdb_modules list out of core code Aaron Tomlin
2022-02-22 18:05   ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 13/13] module: Move version support into a separate file Aaron Tomlin
2022-02-22 18:06   ` Christophe Leroy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d5f11de3-a469-03aa-540f-ac0b803ea5c1@csgroup.eu \
    --to=christophe.leroy@csgroup.eu \
    --cc=akpm@linux-foundation.org \
    --cc=allen.lkml@gmail.com \
    --cc=atomlin@atomlin.com \
    --cc=atomlin@redhat.com \
    --cc=cl@linux.com \
    --cc=jeyu@kernel.org \
    --cc=joe@perches.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-modules@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=mcgrof@kernel.org \
    --cc=msuchanek@suse.de \
    --cc=oleksandr@natalenko.name \
    --cc=pmladek@suse.com \
    --cc=void@manifault.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.