/* n_tty_read()/consumer path: caller holds non-exclusive termios_rwsem read_tail published  */
static int copy_from_read_buf(struct tty_struct *tty, char *b, size_t nr)
/* n_tty_read()/consumer path: caller holds non-exclusive termios_rwsem read_tail published  */
static int copy_from_read_buf(struct tty_struct *tty, char *b, size_t nr)
{
    struct n_tty_data *ldata = tty->disc_data;
    size_t n = 0;
    rt_bool_t is_eof = 0;
    size_t head = ldata->commit_head;
    size_t tail = ldata->read_tail & (RT_TTY_BUF - 1);
    n = min(head - ldata->read_tail, RT_TTY_BUF - tail);
    n = min(nr, n);
    if (n)
    {
        const char *from = read_buf_addr(ldata, tail);
        memcpy(b, from, n);
        is_eof = n == 1 && *from == EOF_CHAR(tty);
        ldata->read_tail += n;
        if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
            (head == ldata->read_tail))
        {
            n = 0;
        }
    }
    return n;
}