如果你顺着上一篇的线索去读
mark_buffer_dirty
的实现会很困惑,因为很多“函数”的定义找不到。
非显式定义宏
有些函数、变量或类型的名字不是直接写出来的,而是用宏的##
符号定义出来的,这意味着这些名字在定义的地方可以不出现,如果你不知道的话,就很难找到他们的定义。
mark_buffer_dirty
[kernel/fs/buffer.c]这个函数看起来不长,但是里面有好几个东西找不到的定义,包括buffer_uptodate
,buffer_dirty
,test_set_buffer_dirty
,TestSetPageDirty
。
void mark_buffer_dirty(struct buffer_head *bh)
{
WARN_ON_ONCE(!buffer_uptodate(bh));
trace_block_dirty_buffer(bh);
/*
* Very *carefully* optimize the it-is-already-dirty case.
*
* Don't let the final "is it dirty" escape to before we
* perhaps modified the buffer.
*/
if (buffer_dirty(bh)) {
smp_mb();
if (buffer_dirty(bh))
return;
}
if (!test_set_buffer_dirty(bh)) {
struct page *page = bh->b_page;
if (!TestSetPageDirty(page)) {
struct address_space *mapping = page_mapping(page);
if (mapping)
__set_page_dirty(page, mapping, 0);
}
}
}
buffer_uptodate
事实上名字叫做buffer_uptodate
的函数是存在的,它在kernel/include/linux/buffer_head.h里面
#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); \
}
//...
BUFFER_FNS(Uptodate, uptodate)
将宏展开就是
static inline void set_buffer_uptodate(struct buffer_head *bh)
{
set_bit(BH_Uptodate, &(bh)->b_state);
}
static inline void clear_buffer_uptodate(struct buffer_head *bh)
{
clear_bit(BH_Uptodate, &(bh)->b_state);
}
static inline int buffer_uptodate(const struct buffer_head *bh)
{
return test_bit(BH_Uptodate, &(bh)->b_state);
}
buffer_dirty
同上,将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);
}
test_set_buffer_dirty
也是一样的
#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); \
}
//...
TAS_BUFFER_FNS(Dirty, dirty)
展开TAS_BUFFER_FNS(Dirty, dirty)
得
static inline int test_set_buffer_dirty(struct buffer_head *bh)
{
return test_and_set_bit(BH_Dirty, &(bh)->b_state);
}
static inline int test_clear_buffer_dirty(struct buffer_head *bh)
{
return test_and_clear_bit(BH_Dirty, &(bh)->b_state);
}
TestSetPageDirty
它的定义可以从kernel/include/linux/page-flags.h找到,线索如下
#define TESTSETFLAG(uname, lname) \
static inline int TestSetPage##uname(struct page *page) \
{ return test_and_set_bit(PG_##lname, &page->flags); }
//...
TESTSETFLAG(Dirty, dirty)
都是一个套路,我就不展开了。
遇到这种情况,如果猜它是非显式定义的宏,还是有一点办法的,例如可以把名字拆开,然后搜索那个名字。例如
TestSetPageDirty
的形式是TestSetPagexxxx,前面的TestSetPage部分看起来是不变的,所以搜它就可以找到上面这个线索。
网友评论