From: Hans-Joachim Picht <hpicht@redhat.com> Date: Fri, 25 Apr 2008 15:06:48 +0200 Subject: [s390] cio: kernel panic in cm_enable processing Message-id: 20080425130648.GA22728@redhat.com O-Subject: [RHEL5 U3 PATCH 1/5] s390 - cio: kernel panic in cm_enable processing Bugzilla: 442032 RH-Acked-by: Alan Cox <alan@redhat.com> RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> Description ============ A kernel panic occurs when cm_enable processing is triggered several times in parallel. The decision whether to add or to remove cm files and the processing itself are done separately, which might cause inconsistencies when this is triggered several times in parallel. Serializing cm_enable processing by mutex_locks on store level is used to fix the problem Bugzilla ========= BZ 442032 https://bugzilla.redhat.com/show_bug.cgi?id=442032 Upstream status of the patch: ============================= Patch is contained in linux-2.6 as git commit 8284fb19efa1f11ea8dd213e9e227fc1fcb20586 Test status: ============ The patch has been tested and fixes the problem. The fix has been verified by the IBM test department. Please ACK. With best regards, Hans drivers/s390/cio/chsc.c | 3 --- drivers/s390/cio/css.c | 10 +++++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index a89c6f3..8cc32d1 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -969,7 +969,6 @@ chsc_secm(struct channel_subsystem *css, int enable) if (!secm_area) return -ENOMEM; - mutex_lock(&css->mutex); if (enable && !css->cm_enabled) { css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); @@ -977,7 +976,6 @@ chsc_secm(struct channel_subsystem *css, int enable) free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); free_page((unsigned long)secm_area); - mutex_unlock(&css->mutex); return -ENOMEM; } } @@ -998,7 +996,6 @@ chsc_secm(struct channel_subsystem *css, int enable) free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); } - mutex_unlock(&css->mutex); free_page((unsigned long)secm_area); return ret; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0e04fd3..651117e 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -548,10 +548,14 @@ css_cm_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_subsystem *css = to_css(dev); + int ret; if (!css) return 0; - return sprintf(buf, "%x\n", css->cm_enabled); + mutex_lock(&css->mutex); + ret = sprintf(buf, "%x\n", css->cm_enabled); + mutex_unlock(&css->mutex); + return ret; } static ssize_t @@ -561,6 +565,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, struct channel_subsystem *css = to_css(dev); int ret; + mutex_lock(&css->mutex); switch (buf[0]) { case '0': ret = css->cm_enabled ? chsc_secm(css, 0) : 0; @@ -571,6 +576,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, default: ret = -EINVAL; } + mutex_unlock(&css->mutex); return ret < 0 ? ret : count; } @@ -599,8 +605,10 @@ static int css_reboot_event(struct notifier_block *this, ret = 0; for (i = 0; i <= __MAX_CSSID && !ret; i++) { + mutex_lock(&css[i]->mutex); if (css[i]->cm_enabled) ret = chsc_secm(css[i], 0); + mutex_unlock(&css[i]->mutex); } return ret ? NOTIFY_BAD : NOTIFY_DONE;