内存换出和缓冲区释放( 二 )


2.2缓冲区的老化
缓冲区的老化,从目前看的代码主要有三种情形:
1.通过/ 初次读写时
do_generic_file_read-->__add_to_page_cache-->lru_cache_addgeneric_file_write-->__grab_cache_page-->add_to_page_cache_unique-->__add_to_page_cache-->lru_cache_addlru_cache_add{...add_page_to_active_list(page);//这里作者说age为0的情况很少产生,估计是因为内存是脏的/* This should be relatively rare */if (!page->age)deactivate_page_nolock(page);...}
2.通过/ 再次读写时
do_generic_file_read-->__find_page_nolock-->age_page_upgeneric_file_write-->__grab_cache_page-->__find_lock_page-->__find_page_nolock-->age_page_upage_page_up{if (!page->age)activate_page(page);/* The actual page aging bit */page->age += PAGE_AGE_ADV;if (page->age > PAGE_AGE_MAX)page->age = PAGE_AGE_MAX;}
3.通过block号读写缓冲区时:
getblk-->touch_buffer//设置标志位,然后在refill_inactive_scan中递增age#define touch_buffer(bh) SetPageReferenced(bh->b_page)
前两种方式主要是VFS在用,第三种方式主要是具体的文件系统(例如 ext2)用 。
3.-->
当age在中减到0之后,page就彻底老化,需要将其和硬盘关联 。所以linux对下面变量做了抽象:
page.index:page在盘(或者inode)内的页面偏移
:page到盘(或者inode)的映射,在这个结构体中记录了页面是否clean/dirty/,并且有将页面写入/读出的方法 。另外;对于普通内存来说是,对于ext2缓冲区是inode.(实体是inode.,操作方法是) 。
3.1普通内存
普通内存在(或者)中将page.age递减置0,会在将pte和page的映射断开,之后如果进程需要通过MMU访问内存,需要通过,然后在hash表中查找重新建立映射了 。
refill_inactive-->swap_out-->swap_out_mm-->swap_out_vma-->swap_out_pgd-->swap_out_pmd-->try_to_swap_outtry_to_swap_out{...//这里pte被写0,所有后面!pte_dirty(pte)跳到drop_pte时是0pte = ptep_get_and_clear(page_table);flush_tlb_page(vma, address);//初次进来,这个标志没置if (PageSwapCache(page)) {entry.val = page->index;if (pte_dirty(pte))set_page_dirty(page);set_swap_pte:swap_duplicate(entry);set_pte(page_table, swp_entry_to_pte(entry));drop_pte:UnlockPage(page);mm->rss--;//将page放入到inactive_ditry_listdeactivate_page(page);page_cache_release(page);out_failed:return 0;}...//虚拟内存和物理内存映射一般是在do_page_fault中建立,出现写时复制或者swap时,如果vma有write_access,会pte_mkdirty 。//有两种情况没dirty:1.这个pte没被写过,被映射到零页,直接释放pte,在do_page_fault时在重新申请0页2.如果这个页面是通过mmap,可以通过do_page_fault从硬盘中读取(另外pipe不是这种情况,因为pipe是通过file--inode的机制去访问page而不是MMU)if (!pte_dirty(pte))goto drop_pte;/** Ok, it's really dirty. That means that* we should either create a new swap cache* entry for it, or we should write it back* to its own backing store.*///通过mmap建立映射,set_page_dirty将page加入到address_space的脏队列中,之后通过同步写入因硬盘if (page->mapping) {set_page_dirty(page);goto drop_pte;}/** This is a dirty, swappable page.First of all,* get a suitable swap entry for it, and make sure* we have the swap cache set up to associate the* page with that swap entry.*///这里是MMU首次老化的内存entry = get_swap_page();if (!entry.val)goto out_unlock_restore; /* No swap space left *//* Add it to the swap cache and mark it dirty *///将page和swap_space映射,将其加入其脏队列中,并添加置address_space和page.index组成的hash表中 。//然后将pte设置成交换盘的索引,以便do_page_fault时能从hash表或者硬盘中读入add_to_swap_cache(page, entry);set_page_dirty(page);goto set_swap_pte;...}

内存换出和缓冲区释放