lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 16 Apr 2019 12:21:30 +0200
From:   Borislav Petkov <bp@...en8.de>
To:     "Ghannam, Yazen" <Yazen.Ghannam@....com>
Cc:     "linux-edac@...r.kernel.org" <linux-edac@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        "bp@...e.de" <bp@...e.de>,
        "tony.luck@...el.com" <tony.luck@...el.com>,
        "x86@...nel.org" <x86@...nel.org>
Subject: Re: [PATCH v2 2/6] x86/MCE: Handle MCA controls in a per_cpu way

On Thu, Apr 11, 2019 at 08:18:01PM +0000, Ghannam, Yazen wrote:
>  arch/x86/kernel/cpu/mce/core.c | 77 ++++++++++++++++++++++------------
>  1 file changed, 51 insertions(+), 26 deletions(-)
> 
> diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
> index 8d0d1e8425db..aa41f41e5931 100644
> --- a/arch/x86/kernel/cpu/mce/core.c
> +++ b/arch/x86/kernel/cpu/mce/core.c
> @@ -64,16 +64,21 @@ static DEFINE_MUTEX(mce_sysfs_mutex);
>  
>  DEFINE_PER_CPU(unsigned, mce_exception_count);
>  
> +struct mce_bank {
> +	u64	ctl;	/* subevents to enable */
> +	bool	init;	/* initialise bank? */
> +};

Pls keep original members alignment.

