#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_ */ |