![Eric Biederman](/assets/img/avatar_default.png)
Currently seq_read assumes that the offset passed to it is always the offset it passed to user space. In the case pread this assumption is broken and we do the wrong thing when presented with pread. To solve this I introduce an offset cache inside of struct seq_file so we know where our logical file position is. Then in seq_read if we try to read from another offset we reset our data structures and attempt to go to the offset user space wanted. [akpm@linux-foundation.org: restore FMODE_PWRITE] [pjt@google.com: seq_open needs its fmode opened up to take advantage of this] Signed-off-by: Eric Biederman <ebiederm@xmission.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Paul Turner <pjt@google.com> Cc: <stable@kernel.org> [2.6.25.x, 2.6.26.x, 2.6.27.x, 2.6.28.x] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
99 lines
2.8 KiB
C
99 lines
2.8 KiB
C
#ifndef _LINUX_SEQ_FILE_H
|
|
#define _LINUX_SEQ_FILE_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/string.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/nodemask.h>
|
|
|
|
struct seq_operations;
|
|
struct file;
|
|
struct path;
|
|
struct inode;
|
|
struct dentry;
|
|
|
|
struct seq_file {
|
|
char *buf;
|
|
size_t size;
|
|
size_t from;
|
|
size_t count;
|
|
loff_t index;
|
|
loff_t read_pos;
|
|
u64 version;
|
|
struct mutex lock;
|
|
const struct seq_operations *op;
|
|
void *private;
|
|
};
|
|
|
|
struct seq_operations {
|
|
void * (*start) (struct seq_file *m, loff_t *pos);
|
|
void (*stop) (struct seq_file *m, void *v);
|
|
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
|
|
int (*show) (struct seq_file *m, void *v);
|
|
};
|
|
|
|
#define SEQ_SKIP 1
|
|
|
|
char *mangle_path(char *s, char *p, char *esc);
|
|
int seq_open(struct file *, const struct seq_operations *);
|
|
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
|
|
loff_t seq_lseek(struct file *, loff_t, int);
|
|
int seq_release(struct inode *, struct file *);
|
|
int seq_escape(struct seq_file *, const char *, const char *);
|
|
int seq_putc(struct seq_file *m, char c);
|
|
int seq_puts(struct seq_file *m, const char *s);
|
|
|
|
int seq_printf(struct seq_file *, const char *, ...)
|
|
__attribute__ ((format (printf,2,3)));
|
|
|
|
int seq_path(struct seq_file *, struct path *, char *);
|
|
int seq_dentry(struct seq_file *, struct dentry *, char *);
|
|
int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
|
|
char *esc);
|
|
int seq_bitmap(struct seq_file *m, const unsigned long *bits,
|
|
unsigned int nr_bits);
|
|
static inline int seq_cpumask(struct seq_file *m, const struct cpumask *mask)
|
|
{
|
|
return seq_bitmap(m, mask->bits, nr_cpu_ids);
|
|
}
|
|
|
|
static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
|
|
{
|
|
return seq_bitmap(m, mask->bits, MAX_NUMNODES);
|
|
}
|
|
|
|
int seq_bitmap_list(struct seq_file *m, unsigned long *bits,
|
|
unsigned int nr_bits);
|
|
|
|
static inline int seq_cpumask_list(struct seq_file *m, cpumask_t *mask)
|
|
{
|
|
return seq_bitmap_list(m, mask->bits, NR_CPUS);
|
|
}
|
|
|
|
static inline int seq_nodemask_list(struct seq_file *m, nodemask_t *mask)
|
|
{
|
|
return seq_bitmap_list(m, mask->bits, MAX_NUMNODES);
|
|
}
|
|
|
|
int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
|
|
int single_release(struct inode *, struct file *);
|
|
void *__seq_open_private(struct file *, const struct seq_operations *, int);
|
|
int seq_open_private(struct file *, const struct seq_operations *, int);
|
|
int seq_release_private(struct inode *, struct file *);
|
|
|
|
#define SEQ_START_TOKEN ((void *)1)
|
|
|
|
/*
|
|
* Helpers for iteration over list_head-s in seq_files
|
|
*/
|
|
|
|
extern struct list_head *seq_list_start(struct list_head *head,
|
|
loff_t pos);
|
|
extern struct list_head *seq_list_start_head(struct list_head *head,
|
|
loff_t pos);
|
|
extern struct list_head *seq_list_next(void *v, struct list_head *head,
|
|
loff_t *ppos);
|
|
|
|
#endif
|