> +static DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank *, mce_banks);
> +
>  #define ATTR_LEN               16
>  /* One object for each MCE bank, shared by all CPUs */
> -struct mce_bank {
> -	u64			ctl;			/* subevents to enable */
> -	bool			init;			/* initialise bank? */
> +struct mce_bank_dev {
>  	struct device_attribute	attr;			/* device attribute */
>  	char			attrname[ATTR_LEN];	/* attribute name */
> +	u8			bank;			/* bank number */
>  };
> +static struct mce_bank_dev mce_bank_devs[MAX_NR_BANKS];
>  
> -static struct mce_bank *mce_banks __read_mostly;
>  struct mce_vendor_flags mce_flags __read_mostly;
>  
>  struct mca_config mca_cfg __read_mostly = {
> @@ -695,7 +700,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
>  		m.tsc = rdtsc();
>  
>  	for (i = 0; i < mca_cfg.banks; i++) {
> -		if (!mce_banks[i].ctl || !test_bit(i, *b))
> +		if (!this_cpu_read(mce_banks)[i].ctl || !test_bit(i, *b))
>  			continue;
>  
>  		m.misc = 0;
> @@ -1138,7 +1143,7 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
>  		if (!test_bit(i, valid_banks))
>  			continue;
>  
> -		if (!mce_banks[i].ctl)
> +		if (!this_cpu_read(mce_banks)[i].ctl)
>  			continue;
>  
>  		m->misc = 0;
> @@ -1475,16 +1480,19 @@ static int __mcheck_cpu_mce_banks_init(void)
>  {
>  	int i;
>  
> -	mce_banks = kcalloc(MAX_NR_BANKS, sizeof(struct mce_bank), GFP_KERNEL);
> -	if (!mce_banks)
> +	per_cpu(mce_banks, smp_processor_id()) =
> +		kcalloc(MAX_NR_BANKS, sizeof(struct mce_bank), GFP_KERNEL);
> +
> +	if (!this_cpu_read(mce_banks))
>  		return -ENOMEM;
>  
>  	for (i = 0; i < MAX_NR_BANKS; i++) {
> -		struct mce_bank *b = &mce_banks[i];
> +		struct mce_bank *b = &this_cpu_read(mce_banks)[i];
>  
>  		b->ctl = -1ULL;
>  		b->init = 1;
>  	}
> +
>  	return 0;
>  }

Instead of doing all those per-CPU accesses in the function, you can use
a local pointer and assign it once in the end, before returning.

Also, fix the similar situation where you have multiple per-CPU accesses
in a single function - assign to a local pointer instead and do all the
accesses through it.

> @@ -1504,7 +1512,7 @@ static int __mcheck_cpu_cap_init(void)
>  
>  	mca_cfg.banks = max(mca_cfg.banks, b);
>  
> -	if (!mce_banks) {
> +	if (!this_cpu_read(mce_banks)) {
>  		int err = __mcheck_cpu_mce_banks_init();
>  		if (err)
>  			return err;
> @@ -1547,7 +1555,7 @@ static void __mcheck_cpu_init_clear_banks(void)
>  	int i;
>  
>  	for (i = 0; i < mca_cfg.banks; i++) {
> -		struct mce_bank *b = &mce_banks[i];
> +		struct mce_bank *b = &this_cpu_read(mce_banks)[i];
>  
>  		if (!b->init)
>  			continue;
> @@ -1602,7 +1610,7 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
>  			 * trips off incorrectly with the IOMMU & 3ware
>  			 * & Cerberus:
>  			 */
> -			clear_bit(10, (unsigned long *)&mce_banks[4].ctl);
> +			clear_bit(10, (unsigned long *)&this_cpu_read(mce_banks)[4].ctl);
>  		}
>  		if (c->x86 < 0x11 && cfg->bootlog < 0) {
>  			/*
> @@ -1616,7 +1624,7 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
>  		 * by default.
>  		 */
>  		if (c->x86 == 6 && cfg->banks > 0)
> -			mce_banks[0].ctl = 0;
> +			this_cpu_read(mce_banks)[0].ctl = 0;
>  
>  		/*
>  		 * overflow_recov is supported for F15h Models 00h-0fh
> @@ -1638,7 +1646,7 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
>  		 */
>  
>  		if (c->x86 == 6 && c->x86_model < 0x1A && cfg->banks > 0)
> -			mce_banks[0].init = 0;
> +			this_cpu_read(mce_banks)[0].init = 0;
>  
>  		/*
>  		 * All newer Intel systems support MCE broadcasting. Enable
> @@ -1952,7 +1960,7 @@ static void mce_disable_error_reporting(void)
>  	int i;
>  
>  	for (i = 0; i < mca_cfg.banks; i++) {
> -		struct mce_bank *b = &mce_banks[i];
> +		struct mce_bank *b = &this_cpu_read(mce_banks)[i];
>  
>  		if (b->init)
>  			wrmsrl(msr_ops.ctl(i), 0);
> @@ -2051,26 +2059,41 @@ static struct bus_type mce_subsys = {
>  
>  DEFINE_PER_CPU(struct device *, mce_device);
>  
> -static inline struct mce_bank *attr_to_bank(struct device_attribute *attr)
> +static inline struct mce_bank_dev *attr_to_bank(struct device_attribute *attr)
>  {
> -	return container_of(attr, struct mce_bank, attr);
> +	return container_of(attr, struct mce_bank_dev, attr);
>  }
>  
>  static ssize_t show_bank(struct device *s, struct device_attribute *attr,
>  			 char *buf)
>  {
> -	return sprintf(buf, "%llx\n", attr_to_bank(attr)->ctl);
> +	struct mce_bank *b;
> +	u8 bank = attr_to_bank(attr)->bank;

Please sort function local variables declaration in a reverse christmas
tree order:

	<type A> longest_variable_name;
	<type B> shorter_var_name;
	<type C> even_shorter;
	<type D> i;

> +
> +	if (bank >= mca_cfg.banks)
> +		return -EINVAL;
> +
> +	b = &per_cpu(mce_banks, s->id)[bank];
> +
> +	return sprintf(buf, "%llx\n", b->ctl);
>  }
>  
>  static ssize_t set_bank(struct device *s, struct device_attribute *attr,
>  			const char *buf, size_t size)
>  {
>  	u64 new;
> +	struct mce_bank *b;
> +	u8 bank = attr_to_bank(attr)->bank;

Ditto.

>  	if (kstrtou64(buf, 0, &new) < 0)
>  		return -EINVAL;
>  
> -	attr_to_bank(attr)->ctl = new;
> +	if (bank >= mca_cfg.banks)
> +		return -EINVAL;
> +
> +	b = &per_cpu(mce_banks, s->id)[bank];
> +
> +	b->ctl = new;
>  	mce_restart();
>  
>  	return size;
> @@ -2185,7 +2208,7 @@ static void mce_device_release(struct device *dev)
>  	kfree(dev);
>  }
>  
> -/* Per cpu device init. All of the cpus still share the same ctrl bank: */
> +/* Per cpu device init. All of the cpus still share the same bank device: */

s/cpu/CPU/g, while at it.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

Powered by blists - more mailing lists