tty write return EAGAIN

/**************************************************************/

EAGAIN是从哪里返回的?

仔细debug一下,看系统函数哪里返回了这个值?应用程序的error number肯定是系统调用的返回值。

fs/read_write.c


SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
        size_t, count)
{
    struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_write(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }
    if(ret == -11)
        pr_err("write again!!!!");
    return ret;
}

ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
    ssize_t ret;

    if (!(file->f_mode & FMODE_WRITE))
        return -EBADF;
    if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
        return -EINVAL;
    if (unlikely(!access_ok(VERIFY_READ, buf, count)))
        return -EFAULT;

    ret = rw_verify_area(WRITE, file, pos, count);
    if (ret >= 0) {
        count = ret;
        if (file->f_op->write){
            ret = file->f_op->write(file, buf, count, pos);
            if(ret == -11)
                pr_err("vfs_write: ret -11, func 0x%x\n", file->f_op->write);
        }
        else
            ret = do_sync_write(file, buf, count, pos);
        if (ret > 0) {
            fsnotify_modify(file);
            add_wchar(current, ret);
        }
        inc_syscw(current);
    }

    return ret;
}

drivers/tty/tty_io.c

cdev_init(&tty_cdev, &tty_fops);
static const struct file_operations tty_fops = {
    .llseek        = no_llseek,
    .read        = tty_read,
    .write        = tty_write,
    .poll        = tty_poll,
    .unlocked_ioctl    = tty_ioctl,
    .compat_ioctl    = tty_compat_ioctl,
    .open        = tty_open,
    .release    = tty_release,
    .fasync        = tty_fasync,
};

static ssize_t tty_write(struct file *file, const char __user *buf,
                        size_t count, loff_t *ppos)
{
    struct inode *inode = file->f_path.dentry->d_inode;
    struct tty_struct *tty = file_tty(file);
     struct tty_ldisc *ld;
    ssize_t ret;
    
    if (tty_paranoia_check(tty, inode, "tty_write"))
        return -EIO;
    if (!tty || !tty->ops->write ||
        (test_bit(TTY_IO_ERROR, &tty->flags)))
            return -EIO;
    /* Short term debug to catch buggy drivers */
    if (tty->ops->write_room == NULL)
        printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
            tty->driver->name);
    ld = tty_ldisc_ref_wait(tty);
    if (!ld->ops->write)
        ret = -EIO;
    else
        ret = do_tty_write(ld->ops->write, tty, file, buf, count);
    tty_ldisc_deref(ld);

    if(strcmp(tty->name, "ttyGS1")==0)
        pr_err("tty_write: ttyGS1:exit %d\n", ret);
    
    return ret;
}


static inline ssize_t do_tty_write(
    ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
    struct tty_struct *tty,
    struct file *file,
    const char __user *buf,
    size_t count)
{
    ssize_t ret, written = 0;
    unsigned int chunk;

    ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
    if (ret < 0)
        return ret;

    /*
     * We chunk up writes into a temporary buffer. This
     * simplifies low-level drivers immensely, since they
     * don't have locking issues and user mode accesses.
     *
     * But if TTY_NO_WRITE_SPLIT is set, we should use a
     * big chunk-size..
     *
     * The default chunk-size is 2kB, because the NTTY
     * layer has problems with bigger chunks. It will
     * claim to be able to handle more characters than
     * it actually does.
     *
     * FIXME: This can probably go away now except that 64K chunks
     * are too likely to fail unless switched to vmalloc...
     */
    chunk = 2048;
    if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
        chunk = 65536;
    if (count < chunk)
        chunk = count;

    /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
    if (tty->write_cnt < chunk) {
        unsigned char *buf_chunk;

        if (chunk < 1024)
            chunk = 1024;

        buf_chunk = kmalloc(chunk, GFP_KERNEL);
        if (!buf_chunk) {
            ret = -ENOMEM;
            goto out;
        }
        kfree(tty->write_buf);
        tty->write_cnt = chunk;
        tty->write_buf = buf_chunk;
    }

    /* Do the write .. */
    for (;;) {
        size_t size = count;
        if (size > chunk)
            size = chunk;
        ret = -EFAULT;
        if (copy_from_user(tty->write_buf, buf, size))
            break;
        ret = write(tty, file, tty->write_buf, size);
        if (ret <= 0)
            break;
        written += ret;
        buf += ret;
        count -= ret;
        if (!count)
            break;
        ret = -ERESTARTSYS;
        if (signal_pending(current))
            break;
        cond_resched();
    }
    if (written) {
        struct inode *inode = file->f_path.dentry->d_inode;
        inode->i_mtime = current_fs_time(inode->i_sb);
        ret = written;
    }
out:
    tty_write_unlock(tty);
    return ret;
}

