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>
This commit is contained in:
Martin Schwidefsky 2015-10-01 14:11:35 +02:00
Родитель 83abeffbd5
Коммит 18d1a7f675
3 изменённых файлов: 78 добавлений и 83 удалений

Просмотреть файл

@ -47,9 +47,9 @@ struct sclp_buffer *
sclp_make_buffer(void *page, unsigned short columns, unsigned short htab) sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
{ {
struct sclp_buffer *buffer; struct sclp_buffer *buffer;
struct write_sccb *sccb; struct sccb_header *sccb;
sccb = (struct write_sccb *) page; sccb = (struct sccb_header *) page;
/* /*
* We keep the struct sclp_buffer structure at the end * We keep the struct sclp_buffer structure at the end
* of the sccb page. * of the sccb page.
@ -57,24 +57,16 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1; buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
buffer->sccb = sccb; buffer->sccb = sccb;
buffer->retry_count = 0; buffer->retry_count = 0;
buffer->mto_number = 0; buffer->messages = 0;
buffer->mto_char_sum = 0; buffer->char_sum = 0;
buffer->current_line = NULL; buffer->current_line = NULL;
buffer->current_length = 0; buffer->current_length = 0;
buffer->columns = columns; buffer->columns = columns;
buffer->htab = htab; buffer->htab = htab;
/* initialize sccb */ /* initialize sccb */
memset(sccb, 0, sizeof(struct write_sccb)); memset(sccb, 0, sizeof(struct sccb_header));
sccb->header.length = sizeof(struct write_sccb); sccb->length = sizeof(struct sccb_header);
sccb->msg_buf.header.length = sizeof(struct msg_buf);
sccb->msg_buf.header.type = EVTYP_MSG;
sccb->msg_buf.mdb.header.length = sizeof(struct mdb);
sccb->msg_buf.mdb.header.type = 1;
sccb->msg_buf.mdb.header.tag = 0xD4C4C240; /* ebcdic "MDB " */
sccb->msg_buf.mdb.header.revision_code = 1;
sccb->msg_buf.mdb.go.length = sizeof(struct go);
sccb->msg_buf.mdb.go.type = 1;
return buffer; return buffer;
} }
@ -90,37 +82,49 @@ sclp_unmake_buffer(struct sclp_buffer *buffer)
} }
/* /*
* Initialize a new Message Text Object (MTO) at the end of the provided buffer * Initialize a new message the end of the provided buffer with
* with enough room for max_len characters. Return 0 on success. * enough room for max_len characters. Return 0 on success.
*/ */
static int static int
sclp_initialize_mto(struct sclp_buffer *buffer, int max_len) sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
{ {
struct write_sccb *sccb; struct sccb_header *sccb;
struct msg_buf *msg;
struct mdb *mdb;
struct go *go;
struct mto *mto; struct mto *mto;
int mto_size; int msg_size;
/* max size of new Message Text Object including message text */ /* max size of new message including message text */
mto_size = sizeof(struct mto) + max_len; msg_size = sizeof(struct msg_buf) + max_len;
/* check if current buffer sccb can contain the mto */ /* check if current buffer sccb can contain the mto */
sccb = buffer->sccb; sccb = buffer->sccb;
if ((MAX_SCCB_ROOM - sccb->header.length) < mto_size) if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
return -ENOMEM; return -ENOMEM;
/* find address of new message text object */ msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
mto = (struct mto *)(((addr_t) sccb) + sccb->header.length); memset(msg, 0, sizeof(struct msg_buf));
msg->header.length = sizeof(struct msg_buf);
msg->header.type = EVTYP_MSG;
/* mdb = &msg->mdb;
* fill the new Message-Text Object, mdb->header.length = sizeof(struct mdb);
* starting behind the former last byte of the SCCB mdb->header.type = 1;
*/ mdb->header.tag = 0xD4C4C240; /* ebcdic "MDB " */
memset(mto, 0, sizeof(struct mto)); mdb->header.revision_code = 1;
go = &mdb->go;
go->length = sizeof(struct go);
go->type = 1;
mto = &mdb->mto;
mto->length = sizeof(struct mto); mto->length = sizeof(struct mto);
mto->type = 4; /* message text object */ mto->type = 4; /* message text object */
mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */ mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
/* set pointer to first byte after struct mto. */ /* set pointer to first byte after struct mto. */
buffer->current_msg = msg;
buffer->current_line = (char *) (mto + 1); buffer->current_line = (char *) (mto + 1);
buffer->current_length = 0; buffer->current_length = 0;
@ -128,45 +132,37 @@ sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
} }
/* /*
* Finalize MTO initialized by sclp_initialize_mto(), updating the sizes of * Finalize message initialized by sclp_initialize_mto(),
* MTO, enclosing MDB, event buffer and SCCB. * updating the sizes of MTO, enclosing MDB, event buffer and SCCB.
*/ */
static void static void
sclp_finalize_mto(struct sclp_buffer *buffer) sclp_finalize_mto(struct sclp_buffer *buffer)
{ {
struct write_sccb *sccb; struct sccb_header *sccb;
struct mto *mto; struct msg_buf *msg;
int str_len, mto_size;
str_len = buffer->current_length;
buffer->current_line = NULL;
buffer->current_length = 0;
/* real size of new Message Text Object including message text */
mto_size = sizeof(struct mto) + str_len;
/* find address of new message text object */
sccb = buffer->sccb;
mto = (struct mto *)(((addr_t) sccb) + sccb->header.length);
/* set size of message text object */
mto->length = mto_size;
/* /*
* update values of sizes * update values of sizes
* (SCCB, Event(Message) Buffer, Message Data Block) * (SCCB, Event(Message) Buffer, Message Data Block)
*/ */
sccb->header.length += mto_size; sccb = buffer->sccb;
sccb->msg_buf.header.length += mto_size; msg = buffer->current_msg;
sccb->msg_buf.mdb.header.length += mto_size; msg->header.length += buffer->current_length;
msg->mdb.header.length += buffer->current_length;
msg->mdb.mto.length += buffer->current_length;
sccb->length += msg->header.length;
/* /*
* count number of buffered messages (= number of Message Text * count number of buffered messages (= number of Message Text
* Objects) and number of buffered characters * Objects) and number of buffered characters
* for the SCCB currently used for buffering and at all * for the SCCB currently used for buffering and at all
*/ */
buffer->mto_number++; buffer->messages++;
buffer->mto_char_sum += str_len; buffer->char_sum += buffer->current_length;
buffer->current_line = NULL;
buffer->current_length = 0;
buffer->current_msg = NULL;
} }
/* /*
@ -218,7 +214,13 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
break; break;
case '\a': /* bell, one for several times */ case '\a': /* bell, one for several times */
/* set SCLP sound alarm bit in General Object */ /* set SCLP sound alarm bit in General Object */
buffer->sccb->msg_buf.mdb.go.general_msg_flags |= if (buffer->current_line == NULL) {
rc = sclp_initialize_mto(buffer,
buffer->columns);
if (rc)
return i_msg;
}
buffer->current_msg->mdb.go.general_msg_flags |=
GNRLMSGFLGS_SNDALRM; GNRLMSGFLGS_SNDALRM;
break; break;
case '\t': /* horizontal tabulator */ case '\t': /* horizontal tabulator */
@ -309,11 +311,13 @@ sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
int int
sclp_buffer_space(struct sclp_buffer *buffer) sclp_buffer_space(struct sclp_buffer *buffer)
{ {
struct sccb_header *sccb;
int count; int count;
count = MAX_SCCB_ROOM - buffer->sccb->header.length; sccb = buffer->sccb;
count = MAX_SCCB_ROOM - sccb->length;
if (buffer->current_line != NULL) if (buffer->current_line != NULL)
count -= sizeof(struct mto) + buffer->current_length; count -= sizeof(struct msg_buf) + buffer->current_length;
return count; return count;
} }
@ -325,7 +329,7 @@ sclp_chars_in_buffer(struct sclp_buffer *buffer)
{ {
int count; int count;
count = buffer->mto_char_sum; count = buffer->char_sum;
if (buffer->current_line != NULL) if (buffer->current_line != NULL)
count += buffer->current_length; count += buffer->current_length;
return count; return count;
@ -378,7 +382,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
{ {
int rc; int rc;
struct sclp_buffer *buffer; struct sclp_buffer *buffer;
struct write_sccb *sccb; struct sccb_header *sccb;
buffer = (struct sclp_buffer *) data; buffer = (struct sclp_buffer *) data;
sccb = buffer->sccb; sccb = buffer->sccb;
@ -389,7 +393,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
return; return;
} }
/* check SCLP response code and choose suitable action */ /* check SCLP response code and choose suitable action */
switch (sccb->header.response_code) { switch (sccb->response_code) {
case 0x0020 : case 0x0020 :
/* Normal completion, buffer processed, message(s) sent */ /* Normal completion, buffer processed, message(s) sent */
rc = 0; rc = 0;
@ -403,7 +407,7 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
/* remove processed buffers and requeue rest */ /* remove processed buffers and requeue rest */
if (sclp_remove_processed((struct sccb_header *) sccb) > 0) { if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
/* not all buffers were processed */ /* not all buffers were processed */
sccb->header.response_code = 0x0000; sccb->response_code = 0x0000;
buffer->request.status = SCLP_REQ_FILLED; buffer->request.status = SCLP_REQ_FILLED;
rc = sclp_add_request(request); rc = sclp_add_request(request);
if (rc == 0) if (rc == 0)
@ -419,14 +423,14 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
break; break;
} }
/* retry request */ /* retry request */
sccb->header.response_code = 0x0000; sccb->response_code = 0x0000;
buffer->request.status = SCLP_REQ_FILLED; buffer->request.status = SCLP_REQ_FILLED;
rc = sclp_add_request(request); rc = sclp_add_request(request);
if (rc == 0) if (rc == 0)
return; return;
break; break;
default: default:
if (sccb->header.response_code == 0x71f0) if (sccb->response_code == 0x71f0)
rc = -ENOMEM; rc = -ENOMEM;
else else
rc = -EINVAL; rc = -EINVAL;
@ -445,25 +449,19 @@ int
sclp_emit_buffer(struct sclp_buffer *buffer, sclp_emit_buffer(struct sclp_buffer *buffer,
void (*callback)(struct sclp_buffer *, int)) void (*callback)(struct sclp_buffer *, int))
{ {
struct write_sccb *sccb;
/* add current line if there is one */ /* add current line if there is one */
if (buffer->current_line != NULL) if (buffer->current_line != NULL)
sclp_finalize_mto(buffer); sclp_finalize_mto(buffer);
/* Are there messages in the output buffer ? */ /* Are there messages in the output buffer ? */
if (buffer->mto_number == 0) if (buffer->messages == 0)
return -EIO; return -EIO;
sccb = buffer->sccb;
/* Use normal write message */
sccb->msg_buf.header.type = EVTYP_MSG;
buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
buffer->request.status = SCLP_REQ_FILLED; buffer->request.status = SCLP_REQ_FILLED;
buffer->request.callback = sclp_writedata_callback; buffer->request.callback = sclp_writedata_callback;
buffer->request.callback_data = buffer; buffer->request.callback_data = buffer;
buffer->request.sccb = sccb; buffer->request.sccb = buffer->sccb;
buffer->callback = callback; buffer->callback = callback;
return sclp_add_request(&buffer->request); return sclp_add_request(&buffer->request);
} }

Просмотреть файл

@ -45,6 +45,7 @@ struct mdb_header {
struct mdb { struct mdb {
struct mdb_header header; struct mdb_header header;
struct go go; struct go go;
struct mto mto;
} __attribute__((packed)); } __attribute__((packed));
struct msg_buf { struct msg_buf {
@ -52,14 +53,9 @@ struct msg_buf {
struct mdb mdb; struct mdb mdb;
} __attribute__((packed)); } __attribute__((packed));
struct write_sccb {
struct sccb_header header;
struct msg_buf msg_buf;
} __attribute__((packed));
/* The number of empty mto buffers that can be contained in a single sccb. */ /* The number of empty mto buffers that can be contained in a single sccb. */
#define NR_EMPTY_MTO_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \ #define NR_EMPTY_MSG_PER_SCCB ((PAGE_SIZE - sizeof(struct sclp_buffer) - \
sizeof(struct write_sccb)) / sizeof(struct mto)) sizeof(struct sccb_header)) / sizeof(struct msg_buf))
/* /*
* data structure for information about list of SCCBs (only for writing), * data structure for information about list of SCCBs (only for writing),
@ -68,7 +64,8 @@ struct write_sccb {
struct sclp_buffer { struct sclp_buffer {
struct list_head list; /* list_head for sccb_info chain */ struct list_head list; /* list_head for sccb_info chain */
struct sclp_req request; struct sclp_req request;
struct write_sccb *sccb; void *sccb;
struct msg_buf *current_msg;
char *current_line; char *current_line;
int current_length; int current_length;
int retry_count; int retry_count;
@ -76,8 +73,8 @@ struct sclp_buffer {
unsigned short columns; unsigned short columns;
unsigned short htab; unsigned short htab;
/* statistics about this buffer */ /* statistics about this buffer */
unsigned int mto_char_sum; /* # chars in sccb */ unsigned int char_sum; /* # chars in sccb */
unsigned int mto_number; /* # mtos in sccb */ unsigned int messages; /* # messages in sccb */
/* Callback that is called after reaching final status. */ /* Callback that is called after reaching final status. */
void (*callback)(struct sclp_buffer *, int); void (*callback)(struct sclp_buffer *, int);
}; };

Просмотреть файл

@ -84,8 +84,8 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
* to change as output buffers get emptied, or if the output flow * to change as output buffers get emptied, or if the output flow
* control is acted. This is not an exact number because not every * control is acted. This is not an exact number because not every
* character needs the same space in the sccb. The worst case is * character needs the same space in the sccb. The worst case is
* a string of newlines. Every newlines creates a new mto which * a string of newlines. Every newline creates a new message which
* needs 8 bytes. * needs 82 bytes.
*/ */
static int static int
sclp_tty_write_room (struct tty_struct *tty) sclp_tty_write_room (struct tty_struct *tty)
@ -97,9 +97,9 @@ sclp_tty_write_room (struct tty_struct *tty)
spin_lock_irqsave(&sclp_tty_lock, flags); spin_lock_irqsave(&sclp_tty_lock, flags);
count = 0; count = 0;
if (sclp_ttybuf != NULL) if (sclp_ttybuf != NULL)
count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct mto); count = sclp_buffer_space(sclp_ttybuf) / sizeof(struct msg_buf);
list_for_each(l, &sclp_tty_pages) list_for_each(l, &sclp_tty_pages)
count += NR_EMPTY_MTO_PER_SCCB; count += NR_EMPTY_MSG_PER_SCCB;
spin_unlock_irqrestore(&sclp_tty_lock, flags); spin_unlock_irqrestore(&sclp_tty_lock, flags);
return count; return count;
} }