set_buffer_dirty的源码在哪?怎么理解?

都一个月没更新了,因为放了两个多星期假,然后回来也准备了下实验室年会的报告,现在终于事情都完了,回归正途~

在看关于将buffer置为脏页的时候,我们是看到如下,也就是根本跟不进他在哪里


当然,我们从他的含义上是知道他是做了什么事情的,但是就是心里痒痒不知道他究竟是怎么做的?为什么不是以一个函数出现的呢?(因为如果是函数当然可以跟进去),那么一种情况就是可能是以宏的形式出现。那么我们就尝试在跟buffer有关的文件中找一下。可以在/include/linux/buffer_head.h中在对struct buffer_head的定义后有对buffer_head中的b_state字段做了解释的:

enum bh_state_bits {
	BH_Uptodate,	/* Contains valid data */
	BH_Dirty,	/* Is dirty */
	BH_Lock,	/* Is locked */
	BH_Req,		/* Has been submitted for I/O */
	BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
			  * IO completion of other buffers in the page
			  */

	BH_Mapped,	/* Has a disk mapping */
	BH_New,		/* Disk mapping was newly created by get_block */
	BH_Async_Read,	/* Is under end_buffer_async_read I/O */
	BH_Async_Write,	/* Is under end_buffer_async_write I/O */
	BH_Delay,	/* Buffer is not yet allocated on disk */
	BH_Boundary,	/* Block is followed by a discontiguity */
	BH_Write_EIO,	/* I/O error on write */
	BH_Ordered,	/* ordered write */
	BH_Eopnotsupp,	/* operation not supported (barrier) */
	BH_Unwritten,	/* Buffer is allocated on disk but not written */
	BH_Quiet,	/* Buffer Error Prinks to be quiet */
	BH_Meta,     //fangxj2
	BH_PrivateStart,/* not a state bit, but the first bit available
			 * for private allocation by other entities
			 */
};
该字段表示了buffer的状态的,在后面我们又看到:

#define BUFFER_FNS(bit, name)						\
static inline void set_buffer_##name(struct buffer_head *bh)		\
{									\
	set_bit(BH_##bit, &(bh)->b_state);				\
}									\
static inline void clear_buffer_##name(struct buffer_head *bh)		\
{									\
	clear_bit(BH_##bit, &(bh)->b_state);				\
}									\
static inline int buffer_##name(const struct buffer_head *bh)		\
{									\
	return test_bit(BH_##bit, &(bh)->b_state);			\
}

/*
 * test_set_buffer_foo() and test_clear_buffer_foo()
 */
#define TAS_BUFFER_FNS(bit, name)					\
static inline int test_set_buffer_##name(struct buffer_head *bh)	\
{									\
	return test_and_set_bit(BH_##bit, &(bh)->b_state);		\
}									\
static inline int test_clear_buffer_##name(struct buffer_head *bh)	\
{									\
	return test_and_clear_bit(BH_##bit, &(bh)->b_state);		\
}									\

很有意思吧?首先我们要先知道 在#define中“##”这是表示字符的连接的,就像  #define M(x) a##x+#c 如果我们使用 M (mm) 那么在预编译时候是变成了 ammc 。好的,稍微有点经验的应该明白 那这里用该就是 当我们调用了set_bufer_dirty 那就是将这上面定义的set_buffer_##name 中的name用我们的dirty替换为dirty.那么为什么调用时候不是调用宏BUFFER_FNS呢?另外,为什么在函数体中

 set_bit(BH_##bit, &(bh)->b_state);

为什么不是 BH_##name 而是BH_##bit呢? 确实,这里用name的话也是不对,看上面的你枚举类型如果这里是##name的话那么我应该是调用set_buffer_Dirty而不是set_buffer_dirty。那么肯定还存在一个bit与name的转化换,将name如果是dirty转成Dirty。

所以接着又看到了:

BUFFER_FNS(Uptodate, uptodate)
BUFFER_FNS(Dirty, dirty)
TAS_BUFFER_FNS(Dirty, dirty)
BUFFER_FNS(Lock, locked)
BUFFER_FNS(Req, req)
TAS_BUFFER_FNS(Req, req)
BUFFER_FNS(Mapped, mapped)
BUFFER_FNS(New, new)
BUFFER_FNS(Async_Read, async_read)
BUFFER_FNS(Async_Write, async_write)
BUFFER_FNS(Delay, delay)
BUFFER_FNS(Boundary, boundary)
BUFFER_FNS(Write_EIO, write_io_error)
BUFFER_FNS(Ordered, ordered)
BUFFER_FNS(Eopnotsupp, eopnotsupp)
BUFFER_FNS(Unwritten, unwritten)
所以这时候结果出来了!!

我们知道宏在预编译时候要进行替换,那么在预编译时候,上面的这一系列宏都被展开。那么结果应该就是对于第一个BUFFER_FNS(Update,update) 就是将上面的三个函数的bit用Update替换,对name用update替换。也就是:

static inline void set_buffer_update(struct buffer_head *bh)		\
{									\
	set_bit(BH_Update, &(bh)->b_state);				\
}									\
static inline void clear_buffer_update (struct buffer_head *bh)		\
{									\
	clear_bit(BH_Update, &(bh)->b_state);				\
}									\
static inline int buffer_update (const struct buffer_head *bh)		\
{									\
	return test_bit(BH_Update, &(bh)->b_state);			\
}

同样,同样对于第二个,BUFFER_FNS(Dirty,dirty) 也一样,变成了:

static inline void set_buffer_dirty(struct buffer_head *bh)		\
{									\
	set_bit(BH_Dirty, &(bh)->b_state);				\
}									\
static inline void clear_buffer_dirty (struct buffer_head *bh)		\
{									\
	clear_bit(BH_Dirty, &(bh)->b_state);				\
}									\
static inline int buffer_dirty (const struct buffer_head *bh)		\
{									\
	return test_bit(BH_Dirty, &(bh)->b_state);			\
}

依次类推,那么在预编译后,实际上根据这个BUFFER_FNS也就产生了 3*15=45个函数的!!

是不是有一次对linux 代码的巧妙性又叹服了一次。这样既使得代码量少了(所以说高质量的代码让你用几行的代码实现人家重复的40几行的功能),另一个就是扩展性好。如果我在Buffer_head的state中想要增加其他的信息,我只要在他的枚举中加入,例如我加入一个BH_Meta,然后再加入一个BUFFER_FND(Meta,meta) 就OK了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值