Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97594
  • 博文数量: 14
  • 博客积分: 601
  • 博客等级: 中士
  • 技术积分: 247
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-05 14:26
文章分类

全部博文(14)

文章存档

2010年(3)

2009年(11)

我的朋友

分类: LINUX

2009-09-09 00:15:05

        jbd2所以的文件在linux-kernel(2.6.30,我所用的是kernel2.6.30)/fs/jbd2目录下,当然还有一个文件在/include/linux下的jbd2.h

下面来看看这个模块一共多少代码,

lan@lan-laptop:~/linux-2.6.30/fs/jbd2$ wc -l *.c

   760 checkpoint.c

  1066 commit.c

  2383 journal.c

   745 recovery.c

   714 revoke.c

  2180 transaction.c

        7848 total

就七千多行代码,这相对于有1000多万行的linux内核来说,真是让我们做梦能笑出声来。其它的先不管,按照fudan_abc的说法,先看看Makefile文件。

lan@lan-laptop:~/linux-2.6.30/fs/jbd2$ cat Makefile

#

# Makefile for the linux journaling routines.

#

 

obj-$(CONFIG_JBD2) += jbd2.o

 

jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o

 

除了注释就两行有用的:

obj-$(CONFIG_JBD2) += jbd2.o这行的意思是你要将jbd2模块以什么样的方式编译到内核中,有三种选择方式(Y与内核一起编译,M以模块方式编译,N不编译,当内核有Ext4或是OCFS2文件系统时不能没有jbd2)。

 

jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o

这行的意思是jbd2所需的目标文件,一共有六个文件,这是一个make的隐式规则,这六个.o文件对应该的是同名的.c文件,就是刚才统计行数的那六个文件。当然还有一个jbd2.hinclude/linux目录下,是其它(Ext4等模块)用的。

 

Jbd2模块的入口在journal.c文件里,看最后三行,

MODULE_LICENSE("GPL");

module_init(journal_init);

module_exit(journal_exit);

写过Linux内核驱动,哪怕是最简单的经典的printk(“hello world\n”);都知道这是三行意思。module_init(journal_init)这个表示jbd2这个模块的入口,它通过执行journal_init这个函数来实现,module_exit(journal_exit)表示这个jbd2这个模块卸载时要执行的函数journal_exit.

 

journal.c的第2352行。

 

 

static int __init journal_init(void)
{
    int ret;

    BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);

    ret = journal_init_caches();
    if (ret == 0) {
        jbd2_create_debugfs_entry();
        jbd2_create_jbd_stats_proc_entry();
    } else {
        jbd2_journal_destroy_caches();
    }
    return ret;
}

 

所有的模块入口函数都是一个模样,哈哈,连空行也就12行,让我们一行一行的看。

2356行是判断journal_superblock_s这个结构体的大小是不是1024字节,如果不是,则迫使编译器报一个编译错误。journal_superblock_sinclude/linux/jbd2.h里,定义如下(209行开始)

/*
 * The journal superblock. All fields are in big-endian byte order.
 */

typedef struct journal_superblock_s
{
/* 0x0000 */
    journal_header_t s_header;

/* 0x000C */
    /* Static information describing the journal */
    __be32    s_blocksize;        /* journal device blocksize */
    __be32    s_maxlen;        /* total blocks in journal file */
    __be32    s_first;        /* first block of log information */

/* 0x0018 */
    /* Dynamic information describing the current state of the log */
    __be32    s_sequence;        /* first commit ID expected in log */
    __be32    s_start;        /* blocknr of start of log */

/* 0x0020 */
    /* Error value, as set by jbd2_journal_abort(). */
    __be32    s_errno;

/* 0x0024 */
    /* Remaining fields are only valid in a version-2 superblock */
    __be32    s_feature_compat;    /* compatible feature set */
    __be32    s_feature_incompat;    /* incompatible feature set */
    __be32    s_feature_ro_compat;    /* readonly-compatible feature set */
/* 0x0030 */
    __u8    s_uuid[16];        /* 128-bit uuid for journal */

/* 0x0040 */
    __be32    s_nr_users;        /* Nr of filesystems sharing log */

    __be32    s_dynsuper;        /* Blocknr of dynamic superblock copy*/

/* 0x0048 */
    __be32    s_max_transaction;    /* Limit of journal blocks per trans.*/
    __be32    s_max_trans_data;    /* Limit of data blocks per trans. */

/* 0x0050 */
    __u32    s_padding[44];

/* 0x0100 */
    __u8    s_users[16*48];        /* ids of all fs'es sharing the log */
/* 0x0400 */
} journal_superblock_t;

正好是0x400=1024字节,如果不等于1024字节,那当然就出错了。接下来调用了一个journal_init_caches(),这个函数所做功能就是初化jbd2所需要的cache,这里先放下,以后再慢慢说,不管怎么样,这个函数如果成功就反回0,否返回非0,一般是负数,当然也有些函数不是返回0表示成功,而是返回一个有效的指针地址;还有一些十分变态的函数,返回非0表示成功,等遇到这样的函数我再狠狠的骂它一顿。

如果journal_init_caches()返回0,那就执行 jbd2_create_debugfs_entry()jbd2_create_jbd_stats_proc_entry()当然,在release版本中,jbd2_create_debugfs_entry()是一个空函数,它只是为了调试用的,一调试完成,它也就没有用了,卸磨杀驴不是很多人惯用的招数么?那么jbd2_create_jbd_stats_proc_entry()又做的是什么呢?我们还是来看看它的代码(journal.c/2285)

 

#ifdef CONFIG_PROC_FS

#define JBD2_STATS_PROC_NAME "fs/jbd2"

static void __init jbd2_create_jbd_stats_proc_entry(void)
{
    proc_jbd2_stats = proc_mkdir(JBD2_STATS_PROC_NAME, NULL);
}

static void __exit jbd2_remove_jbd_stats_proc_entry(void)
{
    if (proc_jbd2_stats)
        remove_proc_entry(JBD2_STATS_PROC_NAME, NULL);
}

#else

#define jbd2_create_jbd_stats_proc_entry() do {} while (0)
#define jbd2_remove_jbd_stats_proc_entry() do {} while (0)

#endif

一看它的名字都能知道,其实它是在linux系统里的/proc/fs创建一个目录叫jbd2.如果你的系统有分区是ext4系统,那么就会看到

lan@lan-laptop:~$ ls /proc/fs

ext4 jbd2 nfsd

那个jbd2目录就是这个函数的功劳。这里也能看到jbd2_remove_jbd_stats_proc_entry(void)这个函数,它就负责把这目录在jbd2卸载的时候把这个目录删除的,同时你也看到#ifdef CONFIG_PROC_FS这个宏,这个宏开表示我们的系统要/proc这个文件系统,如果没有开,那么就不会有/proc这个目录,更不会有fs/jbd2,所以在#else后的函数是空实现。

如果journal_init_caches()返回一个非0,就会执行jbd2_journal_destroy_caches();
来清除(可能)已经创建的cache.然后把ret返回,因为是非0,所以系统就知道这个模块在初始化的时候出错,就不会把模块调起来。

阅读(5863) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~