| .. | .. |
|---|
| 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; |
|---|