aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-12-09 09:23:52 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-09 14:09:24 -0500
commitacc0f67f307f52f7aec1cffdc40a786c15dd21d9 (patch)
tree30fe7356b60d42814b63c3de8ab00ac2bf9ed05d /drivers/tty/tty_buffer.c
parent9bbc3dca9d2212f900396ab9642c48279657a8c0 (diff)
tty: Halve flip buffer GFP_ATOMIC memory consumption
tty flip buffers use GFP_ATOMIC allocations for received data which is to be processed by the line discipline. For each byte received, an extra byte is used to indicate the error status of that byte. Instead, if the received data is error-free, encode the entire buffer without status bytes. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c45
1 files changed, 35 insertions, 10 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 08835a6dd022..3002e20e10d7 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -101,6 +101,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)
101 p->next = NULL; 101 p->next = NULL;
102 p->commit = 0; 102 p->commit = 0;
103 p->read = 0; 103 p->read = 0;
104 p->flags = 0;
104} 105}
105 106
106/** 107/**
@@ -229,31 +230,49 @@ void tty_buffer_flush(struct tty_struct *tty)
229 * tty_buffer_request_room - grow tty buffer if needed 230 * tty_buffer_request_room - grow tty buffer if needed
230 * @tty: tty structure 231 * @tty: tty structure
231 * @size: size desired 232 * @size: size desired
233 * @flags: buffer flags if new buffer allocated (default = 0)
232 * 234 *
233 * Make at least size bytes of linear space available for the tty 235 * Make at least size bytes of linear space available for the tty
234 * buffer. If we fail return the size we managed to find. 236 * buffer. If we fail return the size we managed to find.
237 *
238 * Will change over to a new buffer if the current buffer is encoded as
239 * TTY_NORMAL (so has no flags buffer) and the new buffer requires
240 * a flags buffer.
235 */ 241 */
236int tty_buffer_request_room(struct tty_port *port, size_t size) 242static int __tty_buffer_request_room(struct tty_port *port, size_t size,
243 int flags)
237{ 244{
238 struct tty_bufhead *buf = &port->buf; 245 struct tty_bufhead *buf = &port->buf;
239 struct tty_buffer *b, *n; 246 struct tty_buffer *b, *n;
240 int left; 247 int left, change;
241 248
242 b = buf->tail; 249 b = buf->tail;
243 left = b->size - b->used; 250 if (b->flags & TTYB_NORMAL)
251 left = 2 * b->size - b->used;
252 else
253 left = b->size - b->used;
244 254
245 if (left < size) { 255 change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
256 if (change || left < size) {
246 /* This is the slow path - looking for new buffers to use */ 257 /* This is the slow path - looking for new buffers to use */
247 if ((n = tty_buffer_alloc(port, size)) != NULL) { 258 if ((n = tty_buffer_alloc(port, size)) != NULL) {
259 n->flags = flags;
248 buf->tail = n; 260 buf->tail = n;
249 b->commit = b->used; 261 b->commit = b->used;
250 smp_mb(); 262 smp_mb();
251 b->next = n; 263 b->next = n;
252 } else 264 } else if (change)
265 size = 0;
266 else
253 size = left; 267 size = left;
254 } 268 }
255 return size; 269 return size;
256} 270}
271
272int tty_buffer_request_room(struct tty_port *port, size_t size)
273{
274 return __tty_buffer_request_room(port, size, 0);
275}
257EXPORT_SYMBOL_GPL(tty_buffer_request_room); 276EXPORT_SYMBOL_GPL(tty_buffer_request_room);
258 277
259/** 278/**
@@ -273,12 +292,14 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
273 int copied = 0; 292 int copied = 0;
274 do { 293 do {
275 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 294 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
276 int space = tty_buffer_request_room(port, goal); 295 int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
296 int space = __tty_buffer_request_room(port, goal, flags);
277 struct tty_buffer *tb = port->buf.tail; 297 struct tty_buffer *tb = port->buf.tail;
278 if (unlikely(space == 0)) 298 if (unlikely(space == 0))
279 break; 299 break;
280 memcpy(char_buf_ptr(tb, tb->used), chars, space); 300 memcpy(char_buf_ptr(tb, tb->used), chars, space);
281 memset(flag_buf_ptr(tb, tb->used), flag, space); 301 if (~tb->flags & TTYB_NORMAL)
302 memset(flag_buf_ptr(tb, tb->used), flag, space);
282 tb->used += space; 303 tb->used += space;
283 copied += space; 304 copied += space;
284 chars += space; 305 chars += space;
@@ -361,11 +382,12 @@ EXPORT_SYMBOL(tty_schedule_flip);
361int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, 382int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
362 size_t size) 383 size_t size)
363{ 384{
364 int space = tty_buffer_request_room(port, size); 385 int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
365 if (likely(space)) { 386 if (likely(space)) {
366 struct tty_buffer *tb = port->buf.tail; 387 struct tty_buffer *tb = port->buf.tail;
367 *chars = char_buf_ptr(tb, tb->used); 388 *chars = char_buf_ptr(tb, tb->used);
368 memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); 389 if (~tb->flags & TTYB_NORMAL)
390 memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
369 tb->used += space; 391 tb->used += space;
370 } 392 }
371 return space; 393 return space;
@@ -378,7 +400,10 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
378{ 400{
379 struct tty_ldisc *disc = tty->ldisc; 401 struct tty_ldisc *disc = tty->ldisc;
380 unsigned char *p = char_buf_ptr(head, head->read); 402 unsigned char *p = char_buf_ptr(head, head->read);
381 char *f = flag_buf_ptr(head, head->read); 403 char *f = NULL;
404
405 if (~head->flags & TTYB_NORMAL)
406 f = flag_buf_ptr(head, head->read);
382 407
383 if (disc->ops->receive_buf2) 408 if (disc->ops->receive_buf2)
384 count = disc->ops->receive_buf2(tty, p, f, count); 409 count = disc->ops->receive_buf2(tty, p, f, count);