Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d53c51f2 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

s390/cio: fix accidental interrupt enabling during resume



Since commit 9f3d6d7a chsc_get_channel_measurement_chars is called with
interrupts disabled during resume from hibernate. Since this function
used spin_unlock_irq, interrupts have been enabled accidentally. Fix
this by using the irqsave variant.

Since we can't guarantee the IRQ-enablement state for all (future/
external) callers, change the locking in related functions to prevent
similar bugs in the future.

Fixes: 9f3d6d7a ("s390/cio: update measurement characteristics")
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: default avatarPeter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 871f8bf0
Loading
Loading
Loading
Loading
+12 −8
Original line number Original line Diff line number Diff line
@@ -95,12 +95,13 @@ struct chsc_ssd_area {
int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
{
{
	struct chsc_ssd_area *ssd_area;
	struct chsc_ssd_area *ssd_area;
	unsigned long flags;
	int ccode;
	int ccode;
	int ret;
	int ret;
	int i;
	int i;
	int mask;
	int mask;


	spin_lock_irq(&chsc_page_lock);
	spin_lock_irqsave(&chsc_page_lock, flags);
	memset(chsc_page, 0, PAGE_SIZE);
	memset(chsc_page, 0, PAGE_SIZE);
	ssd_area = chsc_page;
	ssd_area = chsc_page;
	ssd_area->request.length = 0x0010;
	ssd_area->request.length = 0x0010;
@@ -144,7 +145,7 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
			ssd->fla[i] = ssd_area->fla[i];
			ssd->fla[i] = ssd_area->fla[i];
	}
	}
out:
out:
	spin_unlock_irq(&chsc_page_lock);
	spin_unlock_irqrestore(&chsc_page_lock, flags);
	return ret;
	return ret;
}
}


@@ -832,9 +833,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
		u32 fmt : 4;
		u32 fmt : 4;
		u32 : 16;
		u32 : 16;
	} __attribute__ ((packed)) *secm_area;
	} __attribute__ ((packed)) *secm_area;
	unsigned long flags;
	int ret, ccode;
	int ret, ccode;


	spin_lock_irq(&chsc_page_lock);
	spin_lock_irqsave(&chsc_page_lock, flags);
	memset(chsc_page, 0, PAGE_SIZE);
	memset(chsc_page, 0, PAGE_SIZE);
	secm_area = chsc_page;
	secm_area = chsc_page;
	secm_area->request.length = 0x0050;
	secm_area->request.length = 0x0050;
@@ -864,7 +866,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
		CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
		CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
			      secm_area->response.code);
			      secm_area->response.code);
out:
out:
	spin_unlock_irq(&chsc_page_lock);
	spin_unlock_irqrestore(&chsc_page_lock, flags);
	return ret;
	return ret;
}
}


@@ -992,6 +994,7 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,


int chsc_get_channel_measurement_chars(struct channel_path *chp)
int chsc_get_channel_measurement_chars(struct channel_path *chp)
{
{
	unsigned long flags;
	int ccode, ret;
	int ccode, ret;


	struct {
	struct {
@@ -1021,7 +1024,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
	if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
	if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
		return -EINVAL;
		return -EINVAL;


	spin_lock_irq(&chsc_page_lock);
	spin_lock_irqsave(&chsc_page_lock, flags);
	memset(chsc_page, 0, PAGE_SIZE);
	memset(chsc_page, 0, PAGE_SIZE);
	scmc_area = chsc_page;
	scmc_area = chsc_page;
	scmc_area->request.length = 0x0010;
	scmc_area->request.length = 0x0010;
@@ -1053,7 +1056,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
	chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
	chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
				  (struct cmg_chars *) &scmc_area->data);
				  (struct cmg_chars *) &scmc_area->data);
out:
out:
	spin_unlock_irq(&chsc_page_lock);
	spin_unlock_irqrestore(&chsc_page_lock, flags);
	return ret;
	return ret;
}
}


@@ -1134,6 +1137,7 @@ struct css_chsc_char css_chsc_characteristics;
int __init
int __init
chsc_determine_css_characteristics(void)
chsc_determine_css_characteristics(void)
{
{
	unsigned long flags;
	int result;
	int result;
	struct {
	struct {
		struct chsc_header request;
		struct chsc_header request;
@@ -1146,7 +1150,7 @@ chsc_determine_css_characteristics(void)
		u32 chsc_char[508];
		u32 chsc_char[508];
	} __attribute__ ((packed)) *scsc_area;
	} __attribute__ ((packed)) *scsc_area;


	spin_lock_irq(&chsc_page_lock);
	spin_lock_irqsave(&chsc_page_lock, flags);
	memset(chsc_page, 0, PAGE_SIZE);
	memset(chsc_page, 0, PAGE_SIZE);
	scsc_area = chsc_page;
	scsc_area = chsc_page;
	scsc_area->request.length = 0x0010;
	scsc_area->request.length = 0x0010;
@@ -1168,7 +1172,7 @@ chsc_determine_css_characteristics(void)
		CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
		CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
			      scsc_area->response.code);
			      scsc_area->response.code);
exit:
exit:
	spin_unlock_irq(&chsc_page_lock);
	spin_unlock_irqrestore(&chsc_page_lock, flags);
	return result;
	return result;
}
}