- 论坛徽章:
- 0
|
上一节,我们讲了怎么初始化journal对像和日志分区的检查,其中说到一个函数
journal = jbd2_journal_init_dev(bdev, sb->s_bdev, start, len, blocksize);
这个函数就是初始化日志分区的。
上面的参数依次是:日志分区描述结构体,主分区描述结构体,主分区数据起始的block编号,主分区的bock数,和主分区的block的大小。
这个函数的实现在fs/jbd2/journal.c(1036)
/* jbd2_journal_init_dev and jbd2_journal_init_inode:
*
* Create a journal structure assigned some fixed set of disk blocks to
* the journal. We don't actually touch those disk blocks yet, but we
* need to set up all of the mapping information to tell the journaling
* system where the journal blocks are.
*
*/
/* jbd2_journal_init_dev 和 jbd2_journal_init_inode的功能都是一样的,
就是创建journal结构体,并且给它一些固定的成员赋值,主要是主分区的
一些信息。我们并没有进行实际的硬盘读写操作,只是让日志系统知道真正
的日志信息数据块在哪里。
*/
/** 下面这段就不翻译了,日志开始已经过过这些参数的意思了。
* journal_t * jbd2_journal_init_dev() - creates and initialises a journal structure
* @bdev: Block device on which to create the journal
* @fs_dev: Device which hold journalled filesystem for this journal.
* @start: Block nr Start of journal.
* @len: Length of the journal in blocks.
* @blocksize: blocksize of journalling device
*
* Returns: a newly created journal_t *
*
* jbd2_journal_init_dev creates a journal which maps a fixed contiguous
* range of blocks on an arbitrary block device.
*
*/
journal_t * jbd2_journal_init_dev(struct block_device *bdev,
struct block_device *fs_dev,
unsigned long long start, int len, int blocksize)
{
// 给journal_t结构体分配空间,并初始化一些成员变量,主要是等待列表
// 和一些固定的东西,它的实现在journal.c(971)行,那里面有两个函数要
// 简单说明一下,jbd2_journal_init_revoke:这个函数创建和初始化这个
// 日志的撤销表,就是当一个数据块已经正确写到主设备上了,就要把这块
// 数据从日志系统中删除,因为不是立即删除,所以要放在一个表里,等待。
// 还有另一个函数是journal_init_stats:这个函数初始化journal的状态,
// 并创建一个历史列表来记录100个已经完成了的transaction.
journal_t *journal = journal_init_common();
struct buffer_head *bh;
char *p;
int n;
if (!journal)
return NULL;
/* journal descriptor can store up to n blocks -bzzz */
journal->j_blocksize = blocksize; // 记录主分区的block大小。
//初始化主分区在/proc/fs/jbd2/sdax 的目录和里面的info,history.
jbd2_stats_proc_init(journal);
// 计算一个block里能在放多少个buffer_head的描述符。并创建相应个数的
// buffer_head的指针空间。
n = journal->j_blocksize / sizeof(journal_block_tag_t);
journal->j_wbufsize = n;
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
if (!journal->j_wbuf) {
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
__func__);
goto out_err;
}
journal->j_dev = bdev;
journal->j_fs_dev = fs_dev;
journal->j_blk_offset = start;
journal->j_maxlen = len;
/* 下面就是根据主分区来生成日志的名字,就是设备名加分区名,如“sda8”
*/
bdevname(journal->j_dev, journal->j_devname);
p = journal->j_devname;
while ((p = strchr(p, '/')))
*p = '!';
// 从日志分区的第一个数据块读出一个块的数据。这个块就是日志分区的
// super_block,当然实际名称是journal_superblock_t,定义在include/
// linux/jbd2.h(212)
bh = __getblk(journal->j_dev, start, journal->j_blocksize);
if (!bh) {
printk(KERN_ERR
"%s: Cannot get buffer for journal superblock\n",
__func__);
goto out_err;
}
journal->j_sb_buffer = bh;
journal->j_superblock = (journal_superblock_t *)bh->b_data;
return journal;
out_err:
jbd2_stats_proc_exit(journal);
kfree(journal);
return NULL;
}
接下来我们再看看jbd2_stats_proc_init,其定义在journal.c(927)
/*这个函数就是这么寥寥几行,真让人怀疑它的能力,但你有所不知道,往往最简单的东西
后面却暗藏着玄机,或叫什么冰山一角之类的吧。且让我说说它的功能。确实很简单,就
是在/proc/fs/jbd2目录下根据设备号生成的名称创建一个目录,比如sda8:8(因为我的机器 没有独立分区来记录易日志,而是一个目录,所以在sda8后加了一个8,表示这个分区里的第8个inode是用来记录日志的,相关代码在journal.c/1112),关于里面的proc_jbd2_stats这个变量如果你的大脑内存比较大应该还记得在journal_init函数里有一个
jbd2_create_jbd_stats_proc_entry吧,就是在那创建的这个目录。这里再深入就涉及/proc文件系统了,但是/proc系统作为内核对外层应该的一个窗口,我就不得不哆嗦几句了。创建了相应的目录后,再创建两个文件,一个是history,一个是info,到这里,应该怎么第三节里讲的那两个文件是怎么来的了吧,至于怎么显示出那些信息来的,放在下节讲吧,哥们累了,要睡了Zzzz*/
static void jbd2_stats_proc_init(journal_t *journal)
{
journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats);
if (journal->j_proc_entry) {
proc_create_data("history", S_IRUGO, journal->j_proc_entry,
&jbd2_seq_history_fops, journal);
proc_create_data("info", S_IRUGO, journal->j_proc_entry,
&jbd2_seq_info_fops, journal);
}
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/95949/showart_2050037.html |
|