From 118bd31bea2cdb7f1dbf22dd9a58e818b5313156 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 26 Jul 2016 16:53:09 +0200 Subject: s390/mm: add no-dat TLB flush optimization Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_early.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index efd84d1d178b..bc1fc00910b0 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -39,7 +39,7 @@ struct read_info_sccb { u8 fac84; /* 84 */ u8 fac85; /* 85 */ u8 _pad_86[91 - 86]; /* 86-90 */ - u8 flags; /* 91 */ + u8 fac91; /* 91 */ u8 _pad_92[98 - 92]; /* 92-97 */ u8 fac98; /* 98 */ u8 hamaxpow; /* 99 */ @@ -103,6 +103,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp.has_kss = !!(sccb->fac98 & 0x01); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; + if (sccb->fac91 & 0x40) + S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST; sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp.rzm <<= 20; @@ -139,7 +141,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) /* Save IPL information */ sclp_ipl_info.is_valid = 1; - if (sccb->flags & 0x2) + if (sccb->fac91 & 0x2) sclp_ipl_info.has_dump = 1; memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); -- cgit v1.2.3 From 45be0a02f8110a13502fac6167a893c7c0eff432 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 6 Feb 2017 15:56:14 +0100 Subject: s390/sclp: single increment assignment control Set a new option bit of the attach command to speed up memory hotplug. Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_cmd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index b9c5522b8a68..dff8b94871f0 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -252,6 +252,7 @@ static int sclp_attach_storage(u8 id) if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; + sccb->header.function_code = 0x40; rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, SCLP_QUEUE_INTERVAL); if (rc) -- cgit v1.2.3 From 9920decd64cdfa078efe968bf85de6bf50c73bb7 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:10 +0530 Subject: s390/zcrypt_queue: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 1361 96 0 1457 5b1 s390/crypto/zcrypt_queue.o File size After adding 'const': text data bss dec hex filename 1425 32 0 1457 5b1 s390/crypto/zcrypt_queue.o Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index a303f3b2c328..4742be0eec24 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -89,7 +89,7 @@ static struct attribute *zcrypt_queue_attrs[] = { NULL, }; -static struct attribute_group zcrypt_queue_attr_group = { +static const struct attribute_group zcrypt_queue_attr_group = { .attrs = zcrypt_queue_attrs, }; -- cgit v1.2.3 From 9731c0a9bc42f51187bf78007c79b667c9ccb427 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:11 +0530 Subject: s390/zcrypt_card: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 1019 160 0 1179 49b drivers/s390/crypto/zcrypt_card.o File size After adding 'const': text data bss dec hex filename 1083 96 0 1179 49b drivers/s390/crypto/zcrypt_card.o Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 53436ea52230..f85dacf1c284 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -98,7 +98,7 @@ static struct attribute *zcrypt_card_attrs[] = { NULL, }; -static struct attribute_group zcrypt_card_attr_group = { +static const struct attribute_group zcrypt_card_attr_group = { .attrs = zcrypt_card_attrs, }; -- cgit v1.2.3 From 131716776b778b4a2053759547eddc7674be1e29 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:12 +0530 Subject: s390/dasd: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 779dce069cc5..7b539d92eeaf 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1634,7 +1634,7 @@ static struct attribute * dasd_attrs[] = { NULL, }; -static struct attribute_group dasd_attr_group = { +static const struct attribute_group dasd_attr_group = { .attrs = dasd_attrs, }; -- cgit v1.2.3 From f460d113c6805e953cbcafb5e10b6c0edf5a55aa Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:13 +0530 Subject: s390/cio: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7be01a58b44f..489b583f263d 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -612,7 +612,7 @@ static struct attribute *io_subchannel_attrs[] = { NULL, }; -static struct attribute_group io_subchannel_attr_group = { +static const struct attribute_group io_subchannel_attr_group = { .attrs = io_subchannel_attrs, }; @@ -626,7 +626,7 @@ static struct attribute * ccwdev_attrs[] = { NULL, }; -static struct attribute_group ccwdev_attr_group = { +static const struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; -- cgit v1.2.3 From cfe9a0428dda7122c3da1c65d252c37f37b1486a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:14 +0530 Subject: s390/qeth: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 6763 1216 0 7979 1f2b drivers/s390/net/qeth_l3_sys.o File size After adding 'const': text data bss dec hex filename 7019 960 0 7971 1f2b drivers/s390/net/qeth_l3_sys.o Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/net/qeth_l3_sys.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index f2f94f59e0fa..1a80ce41425e 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -350,7 +350,7 @@ static struct attribute *qeth_l3_device_attrs[] = { NULL, }; -static struct attribute_group qeth_l3_device_attr_group = { +static const struct attribute_group qeth_l3_device_attr_group = { .attrs = qeth_l3_device_attrs, }; @@ -680,7 +680,7 @@ static struct attribute *qeth_ipato_device_attrs[] = { NULL, }; -static struct attribute_group qeth_device_ipato_group = { +static const struct attribute_group qeth_device_ipato_group = { .name = "ipa_takeover", .attrs = qeth_ipato_device_attrs, }; @@ -843,7 +843,7 @@ static struct attribute *qeth_vipa_device_attrs[] = { NULL, }; -static struct attribute_group qeth_device_vipa_group = { +static const struct attribute_group qeth_device_vipa_group = { .name = "vipa", .attrs = qeth_vipa_device_attrs, }; @@ -1006,7 +1006,7 @@ static struct attribute *qeth_rxip_device_attrs[] = { NULL, }; -static struct attribute_group qeth_device_rxip_group = { +static const struct attribute_group qeth_device_rxip_group = { .name = "rxip", .attrs = qeth_rxip_device_attrs, }; -- cgit v1.2.3 From cb0259ca61b0dd4617fb62c821492ae76a6390b4 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:15 +0530 Subject: s390/raw3270: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 8069 816 16 8901 22c5 drivers/s390/char/raw3270.o File size After adding 'const': text data bss dec hex filename 8133 752 16 8901 22c5 drivers/s390/char/raw3270.o Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/char/raw3270.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 710f2292911d..5d4f053d7c38 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1082,7 +1082,7 @@ static struct attribute * raw3270_attrs[] = { NULL, }; -static struct attribute_group raw3270_attr_group = { +static const struct attribute_group raw3270_attr_group = { .attrs = raw3270_attrs, }; -- cgit v1.2.3 From fc2b0f52aea5daf19adb576112a7db6be7a0379c Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:16 +0530 Subject: s390/tape: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. File size before: text data bss dec hex filename 11511 656 16 12183 2f97 drivers/s390/char/tape_core.o File size After adding 'const': text data bss dec hex filename 11575 592 16 12183 2f97 drivers/s390/char/tape_core.o Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 3c379da2eef8..9dd4534823b3 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -175,7 +175,7 @@ static struct attribute *tape_attrs[] = { NULL }; -static struct attribute_group tape_attr_group = { +static const struct attribute_group tape_attr_group = { .attrs = tape_attrs, }; -- cgit v1.2.3 From 8351378f5873164ecc966c58fac43bab53216c94 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 19 Jul 2017 12:39:17 +0530 Subject: s390/sclp_ocf: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_ocf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c index f59b71776bbd..f9cbb1ab047b 100644 --- a/drivers/s390/char/sclp_ocf.c +++ b/drivers/s390/char/sclp_ocf.c @@ -126,7 +126,7 @@ static struct attribute *ocf_attrs[] = { NULL, }; -static struct attribute_group ocf_attr_group = { +static const struct attribute_group ocf_attr_group = { .attrs = ocf_attrs, }; -- cgit v1.2.3 From c7e85ae5eaab5c12fb4a2f65ffef1c3350072110 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 2 Aug 2017 21:37:22 +0530 Subject: s390/sclp: add const to bin_attribute structure Declare bin_attribute structure as const as it is only passed as an argument to the function sysfs_create_bin_file. This argument is of type const, so declare the structure as const. Cross compiled for s390 architecture. Signed-off-by: Bhumika Goyal Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 1406fb688a26..7003d52c2191 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -135,7 +135,7 @@ static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj, return rc ?: count; } -static struct bin_attribute ofb_bin_attr = { +static const struct bin_attribute ofb_bin_attr = { .attr = { .name = "event_data", .mode = S_IWUSR, -- cgit v1.2.3 From ac34bbc3604bd7822ffb06b3e22151a6d99bc4c9 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 2 Aug 2017 21:37:23 +0530 Subject: s390/cio: add const to bin_attribute structures Add const to bin_attribute structures as they are only passed to the functions device_{remove/create}_bin_file. The corresponding arguments are of type const, so declare the structures to be const. Cross compiled for s390 architecture. Signed-off-by: Bhumika Goyal Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 432fc40990bd..f4166f80c4d4 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -143,7 +143,7 @@ static ssize_t chp_measurement_chars_read(struct file *filp, sizeof(chp->cmg_chars)); } -static struct bin_attribute chp_measurement_chars_attr = { +static const struct bin_attribute chp_measurement_chars_attr = { .attr = { .name = "measurement_chars", .mode = S_IRUSR, @@ -197,7 +197,7 @@ static ssize_t chp_measurement_read(struct file *filp, struct kobject *kobj, return count; } -static struct bin_attribute chp_measurement_attr = { +static const struct bin_attribute chp_measurement_attr = { .attr = { .name = "measurement", .mode = S_IRUSR, -- cgit v1.2.3 From 267239cc10f18251892a0783104df3dc22b620d5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:15 +0200 Subject: s390/vmcp: fix uaccess check and avoid undefined behavior The vmcp device driver should return -EFAULT if get_user() fails, due to an invalid user space address. In addition the buffer size value from user space is passed unchecked to get_order(). The return value of get_order(0) undefined. Therefore explicitly test for zero before calling get_order() and also return -EFAULT if get_user() fails. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 98749fa817da..66d5e9f83e0d 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -150,7 +150,9 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) get_order(session->bufsize)); session->response=NULL; temp = get_user(session->bufsize, argp); - if (get_order(session->bufsize) > 8) { + if (temp) + session->bufsize = PAGE_SIZE; + if (!session->bufsize || get_order(session->bufsize) > 8) { session->bufsize = PAGE_SIZE; temp = -EINVAL; } -- cgit v1.2.3 From cd4386a931b6310b05559d2e28efda04d30ab593 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:15 +0200 Subject: s390/cpcmd,vmcp: avoid GFP_DMA allocations According to the CP Programming Services manual Diagnose Code 8 "Virtual Console Function" can be used in all addressing modes. Also the input and output buffers do not have a limitation which specifies they need to be below the 2GB line. This is true at least since z/VM 5.4. Therefore remove the sam31/64 instructions and allow for simple GFP_KERNEL allocations. This makes it easier to allocate a 1MB page if the user requested such a large return buffer. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 66d5e9f83e0d..b5e3a49745f9 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, } if (!session->response) session->response = (char *)__get_free_pages(GFP_KERNEL - | __GFP_RETRY_MAYFAIL | GFP_DMA, + | __GFP_RETRY_MAYFAIL, get_order(session->bufsize)); if (!session->response) { mutex_unlock(&session->mutex); -- cgit v1.2.3 From 3f4298427ad521fdc74fb991b17d84959513218a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:15 +0200 Subject: s390/vmcp: make use of contiguous memory allocator If memory is fragmented it is unlikely that large order memory allocations succeed. This has been an issue with the vmcp device driver since a long time, since it requires large physical contiguous memory ares for large responses. To hopefully resolve this issue make use of the contiguous memory allocator (cma). This patch adds a vmcp specific vmcp cma area with a default size of 4MB. The size can be changed either via the VMCP_CMA_SIZE config option at compile time or with the "vmcp_cma" kernel parameter (e.g. "vmcp_cma=16m"). For any vmcp response buffers larger than 16k memory from the cma area will be allocated. If such an allocation fails, there is a fallback to the buddy allocator. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/Kconfig | 11 +++++++ drivers/s390/char/vmcp.c | 74 ++++++++++++++++++++++++++++++++++++++++++----- drivers/s390/char/vmcp.h | 3 +- 3 files changed, 79 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index b3f1c458905f..97c4c9fdd53d 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -169,10 +169,21 @@ config VMCP def_bool y prompt "Support for the z/VM CP interface" depends on S390 + select CMA help Select this option if you want to be able to interact with the control program on z/VM +config VMCP_CMA_SIZE + int "Memory in MiB reserved for z/VM CP interface" + default "4" + depends on VMCP + help + Specify the default amount of memory in MiB reserved for the z/VM CP + interface. If needed this memory is used for large contiguous memory + allocations. The default can be changed with the kernel command line + parameter "vmcp_cma". + config MONREADER def_tristate m prompt "API for reading z/VM monitor service records" diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index b5e3a49745f9..c202b407698f 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -17,15 +17,77 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include -#include #include "vmcp.h" static debug_info_t *vmcp_debug; +static unsigned long vmcp_cma_size __initdata = CONFIG_VMCP_CMA_SIZE * 1024 * 1024; +static struct cma *vmcp_cma; + +static int __init early_parse_vmcp_cma(char *p) +{ + vmcp_cma_size = ALIGN(memparse(p, NULL), PAGE_SIZE); + return 0; +} +early_param("vmcp_cma", early_parse_vmcp_cma); + +void __init vmcp_cma_reserve(void) +{ + if (!MACHINE_IS_VM) + return; + cma_declare_contiguous(0, vmcp_cma_size, 0, 0, 0, false, "vmcp", &vmcp_cma); +} + +static void vmcp_response_alloc(struct vmcp_session *session) +{ + struct page *page = NULL; + int nr_pages, order; + + order = get_order(session->bufsize); + nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT; + /* + * For anything below order 3 allocations rely on the buddy + * allocator. If such low-order allocations can't be handled + * anymore the system won't work anyway. + */ + if (order > 2) + page = cma_alloc(vmcp_cma, nr_pages, 0, GFP_KERNEL); + if (page) { + session->response = (char *)page_to_phys(page); + session->cma_alloc = 1; + return; + } + session->response = (char *)__get_free_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL, order); +} + +static void vmcp_response_free(struct vmcp_session *session) +{ + int nr_pages, order; + struct page *page; + + if (!session->response) + return; + order = get_order(session->bufsize); + nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT; + if (session->cma_alloc) { + page = phys_to_page((unsigned long)session->response); + cma_release(vmcp_cma, page, nr_pages); + session->cma_alloc = 0; + goto out; + } + free_pages((unsigned long)session->response, order); +out: + session->response = NULL; +} + static int vmcp_open(struct inode *inode, struct file *file) { struct vmcp_session *session; @@ -51,7 +113,7 @@ static int vmcp_release(struct inode *inode, struct file *file) session = file->private_data; file->private_data = NULL; - free_pages((unsigned long)session->response, get_order(session->bufsize)); + vmcp_response_free(session); kfree(session); return 0; } @@ -97,9 +159,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, return -ERESTARTSYS; } if (!session->response) - session->response = (char *)__get_free_pages(GFP_KERNEL - | __GFP_RETRY_MAYFAIL, - get_order(session->bufsize)); + vmcp_response_alloc(session); if (!session->response) { mutex_unlock(&session->mutex); kfree(cmd); @@ -146,9 +206,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&session->mutex); return put_user(temp, argp); case VMCP_SETBUF: - free_pages((unsigned long)session->response, - get_order(session->bufsize)); - session->response=NULL; + vmcp_response_free(session); temp = get_user(session->bufsize, argp); if (temp) session->bufsize = PAGE_SIZE; diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h index 1e29b0418382..4e725edf449f 100644 --- a/drivers/s390/char/vmcp.h +++ b/drivers/s390/char/vmcp.h @@ -20,8 +20,9 @@ #define VMCP_GETSIZE _IOR(0x10, 3, int) struct vmcp_session { - unsigned int bufsize; char *response; + unsigned int bufsize; + unsigned int cma_alloc : 1; int resp_size; int resp_code; /* As we use copy_from/to_user, which might * -- cgit v1.2.3 From ef267938f07197fc011e3aada67ac70a3c65c2ff Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:16 +0200 Subject: s390/vmcp: split vmcp header file and move to uapi Split the vmcp header file and move the device driver internal structure to the C file, and move the ioctl definitions to the uapi directory. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 11 ++++++++++- drivers/s390/char/vmcp.h | 31 ------------------------------- 2 files changed, 10 insertions(+), 32 deletions(-) delete mode 100644 drivers/s390/char/vmcp.h (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index c202b407698f..18b30119a70e 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -25,7 +25,16 @@ #include #include #include -#include "vmcp.h" +#include + +struct vmcp_session { + char *response; + unsigned int bufsize; + unsigned int cma_alloc : 1; + int resp_size; + int resp_code; + struct mutex mutex; +}; static debug_info_t *vmcp_debug; diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h deleted file mode 100644 index 4e725edf449f..000000000000 --- a/drivers/s390/char/vmcp.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright IBM Corp. 2004, 2005 - * Interface implementation for communication with the z/VM control program - * Version 1.0 - * Author(s): Christian Borntraeger - * - * - * z/VMs CP offers the possibility to issue commands via the diagnose code 8 - * this driver implements a character device that issues these commands and - * returns the answer of CP. - * - * The idea of this driver is based on cpint from Neale Ferguson - */ - -#include -#include - -#define VMCP_GETCODE _IOR(0x10, 1, int) -#define VMCP_SETBUF _IOW(0x10, 2, int) -#define VMCP_GETSIZE _IOR(0x10, 3, int) - -struct vmcp_session { - char *response; - unsigned int bufsize; - unsigned int cma_alloc : 1; - int resp_size; - int resp_code; - /* As we use copy_from/to_user, which might * - * sleep and cannot use a spinlock */ - struct mutex mutex; -}; -- cgit v1.2.3 From 4ae48c046814d8b0386883aeb9060b08f46a2ec1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:16 +0200 Subject: s390/vmcp: return -ENOTTY for unknown ioctl commands Return -ENOTTY for unknown ioctl commands instead of -ENOIOCTLCMD. This isn't that much of difference, since common code will translate -ENOIOCTLCMD to -ENOTTY anyway, but this way it seems to be more obvious what is happening (at least to me). Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 18b30119a70e..30fd474c86b3 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -231,7 +231,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(temp, argp); default: mutex_unlock(&session->mutex); - return -ENOIOCTLCMD; + return -ENOTTY; } } -- cgit v1.2.3 From 307957b643493c1bc038d4e4b717871184f13ddf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 7 Aug 2017 15:16:16 +0200 Subject: s390/vmcp: simplify vmcp_ioctl() vmcp_ioctl() has many different return statements and duplicates a lot of mutex_unlock() calls. Simplify this so that only one return statement and one mutex_unlock() call is left. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 30fd474c86b3..0aa50afa5063 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -199,8 +199,8 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct vmcp_session *session; + int ret = -ENOTTY; int __user *argp; - int temp; session = file->private_data; if (is_compat_task()) @@ -211,28 +211,26 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -ERESTARTSYS; switch (cmd) { case VMCP_GETCODE: - temp = session->resp_code; - mutex_unlock(&session->mutex); - return put_user(temp, argp); + ret = put_user(session->resp_code, argp); + break; case VMCP_SETBUF: vmcp_response_free(session); - temp = get_user(session->bufsize, argp); - if (temp) + ret = get_user(session->bufsize, argp); + if (ret) session->bufsize = PAGE_SIZE; if (!session->bufsize || get_order(session->bufsize) > 8) { session->bufsize = PAGE_SIZE; - temp = -EINVAL; + ret = -EINVAL; } - mutex_unlock(&session->mutex); - return temp; + break; case VMCP_GETSIZE: - temp = session->resp_size; - mutex_unlock(&session->mutex); - return put_user(temp, argp); + ret = put_user(session->resp_size, argp); + break; default: - mutex_unlock(&session->mutex); - return -ENOTTY; + break; } + mutex_unlock(&session->mutex); + return ret; } static const struct file_operations vmcp_fops = { -- cgit v1.2.3 From a3c1a2194a7c776c08ad704cd8a3b3ea694c60e6 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 15 Jun 2017 17:13:15 +0200 Subject: s390/scm: use common completion path Since commit caf7df122721 ("block: remove the errors field from struct request") rq->errors can't be (mis)used by block device drivers to store the error condition for usage during async completion. Because of that I simply used async completion only for the non-error paths. This patch places the error within the private data of struct request and uses async completion for all paths again. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/block/scm_blk.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 0071febac9e6..2e7fd966c515 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -249,13 +249,13 @@ static void scm_request_requeue(struct scm_request *scmrq) static void scm_request_finish(struct scm_request *scmrq) { struct scm_blk_dev *bdev = scmrq->bdev; + int *error; int i; for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) { - if (scmrq->error) - blk_mq_end_request(scmrq->request[i], scmrq->error); - else - blk_mq_complete_request(scmrq->request[i]); + error = blk_mq_rq_to_pdu(scmrq->request[i]); + *error = scmrq->error; + blk_mq_complete_request(scmrq->request[i]); } atomic_dec(&bdev->queued_reqs); @@ -415,7 +415,9 @@ void scm_blk_irq(struct scm_device *scmdev, void *data, blk_status_t error) static void scm_blk_request_done(struct request *req) { - blk_mq_end_request(req, 0); + int *error = blk_mq_rq_to_pdu(req); + + blk_mq_end_request(req, *error); } static const struct block_device_operations scm_blk_devops = { @@ -448,6 +450,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) atomic_set(&bdev->queued_reqs, 0); bdev->tag_set.ops = &scm_mq_ops; + bdev->tag_set.cmd_size = sizeof(int); bdev->tag_set.nr_hw_queues = nr_requests; bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests; bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; -- cgit v1.2.3 From d2907225cf9621140664209037bbce5107e02c91 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 14 Jul 2017 10:33:18 +0200 Subject: s390/dasd: add average request times to dasd statistics Add average times to the DASD statistics interface. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 34 ++++++++++++++++++++++++++++++---- drivers/s390/block/dasd_int.h | 4 ++++ 2 files changed, 34 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 670ac0a4ef49..a97b2b819f51 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -801,11 +801,12 @@ static void dasd_profile_end(struct dasd_block *block, struct dasd_ccw_req *cqr, struct request *req) { - long strtime, irqtime, endtime, tottime; /* in microseconds */ - long tottimeps, sectors; + unsigned long strtime, irqtime, endtime, tottime; + unsigned long tottimeps, sectors; struct dasd_device *device; int sectors_ind, tottime_ind, tottimeps_ind, strtime_ind; int irqtime_ind, irqtimeps_ind, endtime_ind; + struct dasd_profile_info *data; device = cqr->startdev; if (!(dasd_global_profile_level || @@ -835,6 +836,11 @@ static void dasd_profile_end(struct dasd_block *block, spin_lock(&dasd_global_profile.lock); if (dasd_global_profile.data) { + data = dasd_global_profile.data; + data->dasd_sum_times += tottime; + data->dasd_sum_time_str += strtime; + data->dasd_sum_time_irq += irqtime; + data->dasd_sum_time_end += endtime; dasd_profile_end_add_data(dasd_global_profile.data, cqr->startdev != block->base, cqr->cpmode == 1, @@ -847,7 +853,12 @@ static void dasd_profile_end(struct dasd_block *block, spin_unlock(&dasd_global_profile.lock); spin_lock(&block->profile.lock); - if (block->profile.data) + if (block->profile.data) { + data = block->profile.data; + data->dasd_sum_times += tottime; + data->dasd_sum_time_str += strtime; + data->dasd_sum_time_irq += irqtime; + data->dasd_sum_time_end += endtime; dasd_profile_end_add_data(block->profile.data, cqr->startdev != block->base, cqr->cpmode == 1, @@ -856,10 +867,16 @@ static void dasd_profile_end(struct dasd_block *block, tottimeps_ind, strtime_ind, irqtime_ind, irqtimeps_ind, endtime_ind); + } spin_unlock(&block->profile.lock); spin_lock(&device->profile.lock); - if (device->profile.data) + if (device->profile.data) { + data = device->profile.data; + data->dasd_sum_times += tottime; + data->dasd_sum_time_str += strtime; + data->dasd_sum_time_irq += irqtime; + data->dasd_sum_time_end += endtime; dasd_profile_end_add_data(device->profile.data, cqr->startdev != block->base, cqr->cpmode == 1, @@ -868,6 +885,7 @@ static void dasd_profile_end(struct dasd_block *block, tottimeps_ind, strtime_ind, irqtime_ind, irqtimeps_ind, endtime_ind); + } spin_unlock(&device->profile.lock); } @@ -989,6 +1007,14 @@ static void dasd_stats_seq_print(struct seq_file *m, seq_printf(m, "total_sectors %u\n", data->dasd_io_sects); seq_printf(m, "total_pav %u\n", data->dasd_io_alias); seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm); + seq_printf(m, "avg_total %lu\n", data->dasd_io_reqs ? + data->dasd_sum_times / data->dasd_io_reqs : 0UL); + seq_printf(m, "avg_build_to_ssch %lu\n", data->dasd_io_reqs ? + data->dasd_sum_time_str / data->dasd_io_reqs : 0UL); + seq_printf(m, "avg_ssch_to_irq %lu\n", data->dasd_io_reqs ? + data->dasd_sum_time_irq / data->dasd_io_reqs : 0UL); + seq_printf(m, "avg_irq_to_end %lu\n", data->dasd_io_reqs ? + data->dasd_sum_time_end / data->dasd_io_reqs : 0UL); seq_puts(m, "histogram_sectors "); dasd_stats_array(m, data->dasd_io_secs); seq_puts(m, "histogram_io_times "); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index dca7cb1e6f65..43f383b2f87d 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -454,6 +454,10 @@ struct dasd_profile_info { unsigned int dasd_read_time2[32]; /* hist. of time from start to irq */ unsigned int dasd_read_time3[32]; /* hist. of time from irq to end */ unsigned int dasd_read_nr_req[32]; /* hist. of # of requests in chanq */ + unsigned long dasd_sum_times; /* sum of request times */ + unsigned long dasd_sum_time_str; /* sum of time from build to start */ + unsigned long dasd_sum_time_irq; /* sum of time from start to irq */ + unsigned long dasd_sum_time_end; /* sum of time from irq to end */ }; struct dasd_profile { -- cgit v1.2.3 From 7bf76f0169538279b78536393639859eeb7d93f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B6ppner?= Date: Tue, 15 Aug 2017 16:40:18 +0200 Subject: s390/dasd: Change unsigned long long to unsigned long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unsigned long long and unsigned long were different in size for 31-bit. For 64-bit the size for both datatypes is 8 Bytes and since the support for 31-bit is long gone we can clean up a little and change everything to unsigned long. Change get_phys_clock() along the way to accept unsigned long as well so that the DASD code can be consistent. Acked-by: Heiko Carstens Signed-off-by: Jan Höppner Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 2 +- drivers/s390/block/dasd_3990_erp.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.c | 8 ++------ drivers/s390/block/dasd_eckd.h | 2 +- drivers/s390/block/dasd_erp.c | 2 +- drivers/s390/block/dasd_int.h | 12 ++++++------ drivers/s390/block/dasd_proc.c | 2 +- 8 files changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a97b2b819f51..83f80710d555 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1665,7 +1665,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, { struct dasd_ccw_req *cqr, *next; struct dasd_device *device; - unsigned long long now; + unsigned long now; int nrf_suppressed = 0; int fp_suppressed = 0; u8 *sense = NULL; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 107cd3361e29..e448a0fc0c09 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2231,7 +2231,7 @@ static void dasd_3990_erp_account_error(struct dasd_ccw_req *erp) struct dasd_device *device = erp->startdev; __u8 lpum = erp->refers->irb.esw.esw1.lpum; int pos = pathmask_to_pos(lpum); - unsigned long long clk; + unsigned long clk; if (!device->path_thrhld) return; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 5667146c6a0a..98fb28e49d2c 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -235,7 +235,7 @@ static void dasd_ext_handler(struct ext_code ext_code, { struct dasd_ccw_req *cqr, *next; struct dasd_device *device; - unsigned long long expires; + unsigned long expires; unsigned long flags; addr_t ip; int rc; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c3e5ad641b0b..8eafcd5fa004 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3254,11 +3254,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( /* 1x prefix + one read/write ccw per track */ cplength = 1 + trkcount; - /* on 31-bit we need space for two 32 bit addresses per page - * on 64-bit one 64 bit address - */ - datasize = sizeof(struct PFX_eckd_data) + - cidaw * sizeof(unsigned long long); + datasize = sizeof(struct PFX_eckd_data) + cidaw * sizeof(unsigned long); /* Allocate the ccw request. */ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, @@ -3856,7 +3852,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, } size = ALIGN(size, 8); - datasize = size + cidaw * sizeof(unsigned long long); + datasize = size + cidaw * sizeof(unsigned long); /* Allocate the ccw request. */ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index fb1f537d986a..34e153a6b19c 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -165,7 +165,7 @@ struct DE_eckd_data { __u8 ga_extended; /* Global Attributes Extended */ struct ch_t beg_ext; struct ch_t end_ext; - unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */ + unsigned long ep_sys_time; /* Ext Parameter - System Time Stamp */ __u8 ep_format; /* Extended Parameter format byte */ __u8 ep_prio; /* Extended Parameter priority I/O byte */ __u8 ep_reserved1; /* Extended Parameter Reserved */ diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 9e3419124264..6389feb2fb7a 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -124,7 +124,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr) { int success; - unsigned long long startclk, stopclk; + unsigned long startclk, stopclk; struct dasd_device *startdev; BUG_ON(cqr->refers == NULL || cqr->function == NULL); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 43f383b2f87d..66248795b973 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -196,10 +196,10 @@ struct dasd_ccw_req { void *function; /* originating ERP action */ /* these are for statistics only */ - unsigned long long buildclk; /* TOD-clock of request generation */ - unsigned long long startclk; /* TOD-clock of request start */ - unsigned long long stopclk; /* TOD-clock of request interrupt */ - unsigned long long endclk; /* TOD-clock of request termination */ + unsigned long buildclk; /* TOD-clock of request generation */ + unsigned long startclk; /* TOD-clock of request start */ + unsigned long stopclk; /* TOD-clock of request interrupt */ + unsigned long endclk; /* TOD-clock of request termination */ /* Callback that is called after reaching final status. */ void (*callback)(struct dasd_ccw_req *, void *data); @@ -423,7 +423,7 @@ struct dasd_path { u8 chpid; struct dasd_conf_data *conf_data; atomic_t error_count; - unsigned long long errorclk; + unsigned long errorclk; }; @@ -539,7 +539,7 @@ struct dasd_block { struct block_device *bdev; atomic_t open_count; - unsigned long long blocks; /* size of volume in blocks */ + unsigned long blocks; /* size of volume in blocks */ unsigned int bp_block; /* bytes per block */ unsigned int s2b_shift; /* log2 (bp_block/512) */ diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 70dc2c4cd3f7..7104d6765773 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -90,7 +90,7 @@ dasd_devices_show(struct seq_file *m, void *v) seq_printf(m, "n/f "); else seq_printf(m, - "at blocksize: %d, %lld blocks, %lld MB", + "at blocksize: %u, %lu blocks, %lu MB", block->bp_block, block->blocks, ((block->bp_block >> 9) * block->blocks) >> 11); -- cgit v1.2.3 From eb304e800d491d5168df61a999beebe8042e7e58 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 18 Aug 2017 08:35:33 +0200 Subject: s390/vmcp: simplify vmcp_response_free() Get rid of the goto and "out" label within vmcp_response_free() which I added. This just makes the code harder to read than necessary. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmcp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 0aa50afa5063..7898bbcc28fc 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -90,10 +90,9 @@ static void vmcp_response_free(struct vmcp_session *session) page = phys_to_page((unsigned long)session->response); cma_release(vmcp_cma, page, nr_pages); session->cma_alloc = 0; - goto out; + } else { + free_pages((unsigned long)session->response, order); } - free_pages((unsigned long)session->response, order); -out: session->response = NULL; } -- cgit v1.2.3 From 8b94dd9e0d4439f83fcc55f1f8020c86e79b623d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 25 Aug 2017 18:40:29 +0530 Subject: s390/zcrypt: make CPRBX const Make this const as it is only used in a copy operation. Signed-off-by: Bhumika Goyal Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_msgtype6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 4fddb4319481..afd20cee7ea0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -140,7 +140,7 @@ struct function_and_rules_block { * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') * - VUD block */ -static struct CPRBX static_cprbx = { +static const struct CPRBX static_cprbx = { .cprb_len = 0x00DC, .cprb_ver_id = 0x02, .func_id = {0x54, 0x32}, -- cgit v1.2.3 From 28b841b3a7cb07a4bfd436a15b31bc88509dcf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B6ppner?= Date: Thu, 30 Jun 2016 13:28:57 +0200 Subject: s390/dasd: Add discard support for FBA devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The z/VM hypervisor provides virtual disks (VDISK) which are backed by main memory of the hypervisor. Those devices are seen as DASD FBA disks within the Linux guest. Whenever data is written to such a device, memory is allocated on-the-fly by z/VM accordingly. This memory, however, is not being freed if data on the device is deleted by the guest OS. In order to make memory usable after deletion again, add discard support to the FBA discipline. While at it, update comments regarding the DASD_FEATURE_* flags. Reviewed-by: Stefan Haberland Signed-off-by: Jan Höppner Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 19 +++- drivers/s390/block/dasd_devmap.c | 1 + drivers/s390/block/dasd_fba.c | 202 ++++++++++++++++++++++++++++++++++++++- drivers/s390/block/dasd_int.h | 3 + 4 files changed, 221 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 83f80710d555..9c97ad1ee121 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3178,7 +3178,9 @@ static int dasd_alloc_queue(struct dasd_block *block) */ static void dasd_setup_queue(struct dasd_block *block) { + unsigned int logical_block_size = block->bp_block; struct request_queue *q = block->request_queue; + unsigned int max_bytes, max_discard_sectors; int max; if (block->base->features & DASD_FEATURE_USERAW) { @@ -3195,7 +3197,7 @@ static void dasd_setup_queue(struct dasd_block *block) } queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); q->limits.max_dev_sectors = max; - blk_queue_logical_block_size(q, block->bp_block); + blk_queue_logical_block_size(q, logical_block_size); blk_queue_max_hw_sectors(q, max); blk_queue_max_segments(q, USHRT_MAX); /* with page sized segments we can translate each segement into @@ -3203,6 +3205,21 @@ static void dasd_setup_queue(struct dasd_block *block) */ blk_queue_max_segment_size(q, PAGE_SIZE); blk_queue_segment_boundary(q, PAGE_SIZE - 1); + + /* Only activate blocklayer discard support for devices that support it */ + if (block->base->features & DASD_FEATURE_DISCARD) { + q->limits.discard_granularity = logical_block_size; + q->limits.discard_alignment = PAGE_SIZE; + + /* Calculate max_discard_sectors and make it PAGE aligned */ + max_bytes = USHRT_MAX * logical_block_size; + max_bytes = ALIGN(max_bytes, PAGE_SIZE) - PAGE_SIZE; + max_discard_sectors = max_bytes / logical_block_size; + + blk_queue_max_discard_sectors(q, max_discard_sectors); + blk_queue_max_write_zeroes_sectors(q, max_discard_sectors); + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); + } } /* diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 7b539d92eeaf..e38042ce94e6 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1676,6 +1676,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) spin_unlock(&dasd_devmap_lock); return 0; } +EXPORT_SYMBOL(dasd_set_feature); int diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 462cab5d4302..6168ccdb389c 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -174,6 +174,9 @@ dasd_fba_check_characteristics(struct dasd_device *device) if (readonly) set_bit(DASD_FLAG_DEVICE_RO, &device->flags); + /* FBA supports discard, set the according feature bit */ + dasd_set_feature(cdev, DASD_FEATURE_DISCARD, 1); + dev_info(&device->cdev->dev, "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " "and %d B/blk%s\n", @@ -247,9 +250,192 @@ static void dasd_fba_check_for_device_change(struct dasd_device *device, dasd_generic_handle_state_change(device); }; -static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, - struct dasd_block *block, - struct request *req) + +/* + * Builds a CCW with no data payload + */ +static void ccw_write_no_data(struct ccw1 *ccw) +{ + ccw->cmd_code = DASD_FBA_CCW_WRITE; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 0; +} + +/* + * Builds a CCW that writes only zeroes. + */ +static void ccw_write_zero(struct ccw1 *ccw, int count) +{ + ccw->cmd_code = DASD_FBA_CCW_WRITE; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = count; + ccw->cda = (__u32) (addr_t) page_to_phys(ZERO_PAGE(0)); +} + +/* + * Helper function to count the amount of necessary CCWs within a given range + * with 4k alignment and command chaining in mind. + */ +static int count_ccws(sector_t first_rec, sector_t last_rec, + unsigned int blocks_per_page) +{ + sector_t wz_stop = 0, d_stop = 0; + int cur_pos = 0; + int count = 0; + + if (first_rec % blocks_per_page != 0) { + wz_stop = first_rec + blocks_per_page - + (first_rec % blocks_per_page) - 1; + if (wz_stop > last_rec) + wz_stop = last_rec; + cur_pos = wz_stop - first_rec + 1; + count++; + } + + if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) { + if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0) + d_stop = last_rec - ((last_rec - blocks_per_page + 1) % + blocks_per_page); + else + d_stop = last_rec; + + cur_pos += d_stop - (first_rec + cur_pos) + 1; + count++; + } + + if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec) + count++; + + return count; +} + +/* + * This function builds a CCW request for block layer discard requests. + * Each page in the z/VM hypervisor that represents certain records of an FBA + * device will be padded with zeros. This is a special behaviour of the WRITE + * command which is triggered when no data payload is added to the CCW. + * + * Note: Due to issues in some z/VM versions, we can't fully utilise this + * special behaviour. We have to keep a 4k (or 8 block) alignment in mind to + * work around those issues and write actual zeroes to the unaligned parts in + * the request. This workaround might be removed in the future. + */ +static struct dasd_ccw_req *dasd_fba_build_cp_discard( + struct dasd_device *memdev, + struct dasd_block *block, + struct request *req) +{ + struct LO_fba_data *LO_data; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + + sector_t wz_stop = 0, d_stop = 0; + sector_t first_rec, last_rec; + + unsigned int blksize = block->bp_block; + unsigned int blocks_per_page; + int wz_count = 0; + int d_count = 0; + int cur_pos = 0; /* Current position within the extent */ + int count = 0; + int cplength; + int datasize; + int nr_ccws; + + first_rec = blk_rq_pos(req) >> block->s2b_shift; + last_rec = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; + count = last_rec - first_rec + 1; + + blocks_per_page = BLOCKS_PER_PAGE(blksize); + nr_ccws = count_ccws(first_rec, last_rec, blocks_per_page); + + /* define extent + nr_ccws * locate record + nr_ccws * single CCW */ + cplength = 1 + 2 * nr_ccws; + datasize = sizeof(struct DE_fba_data) + + nr_ccws * (sizeof(struct LO_fba_data) + sizeof(struct ccw1)); + + cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev); + if (IS_ERR(cqr)) + return cqr; + + ccw = cqr->cpaddr; + + define_extent(ccw++, cqr->data, WRITE, blksize, first_rec, count); + LO_data = cqr->data + sizeof(struct DE_fba_data); + + /* First part is not aligned. Calculate range to write zeroes. */ + if (first_rec % blocks_per_page != 0) { + wz_stop = first_rec + blocks_per_page - + (first_rec % blocks_per_page) - 1; + if (wz_stop > last_rec) + wz_stop = last_rec; + wz_count = wz_stop - first_rec + 1; + + ccw[-1].flags |= CCW_FLAG_CC; + locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count); + + ccw[-1].flags |= CCW_FLAG_CC; + ccw_write_zero(ccw++, wz_count * blksize); + + cur_pos = wz_count; + } + + /* We can do proper discard when we've got at least blocks_per_page blocks. */ + if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) { + /* is last record at page boundary? */ + if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0) + d_stop = last_rec - ((last_rec - blocks_per_page + 1) % + blocks_per_page); + else + d_stop = last_rec; + + d_count = d_stop - (first_rec + cur_pos) + 1; + + ccw[-1].flags |= CCW_FLAG_CC; + locate_record(ccw++, LO_data++, WRITE, cur_pos, d_count); + + ccw[-1].flags |= CCW_FLAG_CC; + ccw_write_no_data(ccw++); + + cur_pos += d_count; + } + + /* We might still have some bits left which need to be zeroed. */ + if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec) { + if (d_stop != 0) + wz_count = last_rec - d_stop; + else if (wz_stop != 0) + wz_count = last_rec - wz_stop; + else + wz_count = count; + + ccw[-1].flags |= CCW_FLAG_CC; + locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count); + + ccw[-1].flags |= CCW_FLAG_CC; + ccw_write_zero(ccw++, wz_count * blksize); + } + + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + + cqr->startdev = memdev; + cqr->memdev = memdev; + cqr->block = block; + cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */ + cqr->retries = memdev->default_retries; + cqr->buildclk = get_tod_clock(); + cqr->status = DASD_CQR_FILLED; + + return cqr; +} + +static struct dasd_ccw_req *dasd_fba_build_cp_regular( + struct dasd_device *memdev, + struct dasd_block *block, + struct request *req) { struct dasd_fba_private *private = block->base->private; unsigned long *idaws; @@ -372,6 +558,16 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, return cqr; } +static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device *memdev, + struct dasd_block *block, + struct request *req) +{ + if (req_op(req) == REQ_OP_DISCARD || req_op(req) == REQ_OP_WRITE_ZEROES) + return dasd_fba_build_cp_discard(memdev, block, req); + else + return dasd_fba_build_cp_regular(memdev, block, req); +} + static int dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) { diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 66248795b973..f9e25fc03d6b 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -167,6 +167,9 @@ do { \ printk(d_loglevel PRINTK_HEADER " " d_string "\n", d_args); \ } while(0) +/* Macro to calculate number of blocks per page */ +#define BLOCKS_PER_PAGE(blksize) (PAGE_SIZE / blksize) + struct dasd_ccw_req { unsigned int magic; /* Eye catcher */ struct list_head devlist; /* for dasd_device request queue */ -- cgit v1.2.3