summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>2016-07-25 08:52:28 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-07-31 05:27:58 -0400
commitd6d86c57d77d466df2096b134e5f54463d3f0fb8 (patch)
treee228aa3826f9e587db7c2d5f88e0e6f36da78477
parent4475aeb8b77db34dea96b09900ba0cb245b6fb42 (diff)
s390/zcrypt: Fix zcrypt suspend/resume behavior
The device suspend call triggers all ap devices to fetch potentially available response messages from the queues. Therefore the corresponding zcrypt device, that is allocated asynchronously after ap device probing, needs to be fully prepared. This race condition could lead to uninitialized response buffers while trying to read from the queues. Introduce a new callback within the ap layer to get noticed when a zcrypt device is fully prepared. Additional checks prevent reading from devices that are not fully prepared. Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/crypto/ap_bus.c46
-rw-r--r--drivers/s390/crypto/ap_bus.h1
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c2
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c2
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c2
5 files changed, 47 insertions, 6 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 4feb27215ab6..03e4d6246d87 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -468,6 +468,8 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
468{ 468{
469 struct ap_queue_status status; 469 struct ap_queue_status status;
470 470
471 if (msg == NULL)
472 return -EINVAL;
471 status = __ap_recv(qid, psmid, msg, length); 473 status = __ap_recv(qid, psmid, msg, length);
472 switch (status.response_code) { 474 switch (status.response_code) {
473 case AP_RESPONSE_NORMAL: 475 case AP_RESPONSE_NORMAL:
@@ -617,6 +619,8 @@ static enum ap_wait ap_sm_read(struct ap_device *ap_dev)
617{ 619{
618 struct ap_queue_status status; 620 struct ap_queue_status status;
619 621
622 if (!ap_dev->reply)
623 return AP_WAIT_NONE;
620 status = ap_sm_recv(ap_dev); 624 status = ap_sm_recv(ap_dev);
621 switch (status.response_code) { 625 switch (status.response_code) {
622 case AP_RESPONSE_NORMAL: 626 case AP_RESPONSE_NORMAL:
@@ -638,6 +642,31 @@ static enum ap_wait ap_sm_read(struct ap_device *ap_dev)
638} 642}
639 643
640/** 644/**
645 * ap_sm_suspend_read(): Receive pending reply messages from an AP device
646 * without changing the device state in between. In suspend mode we don't
647 * allow sending new requests, therefore just fetch pending replies.
648 * @ap_dev: pointer to the AP device
649 *
650 * Returns AP_WAIT_NONE or AP_WAIT_AGAIN
651 */
652static enum ap_wait ap_sm_suspend_read(struct ap_device *ap_dev)
653{
654 struct ap_queue_status status;
655
656 if (!ap_dev->reply)
657 return AP_WAIT_NONE;
658 status = ap_sm_recv(ap_dev);
659 switch (status.response_code) {
660 case AP_RESPONSE_NORMAL:
661 if (ap_dev->queue_count > 0)
662 return AP_WAIT_AGAIN;
663 /* fall through */
664 default:
665 return AP_WAIT_NONE;
666 }
667}
668
669/**
641 * ap_sm_write(): Send messages from the request queue to an AP device. 670 * ap_sm_write(): Send messages from the request queue to an AP device.
642 * @ap_dev: pointer to the AP device 671 * @ap_dev: pointer to the AP device
643 * 672 *
@@ -738,7 +767,7 @@ static enum ap_wait ap_sm_reset_wait(struct ap_device *ap_dev)
738 struct ap_queue_status status; 767 struct ap_queue_status status;
739 unsigned long info; 768 unsigned long info;
740 769
741 if (ap_dev->queue_count > 0) 770 if (ap_dev->queue_count > 0 && ap_dev->reply)
742 /* Try to read a completed message and get the status */ 771 /* Try to read a completed message and get the status */
743 status = ap_sm_recv(ap_dev); 772 status = ap_sm_recv(ap_dev);
744 else 773 else
@@ -778,7 +807,7 @@ static enum ap_wait ap_sm_setirq_wait(struct ap_device *ap_dev)
778 struct ap_queue_status status; 807 struct ap_queue_status status;
779 unsigned long info; 808 unsigned long info;
780 809
781 if (ap_dev->queue_count > 0) 810 if (ap_dev->queue_count > 0 && ap_dev->reply)
782 /* Try to read a completed message and get the status */ 811 /* Try to read a completed message and get the status */
783 status = ap_sm_recv(ap_dev); 812 status = ap_sm_recv(ap_dev);
784 else 813 else
@@ -834,7 +863,7 @@ static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = {
834 [AP_EVENT_TIMEOUT] = ap_sm_reset, 863 [AP_EVENT_TIMEOUT] = ap_sm_reset,
835 }, 864 },
836 [AP_STATE_SUSPEND_WAIT] = { 865 [AP_STATE_SUSPEND_WAIT] = {
837 [AP_EVENT_POLL] = ap_sm_read, 866 [AP_EVENT_POLL] = ap_sm_suspend_read,
838 [AP_EVENT_TIMEOUT] = ap_sm_nop, 867 [AP_EVENT_TIMEOUT] = ap_sm_nop,
839 }, 868 },
840 [AP_STATE_BORKED] = { 869 [AP_STATE_BORKED] = {
@@ -1335,6 +1364,17 @@ static struct bus_type ap_bus_type = {
1335 .resume = ap_dev_resume, 1364 .resume = ap_dev_resume,
1336}; 1365};
1337 1366
1367void ap_device_init_reply(struct ap_device *ap_dev,
1368 struct ap_message *reply)
1369{
1370 ap_dev->reply = reply;
1371
1372 spin_lock_bh(&ap_dev->lock);
1373 ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL));
1374 spin_unlock_bh(&ap_dev->lock);
1375}
1376EXPORT_SYMBOL(ap_device_init_reply);
1377
1338static int ap_device_probe(struct device *dev) 1378static int ap_device_probe(struct device *dev)
1339{ 1379{
1340 struct ap_device *ap_dev = to_ap_dev(dev); 1380 struct ap_device *ap_dev = to_ap_dev(dev);
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 6adcbdf225d1..d7fdf5c024d7 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -262,6 +262,7 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
262void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); 262void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
263void ap_flush_queue(struct ap_device *ap_dev); 263void ap_flush_queue(struct ap_device *ap_dev);
264void ap_bus_force_rescan(void); 264void ap_bus_force_rescan(void);
265void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg);
265 266
266int ap_module_init(void); 267int ap_module_init(void);
267void ap_module_exit(void); 268void ap_module_exit(void);
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 1e849d6e1dfe..15104aaa075a 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -126,7 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
126 MSGTYPE50_VARIANT_DEFAULT); 126 MSGTYPE50_VARIANT_DEFAULT);
127 zdev->ap_dev = ap_dev; 127 zdev->ap_dev = ap_dev;
128 zdev->online = 1; 128 zdev->online = 1;
129 ap_dev->reply = &zdev->reply; 129 ap_device_init_reply(ap_dev, &zdev->reply);
130 ap_dev->private = zdev; 130 ap_dev->private = zdev;
131 rc = zcrypt_device_register(zdev); 131 rc = zcrypt_device_register(zdev);
132 if (rc) { 132 if (rc) {
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index bb3908818505..ccb2e78ebf0e 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -147,7 +147,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
147 return -ENODEV; 147 return -ENODEV;
148 zdev->ap_dev = ap_dev; 148 zdev->ap_dev = ap_dev;
149 zdev->online = 1; 149 zdev->online = 1;
150 ap_dev->reply = &zdev->reply; 150 ap_device_init_reply(ap_dev, &zdev->reply);
151 ap_dev->private = zdev; 151 ap_dev->private = zdev;
152 rc = zcrypt_device_register(zdev); 152 rc = zcrypt_device_register(zdev);
153 if (rc) { 153 if (rc) {
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index f41852768953..df8f0c4dacb7 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -327,7 +327,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
327 else 327 else
328 zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, 328 zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
329 MSGTYPE06_VARIANT_NORNG); 329 MSGTYPE06_VARIANT_NORNG);
330 ap_dev->reply = &zdev->reply; 330 ap_device_init_reply(ap_dev, &zdev->reply);
331 ap_dev->private = zdev; 331 ap_dev->private = zdev;
332 rc = zcrypt_device_register(zdev); 332 rc = zcrypt_device_register(zdev);
333 if (rc) 333 if (rc)