FileSystem Things

Table of Contents

seqfile

seq_printf(will not overflow)

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;
}
EXPORT_SYMBOL(seq_printf);

seq_read small and large file

Makefile and seq test.c

/*
 * Simple demonstratino of the seq_file interface
 * Felix SHI <shishougang@gmail.com>
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>   /* everything... */
#include <linux/seq_file.h>
#include <linux/kernel.h>    /* printk() */
#include <linux/slab.h>        /* kmalloc() */
#include <linux/types.h>        /* size_t */
#include <linux/list.h>

MODULE_AUTHOR("Felix Shi");
MODULE_LICENSE("Dual BSD/GPL");

struct info_struct {
  struct list_head list;
  char info[10];
};

static LIST_HEAD(data_list);
void empty_list(void)
{
  struct info_struct *p, *ptmp;
  list_for_each_entry_safe(p, ptmp, &data_list, list){
    list_del(p);
    kfree(p);
  }
}

/* The procfs read entry point */
/*
static int proctest_read(char *page, char **start, off_t offset,
                         int count, int *eof, void *data)
{
  int i = 0;
  off_t len = 0;
  struct info_struct *p;

  list_for_each_entry(p, &data_list, list) {
    len += sprintf(page + len, p->info);
  }

  *eof = 1;
  return len;
}*/

static int proctest_large_read(char *page, char **start, off_t offset,
                               int count, int *eof, void *data)
{
  off_t start_point = 0;
  off_t len = 0;

  struct info_struct *p;

  list_for_each_entry(p, &data_list, list){
    len += sprintf(page + len, p->info);

    if(start_point + len <= offset){
      start_point += len;
      len = 0;
    }else if(start_point + len >= offset + count){
      break;
    }
  }

  /* Actual start */
  *start = page + (offset - start_point);

  len -= (offset - start_point);
  if(len > count)
    len = count;
  else
    *eof = 1;
  return len;
}

static int seq_test_init(void)
{
  int i;
  static struct proc_dir_entry *entry = NULL;
  struct info_struct *pinfo;
  entry = create_proc_entry("seqtest", 0, NULL);
  if(entry)
    //entry->read_proc = proctest__read;
    entry->read_proc = proctest_large_read;

  for(i = 0; i < 500; ++i){
    pinfo = kmalloc(sizeof(struct info_struct), GFP_ATOMIC);
    if(!pinfo){
      empty_list();
      return ENOMEM;
    }
    sprintf(pinfo->info, "Node No: %d\n", i);
    list_add_tail(&pinfo->list, &data_list);
  }
  return 0;
}

static void seq_test_exit(void)
{
  remove_proc_entry("seqtest",NULL);
  empty_list();
}
module_init(seq_test_init);
module_exit(seq_test_exit);

seq iteration method

Makefile and seq iter test.c

/*
 * Simple demonstratino of the seq_file interface
 * Felix SHI <shishougang@gmail.com>
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>   /* everything... */
#include <linux/seq_file.h>
#include <linux/kernel.h>    /* printk() */
#include <linux/slab.h>        /* kmalloc() */
#include <linux/types.h>        /* size_t */
#include <linux/list.h>

MODULE_AUTHOR("Felix Shi");
MODULE_LICENSE("Dual BSD/GPL");

struct info_struct {
  struct list_head list;
  char info[10];
};

static LIST_HEAD(data_list);
void empty_list(void)
{
  struct info_struct *p, *ptmp;
  list_for_each_entry_safe(p, ptmp, &data_list, list){
    list_del(p);
    kfree(p);
  }
}

static void *
seq_iter_seq_start(struct seq_file *seq, loff_t *pos)
{
  struct info_struct *p;
  loff_t loff = 0;
  printk("start");
  list_for_each_entry(p, &data_list, list){
    if(*pos == loff++) return p;
  }
  return NULL;
}

static void *
seq_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
  struct list_head *n = ((struct info_struct *)v)->list.next;
  ++*pos;
  return (n != &data_list) ? list_entry(n, struct info_struct, list) : NULL;
}

static int
seq_iter_seq_show(struct seq_file *seq, void *v)
{
  const struct info_struct *p = v;
  seq_printf(seq, p->info);
  return 0;
}

static void
seq_iter_seq_stop(struct seq_file *seq, void *v)
{
}

static struct seq_operations seq_iter_seq_ops = {
  .start = seq_iter_seq_start,
  .next = seq_iter_seq_next,
  .stop = seq_iter_seq_stop,
  .show = seq_iter_seq_show
};

static int seq_iter_seq_open(struct inode *inode, struct file *file)
{
  return seq_open(file, &seq_iter_seq_ops);
}

static struct file_operations seq_iter_proc_fops = {
  .owner = THIS_MODULE,
  .open = seq_iter_seq_open, /* User supplied */
  .read = seq_read,
  .llseek = seq_lseek,
  .release = seq_release
};

static int seq_test_init(void)
{
  int i;
  static struct proc_dir_entry *entry = NULL;
  struct info_struct *pinfo;
  entry = create_proc_entry("seqitertest", 0, NULL);
  printk("init");
  if(entry)
    entry->proc_fops = &seq_iter_proc_fops;

  for(i = 0; i < 500; ++i){
    pinfo = kmalloc(sizeof(struct info_struct), GFP_ATOMIC);
    if(!pinfo){
      empty_list();
      return ENOMEM;
    }
    sprintf(pinfo->info, "Node No: %d\n", i);
    list_add_tail(&pinfo->list, &data_list);
  }
  return 0;
}

static void seq_test_exit(void)
{
  printk("exit");
  remove_proc_entry("seqtest",NULL);
  empty_list();
}
module_init(seq_test_init);
module_exit(seq_test_exit);

Author: Shi Shougang

Created: 2015-03-05 Thu 23:20

Emacs 24.3.1 (Org mode 8.2.10)

Validate