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

s390/sclp: avoid merged message output

The sclp console and tty code currently uses several message text
objects in a single message event to print several lines with one
SCCB. This causes the output of these lines to be fused into a
block which is noticeable when selecting text in the operating system
message panel.

Instead use several message events with a single message text object
each to print every line on its own. This changes the SCCB layout
from

struct sccb_header
struct evbuf_header
struct mdb_header
struct go
struct mto
...
struct mto

to

struct sccb_header
struct evbuf_header
struct mdb_header
struct go
struct mto
...
struct evbuf_header
struct mdb_header
struct go
struct mto

Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+78 -83
+67 -69
drivers/s390/char/sclp_rw.c
··· 47 47 sclp_make_buffer(void *page, unsigned short columns, unsigned short htab) 48 48 { 49 49 struct sclp_buffer *buffer; 50 - struct write_sccb *sccb; 50 + struct sccb_header *sccb; 51 51 52 - sccb = (struct write_sccb *) page; 52 + sccb = (struct sccb_header *) page; 53 53 /* 54 54 * We keep the struct sclp_buffer structure at the end 55 55 * of the sccb page. ··· 57 57 buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1; 58 58 buffer->sccb = sccb; 59 59 buffer->retry_count = 0; 60 - buffer->mto_number = 0; 61 - buffer->mto_char_sum = 0; 60 + buffer->messages = 0; 61 + buffer->char_sum = 0; 62 62 buffer->current_line = NULL; 63 63 buffer->current_length = 0; 64 64 buffer->columns = columns; 65 65 buffer->htab = htab; 66 66 67 67 /* initialize sccb */ 68 - memset(sccb, 0, sizeof(struct write_sccb)); 69 - sccb->header.length = sizeof(struct write_sccb); 70 - sccb->msg_buf.header.length = sizeof(struct msg_buf); 71 - sccb->msg_buf.header.type = EVTYP_MSG; 72 - sccb->msg_buf.mdb.header.length = sizeof(struct mdb); 73 - sccb->msg_buf.mdb.header.type = 1; 74 - sccb->msg_buf.mdb.header.tag = 0xD4C4C240; /* ebcdic "MDB " */ 75 - sccb->msg_buf.mdb.header.revision_code = 1; 76 - sccb->msg_buf.mdb.go.length = sizeof(struct go); 77 - sccb->msg_buf.mdb.go.type = 1; 68 + memset(sccb, 0, sizeof(struct sccb_header)); 69 + sccb->length = sizeof(struct sccb_header); 78 70 79 71 return buffer; 80 72 } ··· 82 90 } 83 91 84 92 /* 85 - * Initialize a new Message Text Object (MTO) at the end of the provided buffer 86 - * with enough room for max_len characters. Return 0 on success. 93 + * Initialize a new message the end of the provided buffer with 94 + * enough room for max_len characters. Return 0 on success. 87 95 */ 88 96 static int 89 97 sclp_initialize_mto(struct sclp_buffer *buffer, int max_len) 90 98 { 91 - struct write_sccb *sccb; 99 + struct sccb_header *sccb; 100 + struct msg_buf *msg; 101 + struct mdb *mdb; 102 + struct go *go; 92 103 struct mto *mto; 93 - int mto_size; 104 + int msg_size; 94 105 95 - /* max size of new Message Text Object including message text */ 96 - mto_size = sizeof(struct mto) + max_len; 106 + /* max size of new message including message text */ 107 + msg_size = sizeof(struct msg_buf) + max_len; 97 108 98 109 /* check if current buffer sccb can contain the mto */ 99 110 sccb = buffer->sccb; 100 - if ((MAX_SCCB_ROOM - sccb->header.length) < mto_size) 111 + if ((MAX_SCCB_ROOM - sccb->length) < msg_size) 101 112 return -ENOMEM; 102 113 103 - /* find address of new message text object */ 104 - mto = (struct mto *)(((addr_t) sccb) + sccb->header.length); 114 + msg = (struct msg_buf *)((addr_t) sccb + sccb->length); 115 + memset(msg, 0, sizeof(struct msg_buf)); 116 + msg->header.length = sizeof(struct msg_buf); 117 + msg->header.type = EVTYP_MSG; 105 118 106 - /* 107 - * fill the new Message-Text Object, 108 - * starting behind the former last byte of the SCCB 109 - */ 110 - memset(mto, 0, sizeof(struct mto)); 119 + mdb = &msg->mdb; 120 + mdb->header.length = sizeof(struct mdb); 121 + mdb->header.type = 1; 122 + mdb->header.tag = 0xD4C4C240; /* ebcdic "MDB " */ 123 + mdb->header.revision_code = 1; 124 + 125 + go = &mdb->go; 126 + go->length = sizeof(struct go); 127 + go->type = 1; 128 + 129 + mto = &mdb->mto; 111 130 mto->length = sizeof(struct mto); 112 131 mto->type = 4; /* message text object */ 113 132 mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */ 114 133 115 134 /* set pointer to first byte after struct mto. */ 135 + buffer->current_msg = msg; 116 136 buffer->current_line = (char *) (mto + 1); 117 137 buffer->current_length = 0; 118 138 ··· 132 128 } 133 129 134 130 /* 135 - * Finalize MTO initialized by sclp_initialize_mto(), updating the sizes of 136 - * MTO, enclosing MDB, event buffer and SCCB. 131 + * Finalize message initialized by sclp_initialize_mto(), 132 + * updating the sizes of MTO, enclosing MDB, event buffer and SCCB. 137 133 */ 138 134 static void 139 135 sclp_finalize_mto(struct sclp_buffer *buffer) 140 136 { 141 - struct write_sccb *sccb; 142 - struct mto *mto; 143 - int str_len, mto_size; 144 - 145 - str_len = buffer->current_length; 146 - buffer->current_line = NULL; 147 - buffer->current_length = 0; 148 - 149 - /* real size of new Message Text Object including message text */ 150 - mto_size = sizeof(struct mto) + str_len; 151 - 152 - /* find address of new message text object */ 153 - sccb = buffer->sccb; 154 - mto = (struct mto *)(((addr_t) sccb) + sccb->header.length); 155 - 156 - /* set size of message text object */ 157 - mto->length = mto_size; 137 + struct sccb_header *sccb; 138 + struct msg_buf *msg; 158 139 159 140 /* 160 141 * update values of sizes 161 142 * (SCCB, Event(Message) Buffer, Message Data Block) 162 143 */ 163 - sccb->header.length += mto_size; 164 - sccb->msg_buf.header.length += mto_size; 165 - sccb->msg_buf.mdb.header.length += mto_size; 144 + sccb = buffer->sccb; 145 + msg = buffer->current_msg; 146 + msg->header.length += buffer->current_length; 147 + msg->mdb.header.length += buffer->current_length; 148 + msg->mdb.mto.length += buffer->current_length; 149 + sccb->length += msg->header.length; 166 150 167 151 /* 168 152 * count number of buffered messages (= number of Message Text 169 153 * Objects) and number of buffered characters 170 154 * for the SCCB currently used for buffering and at all 171 155 */ 172 - buffer->mto_number++; 173 - buffer->mto_char_sum += str_len; 156 + buffer->messages++; 157 + buffer->char_sum += buffer->current_length; 158 + 159 + buffer->current_line = NULL; 160 + buffer->current_length = 0; 161 + buffer->current_msg = NULL; 174 162 } 175 163 176 164 /* ··· 214 218 break; 215 219 case '\a': /* bell, one for several times */ 216 220 /* set SCLP sound alarm bit in General Object */ 217 - buffer->sccb->msg_buf.mdb.go.general_msg_flags |= 221 + if (buffer->current_line == NULL) { 222 + rc = sclp_initialize_mto(buffer, 223 + buffer->columns); 224 + if (rc) 225 + return i_msg; 226 + } 227 + buffer->current_msg->mdb.go.general_msg_flags |= 218 228 GNRLMSGFLGS_SNDALRM; 219 229 break; 220 230 case '\t': /* horizontal tabulator */ ··· 311 309 int 312 310 sclp_buffer_space(struct sclp_buffer *buffer) 313 311 { 312 + struct sccb_header *sccb; 314 313 int count; 315 314 316 - count = MAX_SCCB_ROOM - buffer->sccb->header.length; 315 + sccb = buffer->sccb; 316 + count = MAX_SCCB_ROOM - sccb->length; 317 317 if (buffer->current_line != NULL) 318 - count -= sizeof(struct mto) + buffer->current_length; 318 + count -= sizeof(struct msg_buf) + buffer->current_length; 319 319 return count; 320 320 } 321 321 ··· 329 325 { 330 326 int count; 331 327 332 - count = buffer->mto_char_sum; 328 + count = buffer->char_sum; 333 329 if (buffer->current_line != NULL) 334 330 count += buffer->current_length; 335 331 return count; ··· 382 378 { 383 379 int rc; 384 380 struct sclp_buffer *buffer; 385 - struct write_sccb *sccb; 381 + struct sccb_header *sccb; 386 382 387 383 buffer = (struct sclp_buffer *) data; 388 384 sccb = buffer->sccb; ··· 393 389 return; 394 390 } 395 391 /* check SCLP response code and choose suitable action */ 396 - switch (sccb->header.response_code) { 392 + switch (sccb->response_code) { 397 393 case 0x0020 : 398 394 /* Normal completion, buffer processed, message(s) sent */ 399 395 rc = 0; ··· 407 403 /* remove processed buffers and requeue rest */ 408 404 if (sclp_remove_processed((struct sccb_header *) sccb) > 0) { 409 405 /* not all buffers were processed */ 410 - sccb->header.response_code = 0x0000; 406 + sccb->response_code = 0x0000; 411 407 buffer->request.status = SCLP_REQ_FILLED; 412 408 rc = sclp_add_request(request); 413 409 if (rc == 0) ··· 423 419 break; 424 420 } 425 421 /* retry request */ 426 - sccb->header.response_code = 0x0000; 422 + sccb->response_code = 0x0000; 427 423 buffer->request.status = SCLP_REQ_FILLED; 428 424 rc = sclp_add_request(request); 429 425 if (rc == 0) 430 426 return; 431 427 break; 432 428 default: 433 - if (sccb->header.response_code == 0x71f0) 429 + if (sccb->response_code == 0x71f0) 434 430 rc = -ENOMEM; 435 431 else 436 432 rc = -EINVAL; ··· 449 445 sclp_emit_buffer(struct sclp_buffer *buffer, 450 446 void (*callback)(struct sclp_buffer *, int)) 451 447 { 452 - struct write_sccb *sccb; 453 - 454 448 /* add current line if there is one */ 455 449 if (buffer->current_line != NULL) 456 450 sclp_finalize_mto(buffer); 457 451 458 452 /* Are there messages in the output buffer ? */ 459 - if (buffer->mto_number == 0) 453 + if (buffer->messages == 0) 460 454 return -EIO; 461 - 462 - sccb = buffer->sccb; 463 - /* Use normal write message */ 464 - sccb->msg_buf.header.type = EVTYP_MSG; 465 455 466 456 buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; 467 457 buffer->request.status = SCLP_REQ_FILLED; 468 458 buffer->request.callback = sclp_writedata_callback; 469 459 buffer->request.callback_data = buffer; 470 - buffer->request.sccb = sccb; 460 + buffer->request.sccb = buffer->sccb; 471 461 buffer->callback = callback; 472 462 return sclp_add_request(&buffer->request); 473 463 }
+7 -10
drivers/s390/char/sclp_rw.h
··· 45 45 struct mdb { 46 46 struct mdb_header header; 47 47 struct go go; 48 + struct mto mto; 48 49 } __attribute__((packed)); 49 50 50 51 struct msg_buf { ··· 53 52 struct mdb mdb; 54 53 } __attribute__((packed)); 55 54 56 - struct write_sccb { 57 - struct sccb_header header; 58 - struct msg_buf msg_buf; 59 - } __attribute__((packed)); 60 - 61 55 /* The number of empty mto buffers that can be contained in a single sccb. */ 62 - #define NR_EMPTY_MTO_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \ 63 - sizeof(struct write_sccb)) / sizeof(struct mto)) 56 + #define NR_EMPTY_MSG_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \ 57 + sizeof(struct sccb_header)) / sizeof(struct msg_buf)) 64 58 65 59 /* 66 60 * data structure for information about list of SCCBs (only for writing), ··· 64 68 struct sclp_buffer { 65 69 struct list_head list; /* list_head for sccb_info chain */ 66 70 struct sclp_req request; 67 - struct write_sccb *sccb; 71 + void *sccb; 72 + struct msg_buf *current_msg; 68 73 char *current_line; 69 74 int current_length; 70 75 int retry_count; ··· 73 76 unsigned short columns; 74 77 unsigned short htab; 75 78 /* statistics about this buffer */ 76 - unsigned int mto_char_sum; /* # chars in sccb */ 77 - unsigned int mto_number; /* # mtos in sccb */ 79 + unsigned int char_sum; /* # chars in sccb */ 80 + unsigned int messages; /* # messages in sccb */ 78 81 /* Callback that is called after reaching final status. */ 79 82 void (*callback)(struct sclp_buffer *, int); 80 83 };
+4 -4
drivers/s390/char/sclp_tty.c
··· 84 84 * to change as output buffers get emptied, or if the output flow 85 85 * control is acted. This is not an exact number because not every 86 86 * character needs the same space in the sccb. The worst case is 87 - * a string of newlines. Every newlines creates a new mto which 88 - * needs 8 bytes. 87 + * a string of newlines. Every newline creates a new message which 88 + * needs 82 bytes. 89 89 */ 90 90 static int 91 91 sclp_tty_write_room (struct tty_struct *tty) ··· 97 97 spin_lock_irqsave(&sclp_tty_lock, flags); 98 98 count = 0; 99 99 if (sclp_ttybuf != NULL) 100 - count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct mto); 100 + count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct msg_buf); 101 101 list_for_each(l, &sclp_tty_pages) 102 - count += NR_EMPTY_MTO_PER_SCCB; 102 + count += NR_EMPTY_MSG_PER_SCCB; 103 103 spin_unlock_irqrestore(&sclp_tty_lock, flags); 104 104 return count; 105 105 }