文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>init&lock_page

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
相关阅读 更多 +
排行榜 更多 +
特技摩托挑战(wheelie challenge)

特技摩托挑战(wheelie challenge)

赛车竞速 下载
创造世界游戏

创造世界游戏

冒险解谜 下载
终极躲避球

终极躲避球

休闲益智 下载