All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jean Delvare <jdelvare@suse.de>
To: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
Cc: linux-kernel@vger.kernel.org, matt.fleming@intel.com,
	ard.biesheuvel@linaro.org, grant.likely@linaro.org,
	linux-api@vger.kernel.org, linux-doc@vger.kernel.org,
	mikew@google.com, dmidecode-devel@nongnu.org,
	leif.lindholm@linaro.org, msalter@redhat.com,
	roy.franz@linaro.org
Subject: Re: [Patch 2/3] firmware: dmi_scan: add SBMIOS entry and DMI tables
Date: Thu, 16 Apr 2015 11:52:52 +0200	[thread overview]
Message-ID: <20150416115252.7dc964a3@endymion.delvare> (raw)
In-Reply-To: <1427979423-22767-3-git-send-email-ivan.khoronzhuk@globallogic.com>

Hi Ivan,

On Thu,  2 Apr 2015 15:57:02 +0300, Ivan Khoronzhuk wrote:
> Some utils, like dmidecode and smbios, need to access SMBIOS entry
> table area in order to get information like SMBIOS version, size, etc.
> Currently it's done via /dev/mem. But for situation when /dev/mem
> usage is disabled, the utils have to use dmi sysfs instead, which
> doesn't represent SMBIOS entry and adds code/delay redundancy when direct
> access for table is needed.
> 
> So this patch creates dmi/tables and adds SMBIOS entry point to allow
> utils in question to work correctly without /dev/mem. Also patch adds
> raw dmi table to simplify dmi table processing in user space, as
> proposed by Jean Delvare.
> 
> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
> ---
>  .../ABI/testing/sysfs-firmware-dmi-tables          | 22 ++++++
>  drivers/firmware/dmi-sysfs.c                       | 11 ++-
>  drivers/firmware/dmi_scan.c                        | 80 ++++++++++++++++++++++
>  include/linux/dmi.h                                |  1 +
>  4 files changed, 107 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-firmware-dmi-tables

First of all: thanks for doing this, it looks mostly good now, and I've
tested it successfully on my own system.

> diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi-tables b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
> new file mode 100644
> index 0000000..f46158c
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
> @@ -0,0 +1,22 @@
> +What:		/sys/firmware/dmi/tables/
> +Date:		April 2015
> +Contact:	Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
> +Description:
> +		The firmware provides DMI structures as a packed list of
> +		data referenced by a SMBIOS table entry point. The SMBIOS
> +		entry point contains general information, like SMBIOS
> +		version, DMI table size, etc. The structure, content and
> +		size of SMBIOS entry point is dependent on SMBIOS version.
> +		The format of SMBIOS entry point, equal as DMI structures
> +		can be read in SMBIOS specification.

"equal as" sounds strange, I think a simple "and" would be better.

> +
> +		The dmi/tables provides raw SMBIOS entry point and DMI tables
> +		through sysfs as an alternative to utilities reading them
> +		from /dev/mem. The raw SMBIOS entry point and DMI table are
> +		presented as raw attributes and are accessible via:

"binary attributes" rather than "raw attributes"? The "raw" nature is
already mentioned earlier in the sentence.

> +
> +		/sys/firmware/dmi/tables/smbios_entry_point
> +		/sys/firmware/dmi/tables/DMI
> +
> +		The complete DMI information can be taken using these two

"obtained" or "decoded" would sound better than "taken" IMHO.

> +		tables.
> diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
> index e0f1cb3..8e1a411 100644
> --- a/drivers/firmware/dmi-sysfs.c
> +++ b/drivers/firmware/dmi-sysfs.c
> @@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
>  	.default_attrs = dmi_sysfs_entry_attrs,
>  };
>  
> -static struct kobject *dmi_kobj;
>  static struct kset *dmi_kset;
>  
>  /* Global count of all instances seen.  Only for setup */
> @@ -651,10 +650,11 @@ static int __init dmi_sysfs_init(void)
>  	int error = -ENOMEM;

