init&lock_page
时间:2007-06-11 来源:zixin
通过上面的讨论,已经涉及了本文件的诸多函数,这里对已经有说明的文件
一笔带过,对感兴趣的,做个分析注解.
头六个函数就不多说了,见上面的分析.
(1) page cache 初始化
/*
* mempages: 物理页面个数
*/
void __init page_cache_init(unsigned long mempages)
{
unsigned long htable_size, order;
/*计算要为hash 表分配多少内存, 及其order值(power of 2)*/
htable_size = mempages;
htable_size *= sizeof(struct page *);
for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
;
*计划分配一个能容下所有物理页的hash表,就看又没内存*/
do {
/*这个order能够容下的page个数数*/
unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
/*计算这么大的表对应的hash值(hash表下标)最多有多少位*/
page_hash_bits = 0;
while((tmp >>= 1UL) != 0UL)
page_hash_bits++;
page_hash_table = (struct page **) /*看看有没有这么多连续内存*/
__get_free_pages(GFP_ATOMIC, order);
} while(page_hash_table == NULL && --order > 0);/*没有的话尝试少分点*/
printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
(1 << page_hash_bits), order, (PAGE_SIZE << order));
if (!page_hash_table)
panic("Failed to allocate page hash table\n");
memset((void *)page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
}
(2) TryLockPage,lock_page和UnlockPage
static inline int sync_page(struct page *page)
逻辑简单,调用mapping->a_ops->sync_page(page),对于ext2就是ext2_aops
->block_sync_page->run_task_queue(&tq_disk)(fs/buffer.c).让磁盘有更多
机会运行回写,读入等任务.提供给 ___wait_on_page,__lock_page使用.
/*
* Wait for a page to get unlocked.
*
* This must be called with the caller "holding" the page,
* ie with increased "page->count" so that the page won't
* go away during the wait..
*/
void ___wait_on_page(struct page *page)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
add_wait_queue(&page->wait, &wait);
do {
sync_page(page); /*给磁盘(may be other dev)一点运行机会
*说不定就不用再等了
*/
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!PageLocked(page))
break;
run_task_queue(&tq_disk);/**/
schedule();
} while (PageLocked(page));
tsk->state = TASK_RUNNING;
remove_wait_queue(&page->wait, &wait);
}
也没有什么可以多说的,等待页面解锁时给页面同步相关的task queue多些运行
时间. void lock_page(struct page *page)和static void __lock_page(struct
page *page)同此函数.
include/linux/mm.h定义了
#define UnlockPage(page) do { \
smp_mb__before_clear_bit(); \
if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
smp_mb__after_clear_bit(); \
if (waitqueue_active(&page->wait)) \
wake_up(&page->wait); \
} while (0)
并且注释也说明了两个barrier的作用,
当用
TryLockPage
......
UnlockPage
组成一个临界区的时候,第一个barrier保证test_and_clear_bit在
test_and_set_bit之后执行,第二个barrier保证test_and_clear_bit和访问
wait_queue的次序.
问题是如何使用lock_page, UnlockPage,使用时机是什么?内核注释为"在进
行page上的IO操作时必须lock_page",这种解释有些简略.正在进行io的页面有如
下特征(几个典型情况):
1)如果页面归user space的进程使用,肯定是swap cache在进行io操作,并且页
面已经从用户的页表断开.
2)如果是user task进行文件读写操作,启动io的页面是page cache(normal file)
或者buffer cache.
3)如果是mmap,读写亦通过page cache进行.
4)首先page io在大部分情况下是一个异步操作,kernel不会"停下来"等待磁盘
操作的完成. 如典型的page fault需要换入时,新分配一个页面,加入swap
cache,启动io,最后当前进程wait on page.有可能内核处理swap的几个线程
会访问到此页,此种情况下需要进行互斥操作,不能在一个页面上启动两个io
操作.
5)或者SMP的情况下,一边进行io换入,另一个cpu也可以进行lru操作.
我相信作者一开始的时候准备用page lock这个机制防止对page io的重入.
但是此锁还同步了更多的东西:
看加入swap cache的情况:
void add_to_swap_cache(struct page *page, swp_entry_t entry)
{
unsigned long flags;
#ifdef SWAP_CACHE_INFO
swap_cache_add_total++;
#endif
if (!PageLocked(page)) //如果页面未锁,禁止加入swap cache
一笔带过,对感兴趣的,做个分析注解.
头六个函数就不多说了,见上面的分析.
(1) page cache 初始化
/*
* mempages: 物理页面个数
*/
void __init page_cache_init(unsigned long mempages)
{
unsigned long htable_size, order;
/*计算要为hash 表分配多少内存, 及其order值(power of 2)*/
htable_size = mempages;
htable_size *= sizeof(struct page *);
for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
;
*计划分配一个能容下所有物理页的hash表,就看又没内存*/
do {
/*这个order能够容下的page个数数*/
unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
/*计算这么大的表对应的hash值(hash表下标)最多有多少位*/
page_hash_bits = 0;
while((tmp >>= 1UL) != 0UL)
page_hash_bits++;
page_hash_table = (struct page **) /*看看有没有这么多连续内存*/
__get_free_pages(GFP_ATOMIC, order);
} while(page_hash_table == NULL && --order > 0);/*没有的话尝试少分点*/
printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
(1 << page_hash_bits), order, (PAGE_SIZE << order));
if (!page_hash_table)
panic("Failed to allocate page hash table\n");
memset((void *)page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
}
(2) TryLockPage,lock_page和UnlockPage
static inline int sync_page(struct page *page)
逻辑简单,调用mapping->a_ops->sync_page(page),对于ext2就是ext2_aops
->block_sync_page->run_task_queue(&tq_disk)(fs/buffer.c).让磁盘有更多
机会运行回写,读入等任务.提供给 ___wait_on_page,__lock_page使用.
/*
* Wait for a page to get unlocked.
*
* This must be called with the caller "holding" the page,
* ie with increased "page->count" so that the page won't
* go away during the wait..
*/
void ___wait_on_page(struct page *page)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
add_wait_queue(&page->wait, &wait);
do {
sync_page(page); /*给磁盘(may be other dev)一点运行机会
*说不定就不用再等了
*/
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!PageLocked(page))
break;
run_task_queue(&tq_disk);/**/
schedule();
} while (PageLocked(page));
tsk->state = TASK_RUNNING;
remove_wait_queue(&page->wait, &wait);
}
也没有什么可以多说的,等待页面解锁时给页面同步相关的task queue多些运行
时间. void lock_page(struct page *page)和static void __lock_page(struct
page *page)同此函数.
include/linux/mm.h定义了
#define UnlockPage(page) do { \
smp_mb__before_clear_bit(); \
if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
smp_mb__after_clear_bit(); \
if (waitqueue_active(&page->wait)) \
wake_up(&page->wait); \
} while (0)
并且注释也说明了两个barrier的作用,
当用
TryLockPage
......
UnlockPage
组成一个临界区的时候,第一个barrier保证test_and_clear_bit在
test_and_set_bit之后执行,第二个barrier保证test_and_clear_bit和访问
wait_queue的次序.
问题是如何使用lock_page, UnlockPage,使用时机是什么?内核注释为"在进
行page上的IO操作时必须lock_page",这种解释有些简略.正在进行io的页面有如
下特征(几个典型情况):
1)如果页面归user space的进程使用,肯定是swap cache在进行io操作,并且页
面已经从用户的页表断开.
2)如果是user task进行文件读写操作,启动io的页面是page cache(normal file)
或者buffer cache.
3)如果是mmap,读写亦通过page cache进行.
4)首先page io在大部分情况下是一个异步操作,kernel不会"停下来"等待磁盘
操作的完成. 如典型的page fault需要换入时,新分配一个页面,加入swap
cache,启动io,最后当前进程wait on page.有可能内核处理swap的几个线程
会访问到此页,此种情况下需要进行互斥操作,不能在一个页面上启动两个io
操作.
5)或者SMP的情况下,一边进行io换入,另一个cpu也可以进行lru操作.
我相信作者一开始的时候准备用page lock这个机制防止对page io的重入.
但是此锁还同步了更多的东西:
看加入swap cache的情况:
void add_to_swap_cache(struct page *page, swp_entry_t entry)
{
unsigned long flags;
#ifdef SWAP_CACHE_INFO
swap_cache_add_total++;
#endif
if (!PageLocked(page)) //如果页面未锁,禁止加入swap cache
相关阅读 更多 +