Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: implement write_iter

This makes the tty layer use the .write_iter() function instead of the
traditional .write() functionality.

That allows writev(), but more importantly also makes it possible to
enable .splice_write() for ttys, reinstating the "splice to tty"
functionality that was lost in commit 36e2c7421f02 ("fs: don't allow
splice read/write without explicit ops").

Fixes: 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops")
Reported-by: Oliver Giles <ohw.giles@gmail.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+26 -22
+26 -22
drivers/tty/tty_io.c
··· 143 143 DEFINE_MUTEX(tty_mutex); 144 144 145 145 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); 146 - static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); 147 - ssize_t redirected_tty_write(struct file *, const char __user *, 148 - size_t, loff_t *); 146 + static ssize_t tty_write(struct kiocb *, struct iov_iter *); 147 + ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *); 149 148 static __poll_t tty_poll(struct file *, poll_table *); 150 149 static int tty_open(struct inode *, struct file *); 151 150 long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ··· 477 478 static const struct file_operations tty_fops = { 478 479 .llseek = no_llseek, 479 480 .read = tty_read, 480 - .write = tty_write, 481 + .write_iter = tty_write, 482 + .splice_write = iter_file_splice_write, 481 483 .poll = tty_poll, 482 484 .unlocked_ioctl = tty_ioctl, 483 485 .compat_ioctl = tty_compat_ioctl, ··· 491 491 static const struct file_operations console_fops = { 492 492 .llseek = no_llseek, 493 493 .read = tty_read, 494 - .write = redirected_tty_write, 494 + .write_iter = redirected_tty_write, 495 + .splice_write = iter_file_splice_write, 495 496 .poll = tty_poll, 496 497 .unlocked_ioctl = tty_ioctl, 497 498 .compat_ioctl = tty_compat_ioctl, ··· 608 607 /* This breaks for file handles being sent over AF_UNIX sockets ? */ 609 608 list_for_each_entry(priv, &tty->tty_files, list) { 610 609 filp = priv->file; 611 - if (filp->f_op->write == redirected_tty_write) 610 + if (filp->f_op->write_iter == redirected_tty_write) 612 611 cons_filp = filp; 613 - if (filp->f_op->write != tty_write) 612 + if (filp->f_op->write_iter != tty_write) 614 613 continue; 615 614 closecount++; 616 615 __tty_fasync(-1, filp, 0); /* can't block */ ··· 903 902 ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t), 904 903 struct tty_struct *tty, 905 904 struct file *file, 906 - const char __user *buf, 907 - size_t count) 905 + struct iov_iter *from) 908 906 { 907 + size_t count = iov_iter_count(from); 909 908 ssize_t ret, written = 0; 910 909 unsigned int chunk; 911 910 ··· 957 956 size_t size = count; 958 957 if (size > chunk) 959 958 size = chunk; 959 + 960 960 ret = -EFAULT; 961 - if (copy_from_user(tty->write_buf, buf, size)) 961 + if (copy_from_iter(tty->write_buf, size, from) != size) 962 962 break; 963 + 963 964 ret = write(tty, file, tty->write_buf, size); 964 965 if (ret <= 0) 965 966 break; 967 + 968 + /* FIXME! Have Al check this! */ 969 + if (ret != size) 970 + iov_iter_revert(from, size-ret); 971 + 966 972 written += ret; 967 - buf += ret; 968 973 count -= ret; 969 974 if (!count) 970 975 break; ··· 1030 1023 * write method will not be invoked in parallel for each device. 1031 1024 */ 1032 1025 1033 - static ssize_t tty_write(struct file *file, const char __user *buf, 1034 - size_t count, loff_t *ppos) 1026 + static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from) 1035 1027 { 1028 + struct file *file = iocb->ki_filp; 1036 1029 struct tty_struct *tty = file_tty(file); 1037 1030 struct tty_ldisc *ld; 1038 1031 ssize_t ret; ··· 1045 1038 if (tty->ops->write_room == NULL) 1046 1039 tty_err(tty, "missing write_room method\n"); 1047 1040 ld = tty_ldisc_ref_wait(tty); 1048 - if (!ld) 1049 - return hung_up_tty_write(file, buf, count, ppos); 1050 - if (!ld->ops->write) 1041 + if (!ld || !ld->ops->write) 1051 1042 ret = -EIO; 1052 1043 else 1053 - ret = do_tty_write(ld->ops->write, tty, file, buf, count); 1044 + ret = do_tty_write(ld->ops->write, tty, file, from); 1054 1045 tty_ldisc_deref(ld); 1055 1046 return ret; 1056 1047 } 1057 1048 1058 - ssize_t redirected_tty_write(struct file *file, const char __user *buf, 1059 - size_t count, loff_t *ppos) 1049 + ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) 1060 1050 { 1061 1051 struct file *p = NULL; 1062 1052 ··· 1064 1060 1065 1061 if (p) { 1066 1062 ssize_t res; 1067 - res = vfs_write(p, buf, count, &p->f_pos); 1063 + res = vfs_iocb_iter_write(p, iocb, iter); 1068 1064 fput(p); 1069 1065 return res; 1070 1066 } 1071 - return tty_write(file, buf, count, ppos); 1067 + return tty_write(iocb, iter); 1072 1068 } 1073 1069 1074 1070 /** ··· 2297 2293 { 2298 2294 if (!capable(CAP_SYS_ADMIN)) 2299 2295 return -EPERM; 2300 - if (file->f_op->write == redirected_tty_write) { 2296 + if (file->f_op->write_iter == redirected_tty_write) { 2301 2297 struct file *f; 2302 2298 spin_lock(&redirect_lock); 2303 2299 f = redirect;