Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/cio: fix accidental interrupt enabling during resume

Since commit 9f3d6d7 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: 9f3d6d7 ("s390/cio: update measurement characteristics")
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
d53c51f2 871f8bf0

+12 -8
+12 -8
drivers/s390/cio/chsc.c
··· 95 95 int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) 96 96 { 97 97 struct chsc_ssd_area *ssd_area; 98 + unsigned long flags; 98 99 int ccode; 99 100 int ret; 100 101 int i; 101 102 int mask; 102 103 103 - spin_lock_irq(&chsc_page_lock); 104 + spin_lock_irqsave(&chsc_page_lock, flags); 104 105 memset(chsc_page, 0, PAGE_SIZE); 105 106 ssd_area = chsc_page; 106 107 ssd_area->request.length = 0x0010; ··· 145 144 ssd->fla[i] = ssd_area->fla[i]; 146 145 } 147 146 out: 148 - spin_unlock_irq(&chsc_page_lock); 147 + spin_unlock_irqrestore(&chsc_page_lock, flags); 149 148 return ret; 150 149 } 151 150 ··· 833 832 u32 fmt : 4; 834 833 u32 : 16; 835 834 } __attribute__ ((packed)) *secm_area; 835 + unsigned long flags; 836 836 int ret, ccode; 837 837 838 - spin_lock_irq(&chsc_page_lock); 838 + spin_lock_irqsave(&chsc_page_lock, flags); 839 839 memset(chsc_page, 0, PAGE_SIZE); 840 840 secm_area = chsc_page; 841 841 secm_area->request.length = 0x0050; ··· 866 864 CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", 867 865 secm_area->response.code); 868 866 out: 869 - spin_unlock_irq(&chsc_page_lock); 867 + spin_unlock_irqrestore(&chsc_page_lock, flags); 870 868 return ret; 871 869 } 872 870 ··· 994 992 995 993 int chsc_get_channel_measurement_chars(struct channel_path *chp) 996 994 { 995 + unsigned long flags; 997 996 int ccode, ret; 998 997 999 998 struct { ··· 1024 1021 if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm) 1025 1022 return -EINVAL; 1026 1023 1027 - spin_lock_irq(&chsc_page_lock); 1024 + spin_lock_irqsave(&chsc_page_lock, flags); 1028 1025 memset(chsc_page, 0, PAGE_SIZE); 1029 1026 scmc_area = chsc_page; 1030 1027 scmc_area->request.length = 0x0010; ··· 1056 1053 chsc_initialize_cmg_chars(chp, scmc_area->cmcv, 1057 1054 (struct cmg_chars *) &scmc_area->data); 1058 1055 out: 1059 - spin_unlock_irq(&chsc_page_lock); 1056 + spin_unlock_irqrestore(&chsc_page_lock, flags); 1060 1057 return ret; 1061 1058 } 1062 1059 ··· 1137 1134 int __init 1138 1135 chsc_determine_css_characteristics(void) 1139 1136 { 1137 + unsigned long flags; 1140 1138 int result; 1141 1139 struct { 1142 1140 struct chsc_header request; ··· 1150 1146 u32 chsc_char[508]; 1151 1147 } __attribute__ ((packed)) *scsc_area; 1152 1148 1153 - spin_lock_irq(&chsc_page_lock); 1149 + spin_lock_irqsave(&chsc_page_lock, flags); 1154 1150 memset(chsc_page, 0, PAGE_SIZE); 1155 1151 scsc_area = chsc_page; 1156 1152 scsc_area->request.length = 0x0010; ··· 1172 1168 CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", 1173 1169 scsc_area->response.code); 1174 1170 exit: 1175 - spin_unlock_irq(&chsc_page_lock); 1171 + spin_unlock_irqrestore(&chsc_page_lock, flags); 1176 1172 return result; 1177 1173 } 1178 1174