.. | .. |
---|
6 | 6 | * initial implementation -- AV, Oct 2001. |
---|
7 | 7 | */ |
---|
8 | 8 | |
---|
| 9 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
| 10 | + |
---|
9 | 11 | #include <linux/cache.h> |
---|
10 | 12 | #include <linux/fs.h> |
---|
11 | 13 | #include <linux/export.h> |
---|
.. | .. |
---|
16 | 18 | #include <linux/mm.h> |
---|
17 | 19 | #include <linux/printk.h> |
---|
18 | 20 | #include <linux/string_helpers.h> |
---|
| 21 | +#include <linux/uio.h> |
---|
19 | 22 | |
---|
20 | 23 | #include <linux/uaccess.h> |
---|
21 | 24 | #include <asm/page.h> |
---|
.. | .. |
---|
71 | 74 | p->file = file; |
---|
72 | 75 | |
---|
73 | 76 | /* |
---|
74 | | - * Wrappers around seq_open(e.g. swaps_open) need to be |
---|
75 | | - * aware of this. If they set f_version themselves, they |
---|
76 | | - * should call seq_open first and then set f_version. |
---|
77 | | - */ |
---|
78 | | - file->f_version = 0; |
---|
79 | | - |
---|
80 | | - /* |
---|
81 | 77 | * seq_files support lseek() and pread(). They do not implement |
---|
82 | 78 | * write() at all, but we clear FMODE_PWRITE here for historical |
---|
83 | 79 | * reasons. |
---|
.. | .. |
---|
97 | 93 | int error = 0; |
---|
98 | 94 | void *p; |
---|
99 | 95 | |
---|
100 | | - m->version = 0; |
---|
101 | 96 | m->index = 0; |
---|
102 | 97 | m->count = m->from = 0; |
---|
103 | 98 | if (!offset) |
---|
.. | .. |
---|
155 | 150 | */ |
---|
156 | 151 | ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) |
---|
157 | 152 | { |
---|
158 | | - struct seq_file *m = file->private_data; |
---|
| 153 | + struct iovec iov = { .iov_base = buf, .iov_len = size}; |
---|
| 154 | + struct kiocb kiocb; |
---|
| 155 | + struct iov_iter iter; |
---|
| 156 | + ssize_t ret; |
---|
| 157 | + |
---|
| 158 | + init_sync_kiocb(&kiocb, file); |
---|
| 159 | + iov_iter_init(&iter, READ, &iov, 1, size); |
---|
| 160 | + |
---|
| 161 | + kiocb.ki_pos = *ppos; |
---|
| 162 | + ret = seq_read_iter(&kiocb, &iter); |
---|
| 163 | + *ppos = kiocb.ki_pos; |
---|
| 164 | + return ret; |
---|
| 165 | +} |
---|
| 166 | +EXPORT_SYMBOL(seq_read); |
---|
| 167 | + |
---|
| 168 | +/* |
---|
| 169 | + * Ready-made ->f_op->read_iter() |
---|
| 170 | + */ |
---|
| 171 | +ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
---|
| 172 | +{ |
---|
| 173 | + struct seq_file *m = iocb->ki_filp->private_data; |
---|
159 | 174 | size_t copied = 0; |
---|
160 | 175 | size_t n; |
---|
161 | 176 | void *p; |
---|
162 | 177 | int err = 0; |
---|
163 | 178 | |
---|
164 | | - mutex_lock(&m->lock); |
---|
| 179 | + if (!iov_iter_count(iter)) |
---|
| 180 | + return 0; |
---|
165 | 181 | |
---|
166 | | - /* |
---|
167 | | - * seq_file->op->..m_start/m_stop/m_next may do special actions |
---|
168 | | - * or optimisations based on the file->f_version, so we want to |
---|
169 | | - * pass the file->f_version to those methods. |
---|
170 | | - * |
---|
171 | | - * seq_file->version is just copy of f_version, and seq_file |
---|
172 | | - * methods can treat it simply as file version. |
---|
173 | | - * It is copied in first and copied out after all operations. |
---|
174 | | - * It is convenient to have it as part of structure to avoid the |
---|
175 | | - * need of passing another argument to all the seq_file methods. |
---|
176 | | - */ |
---|
177 | | - m->version = file->f_version; |
---|
| 182 | + mutex_lock(&m->lock); |
---|
178 | 183 | |
---|
179 | 184 | /* |
---|
180 | 185 | * if request is to read from zero offset, reset iterator to first |
---|
181 | 186 | * record as it might have been already advanced by previous requests |
---|
182 | 187 | */ |
---|
183 | | - if (*ppos == 0) { |
---|
| 188 | + if (iocb->ki_pos == 0) { |
---|
184 | 189 | m->index = 0; |
---|
185 | | - m->version = 0; |
---|
186 | 190 | m->count = 0; |
---|
187 | 191 | } |
---|
188 | 192 | |
---|
189 | | - /* Don't assume *ppos is where we left it */ |
---|
190 | | - if (unlikely(*ppos != m->read_pos)) { |
---|
191 | | - while ((err = traverse(m, *ppos)) == -EAGAIN) |
---|
| 193 | + /* Don't assume ki_pos is where we left it */ |
---|
| 194 | + if (unlikely(iocb->ki_pos != m->read_pos)) { |
---|
| 195 | + while ((err = traverse(m, iocb->ki_pos)) == -EAGAIN) |
---|
192 | 196 | ; |
---|
193 | 197 | if (err) { |
---|
194 | 198 | /* With prejudice... */ |
---|
195 | 199 | m->read_pos = 0; |
---|
196 | | - m->version = 0; |
---|
197 | 200 | m->index = 0; |
---|
198 | 201 | m->count = 0; |
---|
199 | 202 | goto Done; |
---|
200 | 203 | } else { |
---|
201 | | - m->read_pos = *ppos; |
---|
| 204 | + m->read_pos = iocb->ki_pos; |
---|
202 | 205 | } |
---|
203 | 206 | } |
---|
204 | 207 | |
---|
.. | .. |
---|
208 | 211 | if (!m->buf) |
---|
209 | 212 | goto Enomem; |
---|
210 | 213 | } |
---|
211 | | - /* if not empty - flush it first */ |
---|
| 214 | + // something left in the buffer - copy it out first |
---|
212 | 215 | if (m->count) { |
---|
213 | | - n = min(m->count, size); |
---|
214 | | - err = copy_to_user(buf, m->buf + m->from, n); |
---|
215 | | - if (err) |
---|
216 | | - goto Efault; |
---|
| 216 | + n = copy_to_iter(m->buf + m->from, m->count, iter); |
---|
217 | 217 | m->count -= n; |
---|
218 | 218 | m->from += n; |
---|
219 | | - size -= n; |
---|
220 | | - buf += n; |
---|
221 | 219 | copied += n; |
---|
222 | | - if (!size) |
---|
| 220 | + if (m->count) // hadn't managed to copy everything |
---|
223 | 221 | goto Done; |
---|
224 | 222 | } |
---|
225 | | - /* we need at least one record in buffer */ |
---|
| 223 | + // get a non-empty record in the buffer |
---|
226 | 224 | m->from = 0; |
---|
227 | 225 | p = m->op->start(m, &m->index); |
---|
228 | 226 | while (1) { |
---|
229 | 227 | err = PTR_ERR(p); |
---|
230 | | - if (!p || IS_ERR(p)) |
---|
| 228 | + if (!p || IS_ERR(p)) // EOF or an error |
---|
231 | 229 | break; |
---|
232 | 230 | err = m->op->show(m, p); |
---|
233 | | - if (err < 0) |
---|
| 231 | + if (err < 0) // hard error |
---|
234 | 232 | break; |
---|
235 | | - if (unlikely(err)) |
---|
| 233 | + if (unlikely(err)) // ->show() says "skip it" |
---|
236 | 234 | m->count = 0; |
---|
237 | | - if (unlikely(!m->count)) { |
---|
| 235 | + if (unlikely(!m->count)) { // empty record |
---|
238 | 236 | p = m->op->next(m, p, &m->index); |
---|
239 | 237 | continue; |
---|
240 | 238 | } |
---|
241 | | - if (m->count < m->size) |
---|
| 239 | + if (!seq_has_overflowed(m)) // got it |
---|
242 | 240 | goto Fill; |
---|
| 241 | + // need a bigger buffer |
---|
243 | 242 | m->op->stop(m, p); |
---|
244 | 243 | kvfree(m->buf); |
---|
245 | 244 | m->count = 0; |
---|
246 | 245 | m->buf = seq_buf_alloc(m->size <<= 1); |
---|
247 | 246 | if (!m->buf) |
---|
248 | 247 | goto Enomem; |
---|
249 | | - m->version = 0; |
---|
250 | 248 | p = m->op->start(m, &m->index); |
---|
251 | 249 | } |
---|
| 250 | + // EOF or an error |
---|
252 | 251 | m->op->stop(m, p); |
---|
253 | 252 | m->count = 0; |
---|
254 | 253 | goto Done; |
---|
255 | 254 | Fill: |
---|
256 | | - /* they want more? let's try to get some more */ |
---|
| 255 | + // one non-empty record is in the buffer; if they want more, |
---|
| 256 | + // try to fit more in, but in any case we need to advance |
---|
| 257 | + // the iterator once for every record shown. |
---|
257 | 258 | while (1) { |
---|
258 | 259 | size_t offs = m->count; |
---|
259 | 260 | loff_t pos = m->index; |
---|
260 | 261 | |
---|
261 | 262 | p = m->op->next(m, p, &m->index); |
---|
262 | | - if (pos == m->index) |
---|
263 | | - /* Buggy ->next function */ |
---|
| 263 | + if (pos == m->index) { |
---|
| 264 | + pr_info_ratelimited("buggy .next function %ps did not update position index\n", |
---|
| 265 | + m->op->next); |
---|
264 | 266 | m->index++; |
---|
265 | | - if (!p || IS_ERR(p)) { |
---|
266 | | - err = PTR_ERR(p); |
---|
267 | | - break; |
---|
268 | 267 | } |
---|
269 | | - if (m->count >= size) |
---|
| 268 | + if (!p || IS_ERR(p)) // no next record for us |
---|
| 269 | + break; |
---|
| 270 | + if (m->count >= iov_iter_count(iter)) |
---|
270 | 271 | break; |
---|
271 | 272 | err = m->op->show(m, p); |
---|
272 | | - if (seq_has_overflowed(m) || err) { |
---|
| 273 | + if (err > 0) { // ->show() says "skip it" |
---|
273 | 274 | m->count = offs; |
---|
274 | | - if (likely(err <= 0)) |
---|
275 | | - break; |
---|
| 275 | + } else if (err || seq_has_overflowed(m)) { |
---|
| 276 | + m->count = offs; |
---|
| 277 | + break; |
---|
276 | 278 | } |
---|
277 | 279 | } |
---|
278 | 280 | m->op->stop(m, p); |
---|
279 | | - n = min(m->count, size); |
---|
280 | | - err = copy_to_user(buf, m->buf, n); |
---|
281 | | - if (err) |
---|
282 | | - goto Efault; |
---|
| 281 | + n = copy_to_iter(m->buf, m->count, iter); |
---|
283 | 282 | copied += n; |
---|
284 | 283 | m->count -= n; |
---|
285 | 284 | m->from = n; |
---|
286 | 285 | Done: |
---|
287 | | - if (!copied) |
---|
288 | | - copied = err; |
---|
289 | | - else { |
---|
290 | | - *ppos += copied; |
---|
| 286 | + if (unlikely(!copied)) { |
---|
| 287 | + copied = m->count ? -EFAULT : err; |
---|
| 288 | + } else { |
---|
| 289 | + iocb->ki_pos += copied; |
---|
291 | 290 | m->read_pos += copied; |
---|
292 | 291 | } |
---|
293 | | - file->f_version = m->version; |
---|
294 | 292 | mutex_unlock(&m->lock); |
---|
295 | 293 | return copied; |
---|
296 | 294 | Enomem: |
---|
297 | 295 | err = -ENOMEM; |
---|
298 | 296 | goto Done; |
---|
299 | | -Efault: |
---|
300 | | - err = -EFAULT; |
---|
301 | | - goto Done; |
---|
302 | 297 | } |
---|
303 | | -EXPORT_SYMBOL(seq_read); |
---|
| 298 | +EXPORT_SYMBOL(seq_read_iter); |
---|
304 | 299 | |
---|
305 | 300 | /** |
---|
306 | 301 | * seq_lseek - ->llseek() method for sequential files. |
---|
.. | .. |
---|
316 | 311 | loff_t retval = -EINVAL; |
---|
317 | 312 | |
---|
318 | 313 | mutex_lock(&m->lock); |
---|
319 | | - m->version = file->f_version; |
---|
320 | 314 | switch (whence) { |
---|
321 | 315 | case SEEK_CUR: |
---|
322 | 316 | offset += file->f_pos; |
---|
| 317 | + fallthrough; |
---|
323 | 318 | case SEEK_SET: |
---|
324 | 319 | if (offset < 0) |
---|
325 | 320 | break; |
---|
.. | .. |
---|
331 | 326 | /* with extreme prejudice... */ |
---|
332 | 327 | file->f_pos = 0; |
---|
333 | 328 | m->read_pos = 0; |
---|
334 | | - m->version = 0; |
---|
335 | 329 | m->index = 0; |
---|
336 | 330 | m->count = 0; |
---|
337 | 331 | } else { |
---|
.. | .. |
---|
342 | 336 | file->f_pos = offset; |
---|
343 | 337 | } |
---|
344 | 338 | } |
---|
345 | | - file->f_version = m->version; |
---|
346 | 339 | mutex_unlock(&m->lock); |
---|
347 | 340 | return retval; |
---|
348 | 341 | } |
---|
.. | .. |
---|
386 | 379 | } |
---|
387 | 380 | EXPORT_SYMBOL(seq_escape); |
---|
388 | 381 | |
---|
| 382 | +void seq_escape_mem_ascii(struct seq_file *m, const char *src, size_t isz) |
---|
| 383 | +{ |
---|
| 384 | + char *buf; |
---|
| 385 | + size_t size = seq_get_buf(m, &buf); |
---|
| 386 | + int ret; |
---|
| 387 | + |
---|
| 388 | + ret = string_escape_mem_ascii(src, isz, buf, size); |
---|
| 389 | + seq_commit(m, ret < size ? ret : -1); |
---|
| 390 | +} |
---|
| 391 | +EXPORT_SYMBOL(seq_escape_mem_ascii); |
---|
| 392 | + |
---|
389 | 393 | void seq_vprintf(struct seq_file *m, const char *f, va_list args) |
---|
390 | 394 | { |
---|
391 | 395 | int len; |
---|