1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
| | Revert the following upstream patch, which dramatically decreased the
performance of shell buffers in Emacs.
From 41c6f6b926d0e712d0321f8a8f6511fea748e814 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 19 Jan 2021 10:49:19 -0800
Subject: tty: implement read_iter
[ Upstream commit dd78b0c483e33225e0e0782b0ed887129b00f956 ]
Now that the ldisc read() function takes kernel pointers, it's fairly
straightforward to make the tty file operations use .read_iter() instead
of .read().
That automatically gives us vread() and friends, and also makes it
possible to do .splice_read() on ttys again.
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/tty_io.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index a50c8a4318228..3f55fe7293f31 100644
--- b/drivers/tty/tty_io.c
+++ a/drivers/tty/tty_io.c
@@ -142,7 +142,7 @@
/* Mutex to protect creating and releasing a tty */
DEFINE_MUTEX(tty_mutex);
-static ssize_t tty_read(struct kiocb *, struct iov_iter *);
+static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t tty_write(struct kiocb *, struct iov_iter *);
static __poll_t tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
@@ -473,9 +473,8 @@
static const struct file_operations tty_fops = {
.llseek = no_llseek,
- .read_iter = tty_read,
+ .read = tty_read,
.write_iter = tty_write,
- .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
@@ -488,9 +487,8 @@
static const struct file_operations console_fops = {
.llseek = no_llseek,
- .read_iter = tty_read,
+ .read = tty_read,
.write_iter = redirected_tty_write,
- .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
@@ -843,17 +841,16 @@
* data or clears the cookie. The cookie may be something that the
* ldisc maintains state for and needs to free.
*/
-static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty,
- struct file *file, struct iov_iter *to)
+static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, struct file *file,
+ char __user *buf, size_t count)
{
int retval = 0;
void *cookie = NULL;
unsigned long offset = 0;
char kernel_buf[64];
- size_t count = iov_iter_count(to);
do {
- int size, copied;
+ int size, uncopied;
size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count;
size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset);
@@ -869,9 +866,10 @@
return size;
}
- copied = copy_to_iter(kernel_buf, size, to);
- offset += copied;
- count -= copied;
+ uncopied = copy_to_user(buf+offset, kernel_buf, size);
+ size -= uncopied;
+ offset += size;
+ count -= size;
/*
* If the user copy failed, we still need to do another ->read()
@@ -879,7 +877,7 @@
*
* But make sure size is zeroed.
*/
- if (unlikely(copied != size)) {
+ if (unlikely(uncopied)) {
count = 0;
retval = -EFAULT;
}
@@ -906,10 +904,10 @@
* read calls may be outstanding in parallel.
*/
-static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to)
+static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
{
int i;
- struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file);
struct tty_struct *tty = file_tty(file);
struct tty_ldisc *ld;
@@ -922,9 +920,11 @@
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_read(file, buf, count, ppos);
i = -EIO;
- if (ld && ld->ops->read)
- i = iterate_tty_read(ld, tty, file, to);
+ if (ld->ops->read)
+ i = iterate_tty_read(ld, tty, file, buf, count);
tty_ldisc_deref(ld);
if (i > 0)
@@ -2943,7 +2943,7 @@
static int this_tty(const void *t, struct file *file, unsigned fd)
{
- if (likely(file->f_op->read_iter != tty_read))
+ if (likely(file->f_op->read != tty_read))
return 0;
return file_tty(file) != t ? 0 : fd + 1;
}
|