您的位置:首页 > 大数据 > 人工智能

tty write return EAGAIN

2013-11-12 13:51 316 查看
/**************************************************************/

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