This initialization can be moved to the single error path left that
needs it. (I can do it myself in a separate patch if you don't want to
do it here.)

>  	int val;
>  
> -	/* Set up our directory */
> -	dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
> -	if (!dmi_kobj)
> +	if (!dmi_kobj) {
> +		pr_err("dmi-sysfs: dmi entry is absent.\n");
> +		error = -ENOSYS;
>  		goto err;
> +	}
>  
>  	dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
>  	if (!dmi_kset)
> @@ -675,7 +675,6 @@ static int __init dmi_sysfs_init(void)
>  err:
>  	cleanup_entry_list();
>  	kset_unregister(dmi_kset);
> -	kobject_put(dmi_kobj);
>  	return error;
>  }
>  
> @@ -685,8 +684,6 @@ static void __exit dmi_sysfs_exit(void)
>  	pr_debug("dmi-sysfs: unloading.\n");
>  	cleanup_entry_list();
>  	kset_unregister(dmi_kset);
> -	kobject_del(dmi_kobj);
> -	kobject_put(dmi_kobj);
>  }
>  
>  module_init(dmi_sysfs_init);
> diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
> index d3aae09..bb19f8b 100644
> --- a/drivers/firmware/dmi_scan.c
> +++ b/drivers/firmware/dmi_scan.c
> @@ -10,6 +10,9 @@
>  #include <asm/dmi.h>
>  #include <asm/unaligned.h>
>  
> +struct kobject *dmi_kobj;
> +EXPORT_SYMBOL_GPL(dmi_kobj);
> +
>  /*
>   * DMI stands for "Desktop Management Interface".  It is part
>   * of and an antecedent to, SMBIOS, which stands for System
> @@ -20,6 +23,9 @@ static const char dmi_empty_string[] = "        ";
>  static u32 dmi_ver __initdata;
>  static u32 dmi_len;
>  static u16 dmi_num;
> +static u8 smbios_entry_point[32];
> +static int smbios_entry_point_size;
> +
>  /*
>   * Catch too early calls to dmi_check_system():
>   */
> @@ -118,6 +124,7 @@ static void dmi_decode_table(u8 *buf,
>  }
>  
>  static phys_addr_t dmi_base;
> +static u8 *dmi_table;

This variable is only ever used in a single function (dmi_init). Does
it actually need to be a global variable? I suspect not.