drivers/tty/n_tty.c

static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
               const unsigned char *buf, size_t nr)
{
    const unsigned char *b = buf;
    DECLARE_WAITQUEUE(wait, current);
    int c;
    ssize_t retval = 0;

    /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
    if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
        retval = tty_check_change(tty);
        if (retval)
            return retval;
    }

    /* Write out any echoed characters that are still pending */
    process_echoes(tty);

    add_wait_queue(&tty->write_wait, &wait);
    while (1) {
        set_current_state(TASK_INTERRUPTIBLE);
        if (signal_pending(current)) {
            retval = -ERESTARTSYS;
            break;
        }
        if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
            retval = -EIO;
            break;
        }
        if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
            if(strcmp(tty->name, "ttyGS1")==0)
                pr_err("n_tty_write: ttyGS1\n");
            while (nr > 0) {
                ssize_t num = process_output_block(tty, b, nr);
                if (num < 0) {
                    if (num == -EAGAIN)
                        break;
                    retval = num;
                    goto break_out;
                }
                b += num;
                nr -= num;
                if (nr == 0)
                    break;
                c = *b;
                if (process_output(c, tty) < 0)
                    break;
                b++; nr--;
            }
            if (tty->ops->flush_chars)
                tty->ops->flush_chars(tty);
        } else {
            if(strcmp(tty->name, "ttyGS1")==0)
                pr_err("n_tty_write: ttyGS1 else\n");
            while (nr > 0) {
                c = tty->ops->write(tty, b, nr);
                if (c < 0) {
                    retval = c;
                    goto break_out;
                }
                if (!c)
                    break;
                b += c;
                nr -= c;
            }
        }
        if (!nr)
            break;
        if (file->f_flags & O_NONBLOCK) {
            if(strcmp(tty->name, "ttyGS1")==0)
                pr_err("n_tty_write: O_NONBLOCK, EAGAIN\n");
            retval = -EAGAIN;
            break;
        }
        schedule();
    }
break_out:
    __set_current_state(TASK_RUNNING);
    remove_wait_queue(&tty->write_wait, &wait);
    if (b - buf != nr && tty->fasync)
        set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
    return (b - buf) ? b - buf : retval;
}

drivers/usb/gadget/u_serial.c

static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
    struct gs_port    *port = tty->driver_data;
    unsigned long    flags;
    int        status;
    if(strcmp(tty->name, "ttyGS1")==0)
        pr_err("gs_write: Enter: ttyGS%d (%p) writing %d bytes\n",
            port->port_num, tty, count);

    pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
            port->port_num, tty, count);

    spin_lock_irqsave(&port->port_lock, flags);
    if (count)
        count = gs_buf_put(&port->port_write_buf, buf, count);
    /* treat count == 0 as flush_chars() */
    if (port->port_usb)
        status = gs_start_tx(port);
    spin_unlock_irqrestore(&port->port_lock, flags);
    if(strcmp(tty->name, "ttyGS1")==0)
        pr_err("gs_write: Exit: ttyGS%d (%p) writed %d bytes\n",
            port->port_num, tty, count);

    return count;
}
调用分好几层,最后才是 tty->operation,每个层都要看到,肯定能找到 retval = -EAGAIN
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值