1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

o Revised seq_file usage after discussions on linux-fsdevel

This commit is contained in:
Steven Whitehouse 2001-11-22 15:14:20 +00:00
parent 60140607cf
commit 58486cf9f5
3 changed files with 12 additions and 307 deletions

View File

@ -70,11 +70,11 @@ void dmfs_zap_errors(struct inode *inode)
}
}
static void *e_start(void *context, loff_t *pos)
static void *e_start(struct seq_file *e, loff_t *pos)
{
struct list_head *p;
loff_t n = *pos;
struct dmfs_i *dmi = context;
struct dmfs_i *dmi = e->context;
down(&dmi->sem);
if (dmi->status) {
@ -90,18 +90,18 @@ static void *e_start(void *context, loff_t *pos)
return NULL;
}
static void *e_next(void *context, void *v, loff_t *pos)
static void *e_next(struct seq_file *e, void *v, loff_t *pos)
{
struct dmfs_i *dmi = context;
struct dmfs_i *dmi = e->context;
struct list_head *p = ((struct dmfs_error *)v)->list.next;
(*pos)++;
return (p == &dmi->errors) || (p == &oom_list) ? NULL
: list_entry(p, struct dmfs_error, list);
}
static void e_stop(void *context, void *v)
static void e_stop(struct seq_file *e, void *v)
{
struct dmfs_i *dmi = context;
struct dmfs_i *dmi = e->context;
up(&dmi->sem);
}
@ -121,7 +121,12 @@ static struct seq_operations error_op = {
static int dmfs_error_open(struct inode *inode, struct file *file)
{
return seq_open(file, &error_op, DMFS_I(file->f_dentry->d_parent->d_inode));
int ret = seq_open(file, &error_op);
if (ret >=0) {
struct seq_file *seq = file->private_data;
seq->context = DMFS_I(file->f_dentry->d_parent->d_inode);
}
return ret;
}
static int dmfs_error_sync(struct file *file, struct dentry *dentry, int datasync)

View File

@ -1,240 +0,0 @@
/*
* linux/fs/seq_file.c
*
* helper functions for making syntetic files from sequences of records.
* initial implementation -- AV, Oct 2001.
*
* Slight modifications to the original. Will be passed on to Al Viro in
* the next few days.
*/
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
/**
* seq_open - initialize sequential file
* @file: file we initialize
* @op: method table describing the sequence
*
* seq_open() sets @file, associating it with a sequence described
* by @op. @op->start() sets the iterator up and returns the first
* element of sequence. @op->stop() shuts it down. @op->next()
* returns the next element of sequence. @op->show() prints element
* into the buffer. In case of error ->start() and ->next() return
* ERR_PTR(error). In the end of sequence they return %NULL. ->show()
* returns 0 in case of success and negative number in case of error.
*/
int seq_open(struct file *file, struct seq_operations *op, void *context)
{
struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
memset(p, 0, sizeof(*p));
sema_init(&p->sem, 1);
p->op = op;
p->context = context;
file->private_data = p;
return 0;
}
/**
* seq_read - ->read() method for sequential files.
* @file, @buf, @size, @ppos: see file_operations method
*
* Ready-made ->f_op->read()
*/
ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos)
{
struct seq_file *m = (struct seq_file *)file->private_data;
size_t copied = 0;
loff_t pos;
size_t n;
void *p;
int err = 0;
if (ppos != &file->f_pos)
return -EPIPE;
down(&m->sem);
/* grab buffer if we didn't have one */
if (!m->buf) {
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
if (!m->buf)
goto Enomem;
}
/* if not empty - flush it first */
if (m->count) {
n = min(m->count, size);
err = copy_to_user(buf, m->buf + m->from, n);
if (err)
goto Efault;
m->count -= n;
m->from += n;
size -= n;
buf += n;
copied += n;
if (!m->count)
(*ppos)++;
if (!size)
goto Done;
}
/* we need at least one record in buffer */
while (1) {
pos = *ppos;
p = m->op->start(m->context, &pos);
err = PTR_ERR(p);
if (!p || IS_ERR(p))
break;
err = m->op->show(m, p);
if (err)
break;
if (m->count < m->size)
goto Fill;
m->op->stop(m->context, p);
kfree(m->buf);
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
if (!m->buf)
goto Enomem;
}
m->op->stop(m->context, p);
goto Done;
Fill:
/* they want more? let's try to get some more */
while (m->count < size) {
size_t offs = m->count;
loff_t next = pos;
p = m->op->next(m->context, p, &next);
if (!p || IS_ERR(p)) {
err = PTR_ERR(p);
break;
}
err = m->op->show(m, p);
if (err || m->count == m->size) {
m->count = offs;
break;
}
pos = next;
}
m->op->stop(m->context, p);
n = min(m->count, size);
err = copy_to_user(buf, m->buf, n);
if (err)
goto Efault;
copied += n;
m->count -= n;
if (m->count)
m->from = n;
else
pos++;
*ppos = pos;
Done:
if (!copied)
copied = err;
up(&m->sem);
return copied;
Enomem:
err = -ENOMEM;
goto Done;
Efault:
err = -EFAULT;
goto Done;
}
/**
* seq_lseek - ->llseek() method for sequential files.
* @file, @offset, @origin: see file_operations method
*
* Ready-made ->f_op->llseek()
*/
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
{
struct seq_file *m = (struct seq_file *)file->private_data;
long long retval = -EINVAL;
down(&m->sem);
switch (origin) {
case 1:
offset += file->f_pos;
case 0:
if (offset < 0)
break;
if (offset != file->f_pos) {
file->f_pos = offset;
m->count = 0;
}
retval = offset;
}
up(&m->sem);
return retval;
}
/**
* seq_release - free the structures associated with sequential file.
* @file: file in question
* @inode: file->f_dentry->d_inode
*
* Frees the structures associated with sequential file; can be used
* as ->f_op->release() if you don't have private data to destroy.
*/
int seq_release(struct inode *inode, struct file *file)
{
struct seq_file *m = (struct seq_file *)file->private_data;
kfree(m->buf);
kfree(m);
return 0;
}
/**
* seq_escape - print string into buffer, escaping some characters
* @m: target buffer
* @s: string
* @esc: set of characters that need escaping
*
* Puts string into buffer, replacing each occurence of character from
* @esc with usual octal escape. Returns 0 in case of success, -1 - in
* case of overflow.
*/
int seq_escape(struct seq_file *m, const char *s, const char *esc)
{
char *end = m->buf + m->size;
char *p;
char c;
for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
if (!strchr(esc, c)) {
*p++ = c;
continue;
}
if (p + 3 < end) {
*p++ = '\\';
*p++ = '0' + ((c & 0300) >> 6);
*p++ = '0' + ((c & 070) >> 3);
*p++ = '0' + (c & 07);
continue;
}
m->count = m->size;
return -1;
}
m->count = p - m->buf;
return 0;
}
int seq_printf(struct seq_file *m, const char *f, ...)
{
va_list args;
int len;
if (m->count < m->size) {
va_start(args, f);
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
va_end(args);
if (m->count + len < m->size) {
m->count += len;
return 0;
}
}
m->count = m->size;
return -1;
}

View File

@ -1,60 +0,0 @@
/*
* Original file by Al Viro. This is a slight modification which I'll
* pass on to Al Viro shortly.
*/
#ifndef _LINUX_SEQ_FILE_H
#define _LINUX_SEQ_FILE_H
#ifdef __KERNEL__
struct seq_operations;
struct seq_file {
char *buf;
size_t size;
size_t from;
size_t count;
loff_t index;
struct semaphore sem;
struct seq_operations *op;
void *context;
};
struct seq_operations {
void * (*start) (void *context, loff_t *pos);
void (*stop) (void *context, void *v);
void * (*next) (void *context, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};
int seq_open(struct file *, struct seq_operations *, void *context);
ssize_t seq_read(struct file *, char *, 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 *);
static inline int seq_putc(struct seq_file *m, char c)
{
if (m->count < m->size) {
m->buf[m->count++] = c;
return 0;
}
return -1;
}
static inline int seq_puts(struct seq_file *m, const char *s)
{
int len = strlen(s);
if (m->count + len < m->size) {
memcpy(m->buf + m->count, s, len);
m->count += len;
return 0;
}
m->count = m->size;
return -1;
}
int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3)));
#endif
#endif