#ifndef
_SEQ_FILE_HELPER_H_
#define
_SEQ_FILE_HELPER_H_
#include <linux/version.h>
#include <linux/list.h>
#include <linux/rbtree.h>
#include <linux/seq_file.h>
#if LINUX_VERSION_CODE
<
KERNEL_VERSION(2, 6, 23)
static inline struct list_head
*seq_list_start(struct list_head *head,
loff_t
pos)
{
struct list_head
*lh;
list_for_each(lh, head)
if (pos-- == 0)
return lh;
return NULL;
}
static inline struct list_head
*seq_list_next(void *v, struct list_head *head,
loff_t
*ppos)
{
struct list_head
*lh;
lh
= ((struct list_head *)v)->next;
++*ppos;
return lh == head ? NULL : lh;
}
#endif
/* common macro
*/
#define
__DEFINE_FOO_SEQ_FOPS(prefix, foo, imp_show, imp_write) \
static struct seq_operations
_##foo##_seq_ops = { \
.start = _##foo##_seq_start, \
.next = _##foo##_seq_next, \
.stop = _##foo##_seq_stop, \
.show = imp_show \
}; \
\
static int _##foo##_seq_open(struct inode *inode, struct file *file) \
{ \
return seq_open(file, &_##foo##_seq_ops); \
} \
\
prefix struct
file_operations foo##_seq_fops = { \
.open = _##foo##_seq_open, \
.read = seq_read, \
.write = imp_write, \
.llseek = seq_lseek, \
.release = seq_release,
\
.owner = THIS_MODULE
};
/* helper for array
*/
#define
_DEFINE_ARRAY_SEQ_FOPS(prefix, arr, n, lock, unlock, imp_show, \
imp_write) \
static void* _##arr##_seq_start(struct seq_file *m, loff_t *pos) \
{ \
lock; \
if (*pos >= n) \
return NULL; \
return &arr[*pos]; \
} \
\
static void* _##arr##_seq_next(struct seq_file *m, void *p, loff_t *pos) \
{ \
if (++*pos >= n) \
return NULL; \
return &arr[*pos]; \
} \
\
static void _##arr##_seq_stop(struct seq_file *m, void *p) \
{ \
unlock; \
} \
\
__DEFINE_FOO_SEQ_FOPS(prefix, arr, imp_show, imp_write)
#define
DEFINE_ARRAY_SEQ_FOPS(arr, n, lock, unlock, imp_show, imp_write) \
_DEFINE_ARRAY_SEQ_FOPS(, arr, n, lock, unlock, imp_show, imp_write)
#define
DEFINE_STATIC_ARRAY_SEQ_FOPS(arr, n, lock, unlock, imp_show, \
imp_write) \
_DEFINE_ARRAY_SEQ_FOPS(static, arr, n, lock, unlock, imp_show, \
imp_write)
/* helper for list
*/
#define
_DEFINE_LIST_SEQ_FOPS(prefix, list, lock, unlock, imp_show, imp_write) \
static void* _##list##_seq_start(struct seq_file *m, loff_t *pos) \
{ \
lock; \
return
seq_list_start(&list, *pos); \
} \
\
static void* _##list##_seq_next(struct seq_file *m, void *p, loff_t *pos) \
{ \
return
seq_list_next(p, &list, pos); \
} \
\
static void _##list##_seq_stop(struct seq_file *m, void *p) \
{ \
unlock; \
} \
\
__DEFINE_FOO_SEQ_FOPS(prefix, list, imp_show, imp_write)
#define
DEFINE_LIST_SEQ_FOPS(list, lock, unlock, imp_show, imp_write) \
_DEFINE_LIST_SEQ_FOPS(, list, lock, unlock, imp_show, imp_write)
#define
DEFINE_STATIC_LIST_SEQ_FOPS(list, lock, unlock, imp_show, imp_write) \
_DEFINE_LIST_SEQ_FOPS(static, list, lock, unlock, imp_show, imp_write)
/* helper for hlist
*/
#ifndef
hlist_for_each_continue
#define
hlist_for_each_continue(pos) \
for (pos = pos->next; pos && ({ prefetch(pos->next); 1; }); \
pos
= pos->next)
#endif
#define
_DEFINE_HLIST_SEQ_FOPS(prefix, head, n, lock, unlock, imp_show, \
imp_write) \
struct
_##head##_seq_iter { \
unsigned int idx; \
struct hlist_node
*node; \
}; \
\
static void* _##head##_seq_start(struct seq_file *m, loff_t *pos) \
{ \
struct hlist_node
*node; \
unsigned int idx; \
loff_t
off = *pos; \
\
lock; \
for (idx = 0; idx < n; idx++) { \
hlist_for_each(node, &head[idx]) { \
if (off-- == 0) { \
struct _##head##_seq_iter *iter; \
iter
=
kmalloc(sizeof(*iter), GFP_KERNEL); \
if (iter == NULL) \
break; \
iter->idx = idx; \
iter->node = node; \
return iter; \
} \
} \
} \
\
return NULL; \
} \
\
static void* _##head##_seq_next(struct seq_file *m, void *p, loff_t *pos) \
{ \
struct _##head##_seq_iter *iter = (struct _##head##_seq_iter*)p; \
\
++*pos; \
hlist_for_each_continue(iter->node) \
return iter; \
for (iter->idx++; iter->idx < n; iter->idx++) { \
hlist_for_each(iter->node, &head[iter->idx]) \
return iter; \
} \
kfree(iter); \
\
return NULL; \
} \
\
static void _##head##_seq_stop(struct seq_file *m, void *p) \
{ \
kfree(p); \
unlock; \
} \
\
static int _##head##_seq_show(struct seq_file *m, void *p) \
{ \
struct _##head##_seq_iter *iter = (struct _##head##_seq_iter*)p; \
\
return imp_show(m, iter->node); \
} \
\
__DEFINE_FOO_SEQ_FOPS(prefix, head, _##head##_seq_show, imp_write)
#define
DEFINE_HLIST_SEQ_FOPS(head, n, lock, unlock, imp_show, imp_write) \
_DEFINE_HLIST_SEQ_FOPS(, head, n, lock, unlock, imp_show, imp_write)
#define
DEFINE_STATIC_HLIST_SEQ_FOPS(head, n, lock, unlock, imp_show, \
imp_write) \
_DEFINE_HLIST_SEQ_FOPS(static, head, n, lock, unlock, imp_show, \
imp_write)
/* helper for rbtree
*/
#define
_DEFINE_RBTREE_SEQ_FOPS(prefix, tree, lock, unlock, imp_show, \
imp_write) \
static void* _##tree##_seq_start(struct seq_file *m, loff_t *pos) \
{ \
struct rb_node *node; \
loff_t
off = *pos; \
\
lock; \
node
=
rb_first(&tree); \
while (off-- > 0 && node != NULL) \
node
=
rb_next(node); \
\
return node; \
} \
\
static void* _##tree##_seq_next(struct seq_file *m, void *p, loff_t *pos) \
{ \
++*pos; \
return rb_next((struct rb_node*)p); \
} \
\
static void _##tree##_seq_stop(struct seq_file *m, void *p) \
{ \
unlock; \
} \
\
__DEFINE_FOO_SEQ_FOPS(prefix, tree, imp_show, imp_write)
#define
DEFINE_RBTREE_SEQ_FOPS(tree, lock, unlock, imp_show, imp_write) \
_DEFINE_RBTREE_SEQ_FOPS(, tree, lock, unlock, imp_show, imp_write)
#define
DEFINE_STATIC_RBTREE_SEQ_FOPS(tree, lock, unlock, imp_show, \
imp_write) \
_DEFINE_RBTREE_SEQ_FOPS(static, tree, lock, unlock, imp_show, \
imp_write)
#endif /* _SEQ_FILE_HELPER_H_
*/
|