mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-28 11:22:15 +03:00
o Revised seq_file usage after discussions on linux-fsdevel
This commit is contained in:
parent
904539476a
commit
dc49ae519e
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user