LCOV - code coverage report
Current view: top level - tty - tty_buffer.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 70.1 % 254 178
Test Date: 2025-08-26 15:45:50 Functions: 68.0 % 25 17

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

Generated by: LCOV version 2.0-1