mm: vmap fix overflow
[safe/jmp/linux-2.6] / fs / seq_file.c
index 5267098..a1a4cfe 100644 (file)
@@ -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;
                                }
                        }