都一個月沒更新了,因爲放了兩個多星期假,然後回來也準備了下實驗室年會的報告,現在終於事情都完了,迴歸正途~
在看關於將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了!