>  
>  static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
>  		void *))
> @@ -476,6 +483,8 @@ static int __init dmi_present(const u8 *buf)
>  	if (memcmp(buf, "_SM_", 4) == 0 &&
>  	    buf[5] < 32 && dmi_checksum(buf, buf[5])) {
>  		smbios_ver = get_unaligned_be16(buf + 6);
> +		smbios_entry_point_size = buf[5];
> +		memcpy(smbios_entry_point, buf, smbios_entry_point_size);
>  
>  		/* Some BIOS report weird SMBIOS version, fix that up */
>  		switch (smbios_ver) {
> @@ -508,6 +517,9 @@ static int __init dmi_present(const u8 *buf)
>  					dmi_ver >> 8, dmi_ver & 0xFF,
>  					(dmi_ver < 0x0300) ? "" : ".x");
>  			} else {
> +				smbios_entry_point_size = 15;
> +				memcpy(smbios_entry_point, buf,
> +				       smbios_entry_point_size);
>  				dmi_ver = (buf[14] & 0xF0) << 4 |
>  					   (buf[14] & 0x0F);
>  				pr_info("Legacy DMI %d.%d present.\n",
> @@ -535,6 +547,8 @@ static int __init dmi_smbios3_present(const u8 *buf)
>  		dmi_ver &= 0xFFFFFF;
>  		dmi_len = get_unaligned_le32(buf + 12);
>  		dmi_base = get_unaligned_le64(buf + 16);
> +		smbios_entry_point_size = buf[6];
> +		memcpy(smbios_entry_point, buf, smbios_entry_point_size);
>  
>  		/*
>  		 * The 64-bit SMBIOS 3.0 entry point no longer has a field
> @@ -638,6 +652,72 @@ void __init dmi_scan_machine(void)
>  	dmi_initialized = 1;
>  }
>  
> +static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
> +			      struct bin_attribute *attr, char *buf,
> +			      loff_t pos, size_t count)
> +{
> +	memcpy(buf, attr->private + pos, count);
> +	return count;
> +}
> +
> +static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);

This one could be world-readable as it contains no sensitive
information.

> +struct bin_attribute bin_attr_dmi_table =
> +			__BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);

I do not understand why you don't use BIN_ATTR here too? I tried naming
the attribute bin_attr_DMI and it seems to work just fine, checkpatch
doesn't even complain!

> +
> +static int __init dmi_init(void)
> +{
> +	int ret = -ENOMEM;
> +	struct kobject *tables_kobj = NULL;
> +
> +	if (!dmi_available) {
> +		ret = -ENOSYS;
> +		goto err;
> +	}

This is weird. Can this actually happen?

We currently have two ways to enter this module: dmi_scan_machine(),
which is called by the architecture code, and dmi_init(), which is
called at subsys_initcall time. As far as I can see,
core/arch_initcalls are guaranteed to be always called before
subsys_initcalls. If we can rely on that, the test above is not needed.
If for any reason we can't, that means that dmi_init() should not be a
subsys_initcall, but should instead be called explicitly at the end of
dmi_scan_machine().

> +
> +	/* Set up dmi directory at /sys/firmware/dmi */
> +	dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
> +	if (!dmi_kobj)
> +		goto err;
> +
> +	tables_kobj = kobject_create_and_add("tables", dmi_kobj);
> +	if (!tables_kobj)
> +		goto err;
> +
> +	bin_attr_smbios_entry_point.size = smbios_entry_point_size;
> +	bin_attr_smbios_entry_point.private = smbios_entry_point;
> +	ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
> +	if (ret)
> +		goto err;
> +
> +	dmi_table = dmi_remap(dmi_base, dmi_len);
> +	if (!dmi_table)
> +		goto err;

At this point "ret" has value 0 so you will take the error path but
return with success. No good. I suggest that you move the call to
dmi_remap before the first call to sysfs_create_bin_file above, so that
"ret" still has value -ENOMEM.

> +
> +	bin_attr_dmi_table.size = dmi_len;
> +	bin_attr_dmi_table.private = dmi_table;
> +	ret = sysfs_create_bin_file(tables_kobj, &bin_attr_dmi_table);
> +	if (ret) {
> +		dmi_unmap(dmi_table);

Doing this here goes against the logic of having a single error path.
Instead you should have an additional error label before err: and jump
there.

> +		goto err;
> +	}
> +
> +	return 0;
> +err:
> +	pr_err("dmi: Firmware registration failed.\n");
> +
> +	if (tables_kobj)
> +		sysfs_remove_bin_file(tables_kobj,
> +				      &bin_attr_smbios_entry_point);
> +	kobject_del(tables_kobj);
> +	kobject_put(tables_kobj);

These last two calls could be moved inside the conditional above. Even
better would be a separate error label so that you know exactly what
needs to be undone.

> +	kobject_del(dmi_kobj);
> +	kobject_put(dmi_kobj);
> +	dmi_kobj = NULL;

I'm wondering, wouldn't it make sense to keep dmi_kobj alive (with an
appropriate comment), so that dmi-sysfs has a chance to load? As it is
now, a bug or some unexpected behavior in this new code could cause a
regression for dmi-sysfs users. Just because I don't like dmi_sysfs
doesn't mean we can break it ;-)

> +
> +	return ret;
> +}
> +subsys_initcall(dmi_init);
> +
>  /**
>   * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
>   *
> diff --git a/include/linux/dmi.h b/include/linux/dmi.h
> index f820f0a..9f55f46 100644
> --- a/include/linux/dmi.h
> +++ b/include/linux/dmi.h
> @@ -93,6 +93,7 @@ struct dmi_dev_onboard {
>  	int devfn;
>  };
>  
> +extern struct kobject *dmi_kobj;

struct kobject is defined in <linux/kobject.h> so I think you should
include that file to avoid random build failures in the future.

>  extern int dmi_check_system(const struct dmi_system_id *list);
>  const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
>  extern const char * dmi_get_system_info(int field);


-- 
Jean Delvare
SUSE L3 Support

  parent reply	other threads:[~2015-04-16  9:53 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-02 12:57 [Patch 0/3] firmware: dmi_scan: add SBMIOS entry point and DMI tables Ivan Khoronzhuk
2015-04-02 12:57 ` Ivan Khoronzhuk
2015-04-02 12:57 ` [Patch 1/3] firmware: dmi_scan: rename dmi_table to dmi_decode_table Ivan Khoronzhuk
2015-04-02 12:57   ` Ivan Khoronzhuk
2015-04-15 11:51   ` Jean Delvare
2015-04-15 14:35   ` Matt Fleming
2015-04-15 14:35     ` Matt Fleming
2015-04-16  8:35     ` Jean Delvare
2015-04-16  8:35       ` Jean Delvare
2015-04-16 20:16       ` Ivan.khoronzhuk
2015-04-17  8:54         ` Jean Delvare
2015-04-17 10:11           ` Ivan.khoronzhuk
2015-04-17 12:04             ` Ivan.khoronzhuk
2015-04-17 12:50               ` Jean Delvare
2015-04-17 12:50                 ` Jean Delvare
2015-04-17 13:40       ` Matt Fleming
2015-04-17 14:12         ` Jean Delvare
2015-04-17 14:12           ` [dmidecode] " Jean Delvare
2015-04-02 12:57 ` [Patch 2/3] firmware: dmi_scan: add SBMIOS entry and DMI tables Ivan Khoronzhuk
2015-04-02 12:57   ` Ivan Khoronzhuk
2015-04-03  9:36   ` Ivan.khoronzhuk
2015-04-15  4:19     ` Roy Franz
2015-04-15  4:19       ` Roy Franz
2015-04-16  0:54       ` Roy Franz
2015-04-16  0:54         ` Roy Franz
2015-04-16  6:48         ` Jean Delvare
2015-04-16  6:48           ` Jean Delvare
2015-04-16 17:08           ` Roy Franz
2015-04-16  9:52   ` Jean Delvare [this message]
2015-04-16 12:56     ` Ivan.khoronzhuk
2015-04-16 12:56       ` Ivan.khoronzhuk
2015-04-16 15:44       ` Jean Delvare
2015-04-16 15:44         ` [dmidecode] " Jean Delvare
2015-04-16 17:27         ` subscivan
2015-04-16 17:32           ` Ivan.khoronzhuk
2015-04-16 17:32             ` Ivan.khoronzhuk
2015-04-17 13:02           ` Jean Delvare
2015-04-17 13:02             ` Jean Delvare
2015-04-02 12:57 ` [Patch 3/3] Documentation: ABI: sysfs-firmware-dmi: add -entries suffix to file name Ivan Khoronzhuk
2015-04-02 12:57   ` Ivan Khoronzhuk
2015-04-15 11:52   ` Jean Delvare

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=20150416115252.7dc964a3@endymion.delvare \
    --to=jdelvare@suse.de \
    --cc=ard.biesheuvel@linaro.org \
    --cc=dmidecode-devel@nongnu.org \
    --cc=grant.likely@linaro.org \
    --cc=ivan.khoronzhuk@globallogic.com \
    --cc=leif.lindholm@linaro.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=matt.fleming@intel.com \
    --cc=mikew@google.com \
    --cc=msalter@redhat.com \
    --cc=roy.franz@linaro.org \
    /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.