LIST_HEADやlist_add_tailやlist_delやkfree/kmallocの使い方のメモ

案外コードのサンプルが少ないのでメモとして.特にカーネルモジュールになると書く人がぐんと少なくなるので初心者入門用としてどうぞ.

次のlist.cとMakefileを一緒にディレクトリに入れて2.6.30で確認.ただしカーネル内のメモリ管理(kmalloc/kfree)が上手くいっているかvalgrind的なものがないのがちょっと気がかり.このメモリ解放しわすれてるよ,的な指摘をお待ちしています.

自分で定義した構造体のリストをつくって,そこに要素を10000ぐらい突っこんで,モジュールがリロードされるときにその領域を全て解放します.

/*
list.c
*/
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>

static LIST_HEAD(my_object_list);

struct my_object {
  struct list_head list;
  /* Time when it recorded from when it started to record */
  long int sec;
  /* tty device name, distinguishing ttys in a honeypot node */
  char tty_name[6];
};

int init_module(void)
{
  struct list_head *p;
  struct my_object *myobj;
  int i;
  printk(KERN_INFO "list append test.\n");

  /*
    GFP_KERNEL : If there is no memory available, it sleeps.
    GFP_ATOMIC : Do not sleep. If no memory available, it fails.
   */
  for (i=0; i<10000; ++i) {
    myobj = kmalloc(sizeof(struct my_object), GFP_KERNEL);
    myobj->sec = i;
    strncpy(myobj->tty_name, "tty", 5);
    list_add_tail(&myobj->list, &my_object_list);
  }

  list_for_each(p, &my_object_list) {
    myobj = list_entry(p, struct my_object, list);
    printk("*** name %s : %ld\n", myobj->tty_name, myobj->sec);
  }

  return 0;
}

void cleanup_module(void)
{
  struct my_object *myobj;
  /*
  struct list_head *next;
  next = head.next;*/
  int i = 0;
  printk("*** start to delete\n");
  while(!list_empty(&my_object_list)) {
    myobj = list_entry(my_object_list.next, struct my_object, list);
    printk("*** deleting %d\n", i++);
    list_del(&myobj->list);
    kfree(myobj);
  }


  /*
    The code below would not work!

  list_for_each(p, &head) {
    myobj = list_entry(p, struct my_object, list);
    list_del(&myobj->list);
    kfree(myobj);
  }
    Because this code destroys elements of the list while the list is required to list_for_each
  */

  printk(KERN_INFO "Goodbye.\n");
}
# Makefile
obj-m += list.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

check-syntax:
	LANG=C make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

このcheck-syntaxはflymakeのためのもの.このカーネルモジュールを動かしてみるには

sudo insmod list
dmesg
sudo rmmod list

を打ってみればよい.


struct list_headを構造体の中に埋め込むことでその構造体のリストを扱うことができるようになる.