Blame view
drivers/tty/tty_buffer.c
16.2 KB
e3b3d0f54 tty: add SPDX ide... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
e04957365 tty: split the bu... |
2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * Tty buffer allocation management */ #include <linux/types.h> #include <linux/errno.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/sched.h> |
e04957365 tty: split the bu... |
15 16 17 18 |
#include <linux/wait.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/module.h> |
593fb1ae4 pps: Move timesta... |
19 |
#include <linux/ratelimit.h> |
e04957365 tty: split the bu... |
20 |
|
1cef50e31 tty: Fix flip buf... |
21 22 23 |
#define MIN_TTYB_SIZE 256 #define TTYB_ALIGN_MASK 255 |
7bfe0b711 tty: Track flip b... |
24 25 26 27 |
/* * Byte threshold to limit memory consumption for flip buffers. * The actual memory limit is > 2x this amount. */ |
7ab57b76e tty: increase the... |
28 |
#define TTYB_DEFAULT_MEM_LIMIT (640 * 1024UL) |
7bfe0b711 tty: Track flip b... |
29 |
|
9114fe8cc tty: Remove priva... |
30 31 32 33 34 35 36 37 38 |
/* * We default to dicing tty buffer allocations to this many characters * in order to avoid multiple page allocations. We know the size of * tty_buffer itself but it must also be taken into account that the * the buffer is 256 byte aligned. See tty_buffer_find for the allocation * logic this must match */ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) |
7bfe0b711 tty: Track flip b... |
39 |
/** |
a7c8d58c7 tty: Fix unsafe v... |
40 41 42 |
* tty_buffer_lock_exclusive - gain exclusive access to buffer * tty_buffer_unlock_exclusive - release exclusive access * |
fa4419545 tty: fix kernel-doc |
43 |
* @port: tty port owning the flip buffer |
a7c8d58c7 tty: Fix unsafe v... |
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
* * Guarantees safe use of the line discipline's receive_buf() method by * excluding the buffer work and any pending flush from using the flip * buffer. Data can continue to be added concurrently to the flip buffer * from the driver side. * * On release, the buffer work is restarted if there is data in the * flip buffer */ void tty_buffer_lock_exclusive(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; atomic_inc(&buf->priority); mutex_lock(&buf->lock); } |
28a821c30 Staging: speakup:... |
61 |
EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); |
a7c8d58c7 tty: Fix unsafe v... |
62 63 64 65 66 67 68 69 70 71 72 73 74 |
void tty_buffer_unlock_exclusive(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; int restart; restart = buf->head->commit != buf->head->read; atomic_dec(&buf->priority); mutex_unlock(&buf->lock); if (restart) queue_work(system_unbound_wq, &buf->work); } |
28a821c30 Staging: speakup:... |
75 |
EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); |
a7c8d58c7 tty: Fix unsafe v... |
76 77 |
/** |
7bfe0b711 tty: Track flip b... |
78 |
* tty_buffer_space_avail - return unused buffer space |
fa4419545 tty: fix kernel-doc |
79 |
* @port: tty port owning the flip buffer |
7bfe0b711 tty: Track flip b... |
80 81 82 83 84 85 86 87 88 89 90 |
* * Returns the # of bytes which can be written by the driver without * reaching the buffer limit. * * Note: this does not guarantee that memory is available to write * the returned # of bytes (use tty_prepare_flip_string_xxx() to * pre-allocate if memory guarantee is required). */ int tty_buffer_space_avail(struct tty_port *port) { |
5dda4ca55 tty: Rename tty b... |
91 |
int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); |
7bfe0b711 tty: Track flip b... |
92 93 |
return max(space, 0); } |
c4a8dab58 staging/fwserial:... |
94 |
EXPORT_SYMBOL_GPL(tty_buffer_space_avail); |
7bfe0b711 tty: Track flip b... |
95 |
|
9dd5139f9 tty: Factor flip ... |
96 97 98 99 100 101 102 |
static void tty_buffer_reset(struct tty_buffer *p, size_t size) { p->used = 0; p->size = size; p->next = NULL; p->commit = 0; p->read = 0; |
acc0f67f3 tty: Halve flip b... |
103 |
p->flags = 0; |
9dd5139f9 tty: Factor flip ... |
104 |
} |
e04957365 tty: split the bu... |
105 106 |
/** * tty_buffer_free_all - free buffers used by a tty |
fa4419545 tty: fix kernel-doc |
107 |
* @port: tty port to free from |
e04957365 tty: split the bu... |
108 109 110 |
* * Remove all the buffers pending on a tty whether queued with data * or in the free ring. Must be called when the tty is no longer in use |
e04957365 tty: split the bu... |
111 |
*/ |
ecbbfd44a TTY: move tty buf... |
112 |
void tty_buffer_free_all(struct tty_port *port) |
e04957365 tty: split the bu... |
113 |
{ |
ecbbfd44a TTY: move tty buf... |
114 |
struct tty_bufhead *buf = &port->buf; |
809850b7a tty: Use lockless... |
115 116 |
struct tty_buffer *p, *next; struct llist_node *llist; |
feacbecb3 TTY: tty_buffer, ... |
117 118 |
unsigned int freed = 0; int still_used; |
5cff39c69 TTY: tty_buffer, ... |
119 |
|
2cf7b67e8 tty: Use generic ... |
120 121 |
while ((p = buf->head) != NULL) { buf->head = p->next; |
feacbecb3 TTY: tty_buffer, ... |
122 |
freed += p->size; |
7391ee169 tty: Simplify fli... |
123 124 |
if (p->size > 0) kfree(p); |
e04957365 tty: split the bu... |
125 |
} |
809850b7a tty: Use lockless... |
126 127 |
llist = llist_del_all(&buf->free); llist_for_each_entry_safe(p, next, llist, free) |
2cf7b67e8 tty: Use generic ... |
128 |
kfree(p); |
809850b7a tty: Use lockless... |
129 |
|
7391ee169 tty: Simplify fli... |
130 131 132 |
tty_buffer_reset(&buf->sentinel, 0); buf->head = &buf->sentinel; buf->tail = &buf->sentinel; |
7bfe0b711 tty: Track flip b... |
133 |
|
feacbecb3 TTY: tty_buffer, ... |
134 135 136 |
still_used = atomic_xchg(&buf->mem_used, 0); WARN(still_used != freed, "we still have not freed %d bytes!", still_used - freed); |
e04957365 tty: split the bu... |
137 138 139 140 |
} /** * tty_buffer_alloc - allocate a tty buffer |
fa4419545 tty: fix kernel-doc |
141 |
* @port: tty port |
e04957365 tty: split the bu... |
142 143 144 |
* @size: desired size (characters) * * Allocate a new tty buffer to hold the desired number of characters. |
11b9faa44 tty: Merge tty_bu... |
145 146 |
* We round our buffers off in 256 character chunks to get better * allocation behaviour. |
e04957365 tty: split the bu... |
147 148 |
* Return NULL if out of memory or the allocation would exceed the * per device queue |
e04957365 tty: split the bu... |
149 |
*/ |
ecbbfd44a TTY: move tty buf... |
150 |
static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) |
e04957365 tty: split the bu... |
151 |
{ |
809850b7a tty: Use lockless... |
152 |
struct llist_node *free; |
e04957365 tty: split the bu... |
153 |
struct tty_buffer *p; |
11b9faa44 tty: Merge tty_bu... |
154 155 156 157 |
/* Round the buffer size out */ size = __ALIGN_MASK(size, TTYB_ALIGN_MASK); if (size <= MIN_TTYB_SIZE) { |
809850b7a tty: Use lockless... |
158 159 160 |
free = llist_del_first(&port->buf.free); if (free) { p = llist_entry(free, struct tty_buffer, free); |
11b9faa44 tty: Merge tty_bu... |
161 162 163 164 165 166 |
goto found; } } /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ |
5dda4ca55 tty: Rename tty b... |
167 |
if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) |
e04957365 tty: split the bu... |
168 169 170 171 |
return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if (p == NULL) return NULL; |
9dd5139f9 tty: Factor flip ... |
172 |
|
11b9faa44 tty: Merge tty_bu... |
173 |
found: |
9dd5139f9 tty: Factor flip ... |
174 |
tty_buffer_reset(p, size); |
5dda4ca55 tty: Rename tty b... |
175 |
atomic_add(size, &port->buf.mem_used); |
e04957365 tty: split the bu... |
176 177 178 179 180 |
return p; } /** * tty_buffer_free - free a tty buffer |
fa4419545 tty: fix kernel-doc |
181 |
* @port: tty port owning the buffer |
e04957365 tty: split the bu... |
182 183 184 185 |
* @b: the buffer to free * * Free a tty buffer, or add it to the free list according to our * internal strategy |
e04957365 tty: split the bu... |
186 |
*/ |
ecbbfd44a TTY: move tty buf... |
187 |
static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) |
e04957365 tty: split the bu... |
188 |
{ |
ecbbfd44a TTY: move tty buf... |
189 |
struct tty_bufhead *buf = &port->buf; |
5cff39c69 TTY: tty_buffer, ... |
190 |
|
e04957365 tty: split the bu... |
191 |
/* Dumb strategy for now - should keep some stats */ |
5dda4ca55 tty: Rename tty b... |
192 |
WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0); |
e04957365 tty: split the bu... |
193 |
|
1cef50e31 tty: Fix flip buf... |
194 |
if (b->size > MIN_TTYB_SIZE) |
e04957365 tty: split the bu... |
195 |
kfree(b); |
7391ee169 tty: Simplify fli... |
196 |
else if (b->size > 0) |
809850b7a tty: Use lockless... |
197 |
llist_add(&b->free, &buf->free); |
e04957365 tty: split the bu... |
198 199 200 |
} /** |
e04957365 tty: split the bu... |
201 202 |
* tty_buffer_flush - flush full tty buffers * @tty: tty to flush |
86c80a8e2 tty: Flush ldisc ... |
203 |
* @ld: optional ldisc ptr (must be referenced) |
e04957365 tty: split the bu... |
204 |
* |
86c80a8e2 tty: Flush ldisc ... |
205 206 |
* flush all the buffers containing receive data. If ld != NULL, * flush the ldisc input buffer. |
e04957365 tty: split the bu... |
207 |
* |
a7c8d58c7 tty: Fix unsafe v... |
208 |
* Locking: takes buffer lock to ensure single-threaded flip buffer |
e9975fdec tty: Ensure singl... |
209 |
* 'consumer' |
e04957365 tty: split the bu... |
210 |
*/ |
86c80a8e2 tty: Flush ldisc ... |
211 |
void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) |
e04957365 tty: split the bu... |
212 |
{ |
2fc20661e TTY: move TTY_FLU... |
213 |
struct tty_port *port = tty->port; |
ecbbfd44a TTY: move tty buf... |
214 |
struct tty_bufhead *buf = &port->buf; |
47aa658a0 tty: Merge __tty_... |
215 |
struct tty_buffer *next; |
e04957365 tty: split the bu... |
216 |
|
a7c8d58c7 tty: Fix unsafe v... |
217 |
atomic_inc(&buf->priority); |
e9975fdec tty: Ensure singl... |
218 |
|
a7c8d58c7 tty: Fix unsafe v... |
219 |
mutex_lock(&buf->lock); |
9e6b7cd7e tty: fix data rac... |
220 221 222 223 |
/* paired w/ release in __tty_buffer_request_room; ensures there are * no pending memory accesses to the freed buffer */ while ((next = smp_load_acquire(&buf->head->next)) != NULL) { |
47aa658a0 tty: Merge __tty_... |
224 225 226 227 |
tty_buffer_free(port, buf->head); buf->head = next; } buf->head->read = buf->head->commit; |
86c80a8e2 tty: Flush ldisc ... |
228 229 230 |
if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); |
a7c8d58c7 tty: Fix unsafe v... |
231 232 |
atomic_dec(&buf->priority); mutex_unlock(&buf->lock); |
e04957365 tty: split the bu... |
233 234 235 |
} /** |
64325a3be tty: Correct tty ... |
236 |
* tty_buffer_request_room - grow tty buffer if needed |
fa4419545 tty: fix kernel-doc |
237 |
* @port: tty port |
e04957365 tty: split the bu... |
238 |
* @size: size desired |
acc0f67f3 tty: Halve flip b... |
239 |
* @flags: buffer flags if new buffer allocated (default = 0) |
e04957365 tty: split the bu... |
240 241 242 |
* * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. |
acc0f67f3 tty: Halve flip b... |
243 244 245 246 |
* * Will change over to a new buffer if the current buffer is encoded as * TTY_NORMAL (so has no flags buffer) and the new buffer requires * a flags buffer. |
e04957365 tty: split the bu... |
247 |
*/ |
acc0f67f3 tty: Halve flip b... |
248 249 |
static int __tty_buffer_request_room(struct tty_port *port, size_t size, int flags) |
e04957365 tty: split the bu... |
250 |
{ |
ecbbfd44a TTY: move tty buf... |
251 |
struct tty_bufhead *buf = &port->buf; |
e04957365 tty: split the bu... |
252 |
struct tty_buffer *b, *n; |
acc0f67f3 tty: Halve flip b... |
253 |
int left, change; |
e8437d7ec tty: Make driver-... |
254 |
|
5cff39c69 TTY: tty_buffer, ... |
255 |
b = buf->tail; |
acc0f67f3 tty: Halve flip b... |
256 257 258 259 |
if (b->flags & TTYB_NORMAL) left = 2 * b->size - b->used; else left = b->size - b->used; |
e04957365 tty: split the bu... |
260 |
|
acc0f67f3 tty: Halve flip b... |
261 262 |
change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); if (change || left < size) { |
e04957365 tty: split the bu... |
263 |
/* This is the slow path - looking for new buffers to use */ |
e16cb0a72 tty: tty_buffer.c... |
264 265 |
n = tty_buffer_alloc(port, size); if (n != NULL) { |
acc0f67f3 tty: Halve flip b... |
266 |
n->flags = flags; |
5cff39c69 TTY: tty_buffer, ... |
267 |
buf->tail = n; |
facd885c7 tty: fix data rac... |
268 269 270 271 |
/* paired w/ acquire in flush_to_ldisc(); ensures * flush_to_ldisc() sees buffer data. */ smp_store_release(&b->commit, b->used); |
069f38b49 tty: Replace smp_... |
272 |
/* paired w/ acquire in flush_to_ldisc(); ensures the |
62a0d8d7c tty: Fix lockless... |
273 274 275 |
* latest commit value can be read before the head is * advanced to the next buffer */ |
069f38b49 tty: Replace smp_... |
276 |
smp_store_release(&b->next, n); |
acc0f67f3 tty: Halve flip b... |
277 278 279 |
} else if (change) size = 0; else |
e04957365 tty: split the bu... |
280 281 |
size = left; } |
e04957365 tty: split the bu... |
282 283 |
return size; } |
acc0f67f3 tty: Halve flip b... |
284 285 286 287 288 |
int tty_buffer_request_room(struct tty_port *port, size_t size) { return __tty_buffer_request_room(port, size, 0); } |
e04957365 tty: split the bu... |
289 290 291 |
EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** |
2832fc11f USB: tty: Add a f... |
292 |
* tty_insert_flip_string_fixed_flag - Add characters to the tty buffer |
2f6933571 TTY: convert more... |
293 |
* @port: tty port |
e04957365 tty: split the bu... |
294 |
* @chars: characters |
2832fc11f USB: tty: Add a f... |
295 |
* @flag: flag value for each character |
e04957365 tty: split the bu... |
296 297 298 |
* @size: size * * Queue a series of bytes to the tty buffering. All the characters |
ccc5ca8d4 tty: fix obsolete... |
299 |
* passed are marked with the supplied flag. Returns the number added. |
e04957365 tty: split the bu... |
300 |
*/ |
2f6933571 TTY: convert more... |
301 |
int tty_insert_flip_string_fixed_flag(struct tty_port *port, |
2832fc11f USB: tty: Add a f... |
302 |
const unsigned char *chars, char flag, size_t size) |
e04957365 tty: split the bu... |
303 304 305 |
{ int copied = 0; do { |
d4bee0a67 tty_buffer: Fix d... |
306 |
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
acc0f67f3 tty: Halve flip b... |
307 308 |
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; int space = __tty_buffer_request_room(port, goal, flags); |
64325a3be tty: Correct tty ... |
309 |
struct tty_buffer *tb = port->buf.tail; |
7391ee169 tty: Simplify fli... |
310 |
if (unlikely(space == 0)) |
e04957365 tty: split the bu... |
311 |
break; |
1fc359fc3 tty: Compute flip... |
312 |
memcpy(char_buf_ptr(tb, tb->used), chars, space); |
acc0f67f3 tty: Halve flip b... |
313 314 |
if (~tb->flags & TTYB_NORMAL) memset(flag_buf_ptr(tb, tb->used), flag, space); |
e04957365 tty: split the bu... |
315 316 317 318 319 320 321 322 |
tb->used += space; copied += space; chars += space; /* There is a small chance that we need to split the data over several buffers. If this is the case we must loop */ } while (unlikely(size > copied)); return copied; } |
2832fc11f USB: tty: Add a f... |
323 |
EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); |
e04957365 tty: split the bu... |
324 325 326 |
/** * tty_insert_flip_string_flags - Add characters to the tty buffer |
2f6933571 TTY: convert more... |
327 |
* @port: tty port |
e04957365 tty: split the bu... |
328 329 330 331 332 333 334 |
* @chars: characters * @flags: flag bytes * @size: size * * Queue a series of bytes to the tty buffering. For each character * the flags array indicates the status of the character. Returns the * number added. |
e04957365 tty: split the bu... |
335 |
*/ |
2f6933571 TTY: convert more... |
336 |
int tty_insert_flip_string_flags(struct tty_port *port, |
e04957365 tty: split the bu... |
337 338 339 340 |
const unsigned char *chars, const char *flags, size_t size) { int copied = 0; do { |
d4bee0a67 tty_buffer: Fix d... |
341 |
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); |
64325a3be tty: Correct tty ... |
342 343 |
int space = tty_buffer_request_room(port, goal); struct tty_buffer *tb = port->buf.tail; |
7391ee169 tty: Simplify fli... |
344 |
if (unlikely(space == 0)) |
e04957365 tty: split the bu... |
345 |
break; |
1fc359fc3 tty: Compute flip... |
346 347 |
memcpy(char_buf_ptr(tb, tb->used), chars, space); memcpy(flag_buf_ptr(tb, tb->used), flags, space); |
e04957365 tty: split the bu... |
348 349 350 351 352 353 354 355 356 357 358 359 |
tb->used += space; copied += space; chars += space; flags += space; /* There is a small chance that we need to split the data over several buffers. If this is the case we must loop */ } while (unlikely(size > copied)); return copied; } EXPORT_SYMBOL(tty_insert_flip_string_flags); /** |
979990c62 tty: improve tty_... |
360 361 362 363 364 365 366 367 368 369 |
* __tty_insert_flip_char - Add one character to the tty buffer * @port: tty port * @ch: character * @flag: flag byte * * Queue a single byte to the tty buffering, with an optional flag. * This is the slow path of tty_insert_flip_char. */ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) { |
8a5a90a2a tty: fix __tty_in... |
370 |
struct tty_buffer *tb; |
979990c62 tty: improve tty_... |
371 |
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; |
065ea0a7a tty: improve tty_... |
372 |
if (!__tty_buffer_request_room(port, 1, flags)) |
979990c62 tty: improve tty_... |
373 |
return 0; |
8a5a90a2a tty: fix __tty_in... |
374 |
tb = port->buf.tail; |
065ea0a7a tty: improve tty_... |
375 376 |
if (~tb->flags & TTYB_NORMAL) *flag_buf_ptr(tb, tb->used) = flag; |
979990c62 tty: improve tty_... |
377 378 379 380 381 382 383 |
*char_buf_ptr(tb, tb->used++) = ch; return 1; } EXPORT_SYMBOL(__tty_insert_flip_char); /** |
e04957365 tty: split the bu... |
384 |
* tty_schedule_flip - push characters to ldisc |
6732c8bb8 TTY: switch tty_s... |
385 |
* @port: tty port to push from |
e04957365 tty: split the bu... |
386 387 388 389 |
* * Takes any pending buffers and transfers their ownership to the * ldisc side of the queue. It then schedules those characters for * processing by the line discipline. |
e04957365 tty: split the bu... |
390 |
*/ |
6732c8bb8 TTY: switch tty_s... |
391 |
void tty_schedule_flip(struct tty_port *port) |
e04957365 tty: split the bu... |
392 |
{ |
6732c8bb8 TTY: switch tty_s... |
393 |
struct tty_bufhead *buf = &port->buf; |
5cff39c69 TTY: tty_buffer, ... |
394 |
|
facd885c7 tty: fix data rac... |
395 396 397 398 |
/* paired w/ acquire in flush_to_ldisc(); ensures * flush_to_ldisc() sees buffer data. */ smp_store_release(&buf->tail->commit, buf->tail->used); |
e052c6d15 tty: Use unbound ... |
399 |
queue_work(system_unbound_wq, &buf->work); |
e04957365 tty: split the bu... |
400 401 402 403 404 |
} EXPORT_SYMBOL(tty_schedule_flip); /** * tty_prepare_flip_string - make room for characters |
2f6933571 TTY: convert more... |
405 |
* @port: tty port |
e04957365 tty: split the bu... |
406 407 408 409 410 411 412 413 |
* @chars: return pointer for character write area * @size: desired size * * Prepare a block of space in the buffer for data. Returns the length * available and buffer pointer to the space which is now allocated and * accounted for as ready for normal characters. This is used for drivers * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! |
e04957365 tty: split the bu... |
414 |
*/ |
2f6933571 TTY: convert more... |
415 |
int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, |
ecbbfd44a TTY: move tty buf... |
416 |
size_t size) |
e04957365 tty: split the bu... |
417 |
{ |
acc0f67f3 tty: Halve flip b... |
418 |
int space = __tty_buffer_request_room(port, size, TTYB_NORMAL); |
e04957365 tty: split the bu... |
419 |
if (likely(space)) { |
64325a3be tty: Correct tty ... |
420 |
struct tty_buffer *tb = port->buf.tail; |
1fc359fc3 tty: Compute flip... |
421 |
*chars = char_buf_ptr(tb, tb->used); |
acc0f67f3 tty: Halve flip b... |
422 423 |
if (~tb->flags & TTYB_NORMAL) memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); |
e04957365 tty: split the bu... |
424 425 426 427 428 |
tb->used += space; } return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); |
8d082cd30 tty: Unify receiv... |
429 430 431 432 433 434 435 436 437 438 |
/** * tty_ldisc_receive_buf - forward data to line discipline * @ld: line discipline to process input * @p: char buffer * @f: TTY_* flags buffer * @count: number of bytes to process * * Callers other than flush_to_ldisc() need to exclude the kworker * from concurrent use of the line discipline, see paste_selection(). * |
e7e51dcf3 tty: fix tty_ldis... |
439 |
* Returns the number of bytes processed |
8d082cd30 tty: Unify receiv... |
440 |
*/ |
c92d781f1 tty: constify tty... |
441 |
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, |
8d082cd30 tty: Unify receiv... |
442 443 444 445 446 447 448 449 450 451 452 453 |
char *f, int count) { if (ld->ops->receive_buf2) count = ld->ops->receive_buf2(ld->tty, p, f, count); else { count = min_t(int, count, ld->tty->receive_room); if (count && ld->ops->receive_buf) ld->ops->receive_buf(ld->tty, p, f, count); } return count; } EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); |
e04957365 tty: split the bu... |
454 |
|
da261e7fe tty: Simplify tty... |
455 |
static int |
c3485ee0d tty_port: Add por... |
456 |
receive_buf(struct tty_port *port, struct tty_buffer *head, int count) |
da261e7fe tty: Simplify tty... |
457 |
{ |
1fc359fc3 tty: Compute flip... |
458 |
unsigned char *p = char_buf_ptr(head, head->read); |
acc0f67f3 tty: Halve flip b... |
459 |
char *f = NULL; |
c9a8e5fce tty: wipe buffer. |
460 |
int n; |
acc0f67f3 tty: Halve flip b... |
461 462 463 |
if (~head->flags & TTYB_NORMAL) f = flag_buf_ptr(head, head->read); |
da261e7fe tty: Simplify tty... |
464 |
|
c9a8e5fce tty: wipe buffer. |
465 466 467 468 |
n = port->client_ops->receive_buf(port, p, f, count); if (n > 0) memset(p, 0, n); return n; |
da261e7fe tty: Simplify tty... |
469 |
} |
e04957365 tty: split the bu... |
470 471 472 473 474 475 476 477 |
/** * flush_to_ldisc * @work: tty structure passed from work queue. * * This routine is called out of the software interrupt to flush data * from the buffer chain to the line discipline. * |
e9975fdec tty: Ensure singl... |
478 479 |
* The receive_buf method is single threaded for each tty instance. * |
a7c8d58c7 tty: Fix unsafe v... |
480 |
* Locking: takes buffer lock to ensure single-threaded flip buffer |
e9975fdec tty: Ensure singl... |
481 |
* 'consumer' |
e04957365 tty: split the bu... |
482 483 484 485 |
*/ static void flush_to_ldisc(struct work_struct *work) { |
ecbbfd44a TTY: move tty buf... |
486 487 |
struct tty_port *port = container_of(work, struct tty_port, buf.work); struct tty_bufhead *buf = &port->buf; |
e04957365 tty: split the bu... |
488 |
|
a7c8d58c7 tty: Fix unsafe v... |
489 |
mutex_lock(&buf->lock); |
45242006e Make flush_to_ldi... |
490 |
|
d7a68be4f tty: Only perform... |
491 492 |
while (1) { struct tty_buffer *head = buf->head; |
62a0d8d7c tty: Fix lockless... |
493 |
struct tty_buffer *next; |
d7a68be4f tty: Only perform... |
494 |
int count; |
a7c8d58c7 tty: Fix unsafe v... |
495 496 |
/* Ldisc or user is trying to gain exclusive access */ if (atomic_read(&buf->priority)) |
d7a68be4f tty: Only perform... |
497 |
break; |
069f38b49 tty: Replace smp_... |
498 |
/* paired w/ release in __tty_buffer_request_room(); |
62a0d8d7c tty: Fix lockless... |
499 500 501 |
* ensures commit value read is not stale if the head * is advancing to the next buffer */ |
069f38b49 tty: Replace smp_... |
502 |
next = smp_load_acquire(&head->next); |
facd885c7 tty: fix data rac... |
503 504 505 506 |
/* paired w/ release in __tty_buffer_request_room() or in * tty_buffer_flush(); ensures we see the committed buffer data */ count = smp_load_acquire(&head->commit) - head->read; |
d7a68be4f tty: Only perform... |
507 |
if (!count) { |
0f40fbbcc Fix OpenSSH pty r... |
508 |
if (next == NULL) |
da261e7fe tty: Simplify tty... |
509 |
break; |
62a0d8d7c tty: Fix lockless... |
510 |
buf->head = next; |
d7a68be4f tty: Only perform... |
511 512 |
tty_buffer_free(port, head); continue; |
e04957365 tty: split the bu... |
513 |
} |
d7a68be4f tty: Only perform... |
514 |
|
c3485ee0d tty_port: Add por... |
515 |
count = receive_buf(port, head, count); |
d7a68be4f tty: Only perform... |
516 517 |
if (!count) break; |
af5554f95 tty: buffers: Mov... |
518 |
head->read += count; |
e04957365 tty: split the bu... |
519 |
} |
45242006e Make flush_to_ldi... |
520 |
|
a7c8d58c7 tty: Fix unsafe v... |
521 |
mutex_unlock(&buf->lock); |
e04957365 tty: split the bu... |
522 |
|
e04957365 tty: split the bu... |
523 524 525 526 |
} /** * tty_flip_buffer_push - terminal |
2e124b4a3 TTY: switch tty_f... |
527 |
* @port: tty port to push |
e04957365 tty: split the bu... |
528 |
* |
a9c3f68f3 tty: Fix low_late... |
529 530 |
* Queue a push of the terminal flip buffers to the line discipline. * Can be called from IRQ/atomic context. |
e04957365 tty: split the bu... |
531 532 533 |
* * In the event of the queue being busy for flipping the work will be * held off and retried later. |
e04957365 tty: split the bu... |
534 |
*/ |
2e124b4a3 TTY: switch tty_f... |
535 |
void tty_flip_buffer_push(struct tty_port *port) |
e04957365 tty: split the bu... |
536 |
{ |
a9c3f68f3 tty: Fix low_late... |
537 |
tty_schedule_flip(port); |
e04957365 tty: split the bu... |
538 539 540 541 542 |
} EXPORT_SYMBOL(tty_flip_buffer_push); /** * tty_buffer_init - prepare a tty buffer structure |
fa4419545 tty: fix kernel-doc |
543 |
* @port: tty port to initialise |
e04957365 tty: split the bu... |
544 545 546 |
* * Set up the initial state of the buffer management for a tty device. * Must be called before the other tty buffer functions are used. |
e04957365 tty: split the bu... |
547 |
*/ |
ecbbfd44a TTY: move tty buf... |
548 |
void tty_buffer_init(struct tty_port *port) |
e04957365 tty: split the bu... |
549 |
{ |
ecbbfd44a TTY: move tty buf... |
550 |
struct tty_bufhead *buf = &port->buf; |
5cff39c69 TTY: tty_buffer, ... |
551 |
|
a7c8d58c7 tty: Fix unsafe v... |
552 |
mutex_init(&buf->lock); |
7391ee169 tty: Simplify fli... |
553 554 555 |
tty_buffer_reset(&buf->sentinel, 0); buf->head = &buf->sentinel; buf->tail = &buf->sentinel; |
809850b7a tty: Use lockless... |
556 |
init_llist_head(&buf->free); |
5dda4ca55 tty: Rename tty b... |
557 |
atomic_set(&buf->mem_used, 0); |
a7c8d58c7 tty: Fix unsafe v... |
558 |
atomic_set(&buf->priority, 0); |
5cff39c69 TTY: tty_buffer, ... |
559 |
INIT_WORK(&buf->work, flush_to_ldisc); |
4d18e6eff tty: Enable confi... |
560 |
buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; |
e04957365 tty: split the bu... |
561 |
} |
4d18e6eff tty: Enable confi... |
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
/** * tty_buffer_set_limit - change the tty buffer memory limit * @port: tty port to change * * Change the tty buffer memory limit. * Must be called before the other tty buffer functions are used. */ int tty_buffer_set_limit(struct tty_port *port, int limit) { if (limit < MIN_TTYB_SIZE) return -EINVAL; port->buf.mem_limit = limit; return 0; } EXPORT_SYMBOL_GPL(tty_buffer_set_limit); |
1d1d14da1 pty: Fix buffer f... |
579 580 581 582 583 584 |
/* slave ptys can claim nested buffer lock when handling BRK and INTR */ void tty_buffer_set_lock_subclass(struct tty_port *port) { lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); } |
e176058f0 tty: Abstract tty... |
585 586 587 588 589 590 591 592 593 594 |
bool tty_buffer_restart_work(struct tty_port *port) { return queue_work(system_unbound_wq, &port->buf.work); } bool tty_buffer_cancel_work(struct tty_port *port) { return cancel_work_sync(&port->buf.work); } |
0f40fbbcc Fix OpenSSH pty r... |
595 596 597 598 599 |
void tty_buffer_flush_work(struct tty_port *port) { flush_work(&port->buf.work); } |