Skip to content

Commit 9bb48c8

Browse files
committed
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 36e2c74 ("fs: don't allow splice read/write without explicit ops"). Fixes: 36e2c74 ("fs: don't allow splice read/write without explicit ops") Reported-by: Oliver Giles <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Al Viro <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2c85ebc commit 9bb48c8

File tree

1 file changed

+26
-22
lines changed

1 file changed

+26
-22
lines changed

drivers/tty/tty_io.c

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,8 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
143143
DEFINE_MUTEX(tty_mutex);
144144

145145
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 *);
149148
static __poll_t tty_poll(struct file *, poll_table *);
150149
static int tty_open(struct inode *, struct file *);
151150
long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
@@ -478,7 +477,8 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file)
478477
static const struct file_operations tty_fops = {
479478
.llseek = no_llseek,
480479
.read = tty_read,
481-
.write = tty_write,
480+
.write_iter = tty_write,
481+
.splice_write = iter_file_splice_write,
482482
.poll = tty_poll,
483483
.unlocked_ioctl = tty_ioctl,
484484
.compat_ioctl = tty_compat_ioctl,
@@ -491,7 +491,8 @@ static const struct file_operations tty_fops = {
491491
static const struct file_operations console_fops = {
492492
.llseek = no_llseek,
493493
.read = tty_read,
494-
.write = redirected_tty_write,
494+
.write_iter = redirected_tty_write,
495+
.splice_write = iter_file_splice_write,
495496
.poll = tty_poll,
496497
.unlocked_ioctl = tty_ioctl,
497498
.compat_ioctl = tty_compat_ioctl,
@@ -607,9 +608,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
607608
/* This breaks for file handles being sent over AF_UNIX sockets ? */
608609
list_for_each_entry(priv, &tty->tty_files, list) {
609610
filp = priv->file;
610-
if (filp->f_op->write == redirected_tty_write)
611+
if (filp->f_op->write_iter == redirected_tty_write)
611612
cons_filp = filp;
612-
if (filp->f_op->write != tty_write)
613+
if (filp->f_op->write_iter != tty_write)
613614
continue;
614615
closecount++;
615616
__tty_fasync(-1, filp, 0); /* can't block */
@@ -902,9 +903,9 @@ static inline ssize_t do_tty_write(
902903
ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
903904
struct tty_struct *tty,
904905
struct file *file,
905-
const char __user *buf,
906-
size_t count)
906+
struct iov_iter *from)
907907
{
908+
size_t count = iov_iter_count(from);
908909
ssize_t ret, written = 0;
909910
unsigned int chunk;
910911

@@ -956,14 +957,20 @@ static inline ssize_t do_tty_write(
956957
size_t size = count;
957958
if (size > chunk)
958959
size = chunk;
960+
959961
ret = -EFAULT;
960-
if (copy_from_user(tty->write_buf, buf, size))
962+
if (copy_from_iter(tty->write_buf, size, from) != size)
961963
break;
964+
962965
ret = write(tty, file, tty->write_buf, size);
963966
if (ret <= 0)
964967
break;
968+
969+
/* FIXME! Have Al check this! */
970+
if (ret != size)
971+
iov_iter_revert(from, size-ret);
972+
965973
written += ret;
966-
buf += ret;
967974
count -= ret;
968975
if (!count)
969976
break;
@@ -1023,9 +1030,9 @@ void tty_write_message(struct tty_struct *tty, char *msg)
10231030
* write method will not be invoked in parallel for each device.
10241031
*/
10251032

1026-
static ssize_t tty_write(struct file *file, const char __user *buf,
1027-
size_t count, loff_t *ppos)
1033+
static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)
10281034
{
1035+
struct file *file = iocb->ki_filp;
10291036
struct tty_struct *tty = file_tty(file);
10301037
struct tty_ldisc *ld;
10311038
ssize_t ret;
@@ -1038,18 +1045,15 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
10381045
if (tty->ops->write_room == NULL)
10391046
tty_err(tty, "missing write_room method\n");
10401047
ld = tty_ldisc_ref_wait(tty);
1041-
if (!ld)
1042-
return hung_up_tty_write(file, buf, count, ppos);
1043-
if (!ld->ops->write)
1048+
if (!ld || !ld->ops->write)
10441049
ret = -EIO;
10451050
else
1046-
ret = do_tty_write(ld->ops->write, tty, file, buf, count);
1051+
ret = do_tty_write(ld->ops->write, tty, file, from);
10471052
tty_ldisc_deref(ld);
10481053
return ret;
10491054
}
10501055

1051-
ssize_t redirected_tty_write(struct file *file, const char __user *buf,
1052-
size_t count, loff_t *ppos)
1056+
ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
10531057
{
10541058
struct file *p = NULL;
10551059

@@ -1060,11 +1064,11 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
10601064

10611065
if (p) {
10621066
ssize_t res;
1063-
res = vfs_write(p, buf, count, &p->f_pos);
1067+
res = vfs_iocb_iter_write(p, iocb, iter);
10641068
fput(p);
10651069
return res;
10661070
}
1067-
return tty_write(file, buf, count, ppos);
1071+
return tty_write(iocb, iter);
10681072
}
10691073

10701074
/**
@@ -2293,7 +2297,7 @@ static int tioccons(struct file *file)
22932297
{
22942298
if (!capable(CAP_SYS_ADMIN))
22952299
return -EPERM;
2296-
if (file->f_op->write == redirected_tty_write) {
2300+
if (file->f_op->write_iter == redirected_tty_write) {
22972301
struct file *f;
22982302
spin_lock(&redirect_lock);
22992303
f = redirect;

0 commit comments

Comments
 (0)