diff options
Diffstat (limited to 'fs/seq_file.c')
| -rw-r--r-- | fs/seq_file.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c index 5267098532bf..a1a4cfe19210 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
| @@ -48,8 +48,16 @@ int seq_open(struct file *file, const struct seq_operations *op) | |||
| 48 | */ | 48 | */ |
| 49 | file->f_version = 0; | 49 | file->f_version = 0; |
| 50 | 50 | ||
| 51 | /* SEQ files support lseek, but not pread/pwrite */ | 51 | /* |
| 52 | file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); | 52 | * seq_files support lseek() and pread(). They do not implement |
| 53 | * write() at all, but we clear FMODE_PWRITE here for historical | ||
| 54 | * reasons. | ||
| 55 | * | ||
| 56 | * If a client of seq_files a) implements file.write() and b) wishes to | ||
| 57 | * support pwrite() then that client will need to implement its own | ||
| 58 | * file.open() which calls seq_open() and then sets FMODE_PWRITE. | ||
| 59 | */ | ||
| 60 | file->f_mode &= ~FMODE_PWRITE; | ||
| 53 | return 0; | 61 | return 0; |
| 54 | } | 62 | } |
| 55 | EXPORT_SYMBOL(seq_open); | 63 | EXPORT_SYMBOL(seq_open); |
| @@ -131,6 +139,22 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
| 131 | int err = 0; | 139 | int err = 0; |
| 132 | 140 | ||
| 133 | mutex_lock(&m->lock); | 141 | mutex_lock(&m->lock); |
| 142 | |||
| 143 | /* Don't assume *ppos is where we left it */ | ||
| 144 | if (unlikely(*ppos != m->read_pos)) { | ||
| 145 | m->read_pos = *ppos; | ||
| 146 | while ((err = traverse(m, *ppos)) == -EAGAIN) | ||
| 147 | ; | ||
| 148 | if (err) { | ||
| 149 | /* With prejudice... */ | ||
| 150 | m->read_pos = 0; | ||
| 151 | m->version = 0; | ||
| 152 | m->index = 0; | ||
| 153 | m->count = 0; | ||
| 154 | goto Done; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 134 | /* | 158 | /* |
| 135 | * seq_file->op->..m_start/m_stop/m_next may do special actions | 159 | * seq_file->op->..m_start/m_stop/m_next may do special actions |
| 136 | * or optimisations based on the file->f_version, so we want to | 160 | * or optimisations based on the file->f_version, so we want to |
| @@ -230,8 +254,10 @@ Fill: | |||
| 230 | Done: | 254 | Done: |
| 231 | if (!copied) | 255 | if (!copied) |
| 232 | copied = err; | 256 | copied = err; |
| 233 | else | 257 | else { |
| 234 | *ppos += copied; | 258 | *ppos += copied; |
| 259 | m->read_pos += copied; | ||
| 260 | } | ||
| 235 | file->f_version = m->version; | 261 | file->f_version = m->version; |
| 236 | mutex_unlock(&m->lock); | 262 | mutex_unlock(&m->lock); |
| 237 | return copied; | 263 | return copied; |
| @@ -266,16 +292,18 @@ loff_t seq_lseek(struct file *file, loff_t offset, int origin) | |||
| 266 | if (offset < 0) | 292 | if (offset < 0) |
| 267 | break; | 293 | break; |
| 268 | retval = offset; | 294 | retval = offset; |
| 269 | if (offset != file->f_pos) { | 295 | if (offset != m->read_pos) { |
| 270 | while ((retval=traverse(m, offset)) == -EAGAIN) | 296 | while ((retval=traverse(m, offset)) == -EAGAIN) |
| 271 | ; | 297 | ; |
| 272 | if (retval) { | 298 | if (retval) { |
| 273 | /* with extreme prejudice... */ | 299 | /* with extreme prejudice... */ |
| 274 | file->f_pos = 0; | 300 | file->f_pos = 0; |
| 301 | m->read_pos = 0; | ||
| 275 | m->version = 0; | 302 | m->version = 0; |
| 276 | m->index = 0; | 303 | m->index = 0; |
| 277 | m->count = 0; | 304 | m->count = 0; |
| 278 | } else { | 305 | } else { |
| 306 | m->read_pos = offset; | ||
| 279 | retval = file->f_pos = offset; | 307 | retval = file->f_pos = offset; |
| 280 | } | 308 | } |
| 281 | } | 309 | } |
