struct page数据结构成员flags定义了一个标志位PG_locked,内核利用PG_locked来设置一个页面锁。lock_page()函数用于申请页面锁,如果页面锁被其他进程占用了,那么会睡眠等待。
[include/linux/pagemap.h]
/*
* lock_page may only be called if we have the page's inode pinned.
*/
static inline void lock_page(struct page *page)
{
might_sleep();
if (!trylock_page(page))
__lock_page(page);
}
[mm/filemap.c]
/**
* __lock_page - get a lock on the page, assuming we need to sleep to get it
* @page: the page to lock
*/
void __lock_page(struct page *page)
{
DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
__wait_on_bit_lock(page_waitqueue(page), &wait, bit_wait_io,
TASK_UNINTERRUPTIBLE);
}
trylock_page()和lock_page()这两个函数看起来很相似,但有很大的区别。trylock_page()定义在include/linux/pagemap.h文件中,它使用test_and_set_bit_lock()去尝试为page的flags设置PG_locked标志位,并且返回原来标志位的值。如果page的PG_locked位已经置位了,那么当前进程调用trylock_page()返回false,说明有其他进程已经锁住了page。因此trylock_page()返回false表示获取锁失败,返回true表示获取锁成功。
static inline int trylock_page(struct page *page)
{
return (likely(!test_and_set_bit_lock(PG_locked, &page->flags)));
}
[include/asm-generic/bitops/lock.h]
/**
* test_and_set_bit_lock - Set a bit and return its old value, for lock
* @nr: Bit to set
* @addr: Address to count from
*
* This operation is atomic and provides acquire barrier semantics.
* It can be used to implement bit locks.
*/
#define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr)