|
@@ -48,8 +48,16 @@ int seq_open(struct file *file, const struct seq_operations *op)
|
|
|
*/
|
|
|
file->f_version = 0;
|
|
|
|
|
|
- /* SEQ files support lseek, but not pread/pwrite */
|
|
|
- file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
|
|
|
+ /*
|
|
|
+ * seq_files support lseek() and pread(). They do not implement
|
|
|
+ * write() at all, but we clear FMODE_PWRITE here for historical
|
|
|
+ * reasons.
|
|
|
+ *
|
|
|
+ * If a client of seq_files a) implements file.write() and b) wishes to
|
|
|
+ * support pwrite() then that client will need to implement its own
|
|
|
+ * file.open() which calls seq_open() and then sets FMODE_PWRITE.
|
|
|
+ */
|
|
|
+ file->f_mode &= ~FMODE_PWRITE;
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(seq_open);
|
|
@@ -131,6 +139,22 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
|
|
|
int err = 0;
|
|
|
|
|
|
mutex_lock(&m->lock);
|
|
|
+
|
|
|
+ /* Don't assume *ppos is where we left it */
|
|
|
+ if (unlikely(*ppos != m->read_pos)) {
|
|
|
+ m->read_pos = *ppos;
|
|
|
+ while ((err = traverse(m, *ppos)) == -EAGAIN)
|
|
|
+ ;
|
|
|
+ if (err) {
|
|
|
+ /* With prejudice... */
|
|
|
+ m->read_pos = 0;
|
|
|
+ m->version = 0;
|
|
|
+ m->index = 0;
|
|
|
+ m->count = 0;
|
|
|
+ goto Done;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* seq_file->op->..m_start/m_stop/m_next may do special actions
|
|
|
* or optimisations based on the file->f_version, so we want to
|
|
@@ -230,8 +254,10 @@ Fill:
|
|
|
Done:
|
|
|
if (!copied)
|
|
|
copied = err;
|
|
|
- else
|
|
|
+ else {
|
|
|
*ppos += copied;
|
|
|
+ m->read_pos += copied;
|
|
|
+ }
|
|
|
file->f_version = m->version;
|
|
|
mutex_unlock(&m->lock);
|
|
|
return copied;
|
|
@@ -266,16 +292,18 @@ loff_t seq_lseek(struct file *file, loff_t offset, int origin)
|
|
|
if (offset < 0)
|
|
|
break;
|
|
|
retval = offset;
|
|
|
- if (offset != file->f_pos) {
|
|
|
+ if (offset != m->read_pos) {
|
|
|
while ((retval=traverse(m, offset)) == -EAGAIN)
|
|
|
;
|
|
|
if (retval) {
|
|
|
/* with extreme prejudice... */
|
|
|
file->f_pos = 0;
|
|
|
+ m->read_pos = 0;
|
|
|
m->version = 0;
|
|
|
m->index = 0;
|
|
|
m->count = 0;
|
|
|
} else {
|
|
|
+ m->read_pos = offset;
|
|
|
retval = file->f_pos = offset;
|
|
|
}
|
|
|
}
|