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

s390/sclp: add parameter to specify number of buffer pages

Add a kernel parameter to be able to specify the number of pages to be
used as output buffer by the line-mode sclp driver and the vt220 sclp
driver. The current number of output pages is 6, if the service element
is unavailable the boot messages alone can fill up the output buffer.
If this happens the system blocks until the service element is working
again. For a large LPAR with many devices it is sensible to have the
ability to increase the output buffer size. To help to debug this
situation add a counter for the page-pool-empty situation and make it
available as a sclp driver attribute.
To avoid the system to stall until the service element works again
add another kernel parameter to allow to drop output buffers.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+138 -7
+69
drivers/s390/char/sclp.c
··· 50 50 /* Suspend request */ 51 51 static DECLARE_COMPLETION(sclp_request_queue_flushed); 52 52 53 + /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */ 54 + int sclp_console_pages = SCLP_CONSOLE_PAGES; 55 + /* Flag to indicate if buffer pages are dropped on buffer full condition */ 56 + int sclp_console_drop = 0; 57 + /* Number of times the console dropped buffer pages */ 58 + unsigned long sclp_console_full; 59 + 53 60 static void sclp_suspend_req_cb(struct sclp_req *req, void *data) 54 61 { 55 62 complete(&sclp_request_queue_flushed); 56 63 } 64 + 65 + static int __init sclp_setup_console_pages(char *str) 66 + { 67 + int pages, rc; 68 + 69 + rc = kstrtoint(str, 0, &pages); 70 + if (!rc && pages >= SCLP_CONSOLE_PAGES) 71 + sclp_console_pages = pages; 72 + return 1; 73 + } 74 + 75 + __setup("sclp_con_pages=", sclp_setup_console_pages); 76 + 77 + static int __init sclp_setup_console_drop(char *str) 78 + { 79 + int drop, rc; 80 + 81 + rc = kstrtoint(str, 0, &drop); 82 + if (!rc && drop) 83 + sclp_console_drop = 1; 84 + return 1; 85 + } 86 + 87 + __setup("sclp_con_drop=", sclp_setup_console_drop); 57 88 58 89 static struct sclp_req sclp_suspend_req; 59 90 ··· 1044 1013 .restore = sclp_restore, 1045 1014 }; 1046 1015 1016 + static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf) 1017 + { 1018 + return sprintf(buf, "%i\n", sclp_console_pages); 1019 + } 1020 + 1021 + static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL); 1022 + 1023 + static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf) 1024 + { 1025 + return sprintf(buf, "%i\n", sclp_console_drop); 1026 + } 1027 + 1028 + static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL); 1029 + 1030 + static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf) 1031 + { 1032 + return sprintf(buf, "%lu\n", sclp_console_full); 1033 + } 1034 + 1035 + static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL); 1036 + 1037 + static struct attribute *sclp_drv_attrs[] = { 1038 + &driver_attr_con_pages.attr, 1039 + &driver_attr_con_drop.attr, 1040 + &driver_attr_con_full.attr, 1041 + NULL, 1042 + }; 1043 + static struct attribute_group sclp_drv_attr_group = { 1044 + .attrs = sclp_drv_attrs, 1045 + }; 1046 + static const struct attribute_group *sclp_drv_attr_groups[] = { 1047 + &sclp_drv_attr_group, 1048 + NULL, 1049 + }; 1050 + 1047 1051 static struct platform_driver sclp_pdrv = { 1048 1052 .driver = { 1049 1053 .name = "sclp", 1050 1054 .owner = THIS_MODULE, 1051 1055 .pm = &sclp_pm_ops, 1056 + .groups = sclp_drv_attr_groups, 1052 1057 }, 1053 1058 }; 1054 1059 ··· 1163 1096 rc = platform_driver_register(&sclp_pdrv); 1164 1097 if (rc) 1165 1098 return rc; 1099 + 1166 1100 sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); 1167 1101 rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; 1168 1102 if (rc) 1169 1103 goto fail_platform_driver_unregister; 1104 + 1170 1105 rc = atomic_notifier_chain_register(&panic_notifier_list, 1171 1106 &sclp_on_panic_nb); 1172 1107 if (rc)
+5 -1
drivers/s390/char/sclp.h
··· 15 15 16 16 /* maximum number of pages concerning our own memory management */ 17 17 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) 18 - #define MAX_CONSOLE_PAGES 6 18 + #define SCLP_CONSOLE_PAGES 6 19 19 20 20 #define EVTYP_OPCMD 0x01 21 21 #define EVTYP_MSG 0x02 ··· 174 174 175 175 int sclp_sdias_init(void); 176 176 void sclp_sdias_exit(void); 177 + 178 + extern int sclp_console_pages; 179 + extern int sclp_console_drop; 180 + extern unsigned long sclp_console_full; 177 181 178 182 /* useful inlines */ 179 183
+30 -1
drivers/s390/char/sclp_con.c
··· 130 130 } 131 131 132 132 /* 133 + * Drop oldest console buffer if sclp_con_drop is set 134 + */ 135 + static int 136 + sclp_console_drop_buffer(void) 137 + { 138 + struct list_head *list; 139 + struct sclp_buffer *buffer; 140 + void *page; 141 + 142 + if (!sclp_console_drop) 143 + return 0; 144 + list = sclp_con_outqueue.next; 145 + if (sclp_con_queue_running) 146 + /* The first element is in I/O */ 147 + list = list->next; 148 + if (list == &sclp_con_outqueue) 149 + return 0; 150 + list_del(list); 151 + buffer = list_entry(list, struct sclp_buffer, list); 152 + page = sclp_unmake_buffer(buffer); 153 + list_add_tail((struct list_head *) page, &sclp_con_pages); 154 + return 1; 155 + } 156 + 157 + /* 133 158 * Writes the given message to S390 system console 134 159 */ 135 160 static void ··· 175 150 do { 176 151 /* make sure we have a console output buffer */ 177 152 if (sclp_conbuf == NULL) { 153 + if (list_empty(&sclp_con_pages)) 154 + sclp_console_full++; 178 155 while (list_empty(&sclp_con_pages)) { 179 156 if (sclp_con_suspended) 180 157 goto out; 158 + if (sclp_console_drop_buffer()) 159 + break; 181 160 spin_unlock_irqrestore(&sclp_con_lock, flags); 182 161 sclp_sync_wait(); 183 162 spin_lock_irqsave(&sclp_con_lock, flags); ··· 326 297 return rc; 327 298 /* Allocate pages for output buffering */ 328 299 INIT_LIST_HEAD(&sclp_con_pages); 329 - for (i = 0; i < MAX_CONSOLE_PAGES; i++) { 300 + for (i = 0; i < sclp_console_pages; i++) { 330 301 page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 331 302 list_add_tail(page, &sclp_con_pages); 332 303 }
+34 -5
drivers/s390/char/sclp_vt220.c
··· 362 362 363 363 #define BUFFER_MAX_DELAY HZ/20 364 364 365 + /* 366 + * Drop oldest console buffer if sclp_con_drop is set 367 + */ 368 + static int 369 + sclp_vt220_drop_buffer(void) 370 + { 371 + struct list_head *list; 372 + struct sclp_vt220_request *request; 373 + void *page; 374 + 375 + if (!sclp_console_drop) 376 + return 0; 377 + list = sclp_vt220_outqueue.next; 378 + if (sclp_vt220_queue_running) 379 + /* The first element is in I/O */ 380 + list = list->next; 381 + if (list == &sclp_vt220_outqueue) 382 + return 0; 383 + list_del(list); 384 + request = list_entry(list, struct sclp_vt220_request, list); 385 + page = request->sclp_req.sccb; 386 + list_add_tail((struct list_head *) page, &sclp_vt220_empty); 387 + return 1; 388 + } 389 + 365 390 /* 366 391 * Internal implementation of the write function. Write COUNT bytes of data 367 392 * from memory at BUF ··· 415 390 do { 416 391 /* Create an sclp output buffer if none exists yet */ 417 392 if (sclp_vt220_current_request == NULL) { 393 + if (list_empty(&sclp_vt220_empty)) 394 + sclp_console_full++; 418 395 while (list_empty(&sclp_vt220_empty)) { 419 - spin_unlock_irqrestore(&sclp_vt220_lock, flags); 420 396 if (may_fail || sclp_vt220_suspended) 421 397 goto out; 422 - else 423 - sclp_sync_wait(); 398 + if (sclp_vt220_drop_buffer()) 399 + break; 400 + spin_unlock_irqrestore(&sclp_vt220_lock, flags); 401 + 402 + sclp_sync_wait(); 424 403 spin_lock_irqsave(&sclp_vt220_lock, flags); 425 404 } 426 405 page = (void *) sclp_vt220_empty.next; ··· 457 428 sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY; 458 429 add_timer(&sclp_vt220_timer); 459 430 } 460 - spin_unlock_irqrestore(&sclp_vt220_lock, flags); 461 431 out: 432 + spin_unlock_irqrestore(&sclp_vt220_lock, flags); 462 433 return overall_written; 463 434 } 464 435 ··· 832 803 833 804 if (!CONSOLE_IS_SCLP) 834 805 return 0; 835 - rc = __sclp_vt220_init(MAX_CONSOLE_PAGES); 806 + rc = __sclp_vt220_init(sclp_console_pages); 836 807 if (rc) 837 808 return rc; 838 809 /* Attach linux console */