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了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章