📄 022_mm_swapfile_c.html
字号:
flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_63cqjcn5t9:4"> <table align=center cellpadding=0 cellspacing=0 height=5716 width=768>
<tbody>
<tr>
<td height=5716 valign=top width=100%>
<pre>2006-8-9 <br>mm/swapfile.c<br><br> linux可以指定交换分区也可以指定交换文件(专门的分区效率高). 交换设备分为两种:块<br>设备和交换文件. <br> 这里交换设备是交换用的设备文件和普通文件的通称,希望不要引起混淆.每个交换设备在<br>内核中都有一个swap_info_struct与之对应:<br><br>struct swap_info_struct {<br> unsigned int flags;<br> kdev_t swap_device;<br> spinlock_t sdev_lock;<br> struct dentry * swap_file;<br> struct vfsmount *swap_vfsmnt;<br> unsigned short * swap_map; /*记录交换设备上page 的引用计数(SWAP_MAP_MAX)*/<br> /* 数组大小为this->max */<br><br> /*按簇分配算法变量,一个簇包含SWAPFILE_CLUSTER 个页面 */<br> unsigned int lowest_bit; /* 和highest_bit一起构成有可能空闲的页面的索引范围*/<br> unsigned int highest_bit;<br> unsigned int cluster_next; /*swap cluster 中下一个可分配页面*/<br> unsigned int cluster_nr; /*本簇内剩余页面数量*/<br><br> int prio; /* swap priority ,数值小的在swap list中靠前 */<br> int pages; /*nr_good_pages*/<br> unsigned long max; /*来自swap_header 的last_page(和),见sys_swapon*/<br> int next; /* next entry on swap list */<br>};<br> <br> 这个结构保存存在一个数组:<br>struct swap_info_struct swap_info[MAX_SWAPFILES];<br><br> 所有可用的swap设备按照优先级从高到低组成一个链表,其表头是:<br> struct swap_list_t swap_list = {-1, -1};<br> <br> 这是一个存储在数组中的链表,next域是整数,-1代表空指针.<br>struct swap_list_t {<br> int head; /* head of priority-ordered swapfile list */<br> int next; /* swapfile to be used next */<br>};<br> head就是表头,优先级最高. swap_list.next指向下次分配swap page页面时应优先考虑的<br>swap设备.<br><br> 系统中可能存在几个swap设备,优先级可能不同,也可能相同.分配swap page的时候在最高<br>优先级的swap设备中轮换分配.只有当所有的高优先级的交换设备上的空间都耗尽了,才启用<br>低优先级的交换设备.<br> <br> 交换设备有一个固定的头,其大小是一个PAGE_SIZE. 2.4支持两种格式的swap设备:<br>union swap_header {<br> struct <br> {<br> char reserved[PAGE_SIZE - 10];<br> char magic[10]; /*version 1:"SWAP-SPACE" version 2:"SWAPSPACE2"*/<br> } magic;<br> struct <br> { /*version 2 使用的结构*/<br> char bootbits[1024]; /* Space for disklabel etc. */<br> unsigned int version; /*subversion, olny 1 now*/<br> unsigned int last_page; /* 交换设备上最后一个页面的nr*/<br> unsigned int nr_badpages;<br> unsigned int padding[125];<br> unsigned int badpages[1];<br> } info;<br>};<br>1)version 1<br> 结构很简单,swap header的末尾是10字节的version magic 字符,剩下的部分是一个位图,置<br>1的位对应的此交换换设备上的page可用.置1则不可用.<br><br>2)version 2<br> version 2中2.4只支持subversion(swap_hearder.info.version)为1的交换分区.相对于ver1<br>增加了几个有用的数据,比如最大页面号,等.其结构如下:<br> 预留1024字节用于disk label(引导扇区,赫赫,要从swap引导么!),然后跟着,subversion,最大<br>页面号,预留页面个数,pading,预留(bad page)数组.<br><br> 在一个交换设备内部,采用簇来管理分配,见swap_info_struct的相关数据.一个簇含有SWAPFILE_<br>CLUSTER(256)个页面. 每次分配的时候,尽量在当前簇中分配,如果失败,寻找下一个完整的空簇,如<br>还是失败,就放弃簇分配方式.<br><br> 簇分配算法的核心函数是:(注意一下簇分配所用到的swap info中的变量)<br>/*<br> * 从指定swap设备中分配swap page, 引用计数置为count<br> * 使用簇来减少碎片<br> */<br>static inline int scan_swap_map(struct swap_info_struct *si, unsigned short count)<br>{<br> unsigned long offset;<br> /*<br> * Cluster ---- 连续的SWAPFILE_CLUSTER 个空页面<br> */<br><br> /*<br> * [lowest_bit, highest_bit] 内也许可用<br> *<br> * 但此范围之外绝对不可用<br> */<br> /* <br> * We try to cluster swap pages by allocating them<br> * sequentially in swap. Once we've allocated<br> * SWAPFILE_CLUSTER pages this way, however, we resort to<br> * first-free allocation, starting a new cluster. This<br> * prevents us from scattering swap pages all over the entire<br> * swap partition, so that we reduce overall disk seek times<br> * between swap pages. -- sct */<br> if (si->cluster_nr) { //这个群中还剩余页面可以一试<br> while (si->cluster_next <= si->highest_bit) {<br> offset = si->cluster_next++;<br> if (si->swap_map[offset])<br> continue;<br> si->cluster_nr--;<br> goto got_page;<br> }<br> }<br> si->cluster_nr = SWAPFILE_CLUSTER;<br><br> /* try to find an empty (even not aligned) cluster. */<br> offset = si->lowest_bit; //从可分配处寻找一个群<br> check_next_cluster:<br> if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)<br> {<br> int nr; //群的始索引<br> for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)<br> if (si->swap_map[nr])<br> {<br> offset = nr+1;<br> goto check_next_cluster;<br> }<br> /* We found a completly empty cluster, so start<br> * using it.<br> */<br> goto got_page;<br> }<br> /* 不幸, 没有连续的空闲页, <br> * 只能缩小搜索粒度, 一页一页的看看有没有空闲页<br> * finegrined-----有细致的纹理的, 像篦子一样密<br> */<br> for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {<br> if (si->swap_map[offset])<br> continue;<br> got_page:<br> if (offset == si->lowest_bit)<br> si->lowest_bit++; //可分配范围调整<br> if (offset == si->highest_bit)<br> si->highest_bit--;<br> si->swap_map[offset] = count;<br> nr_swap_pages--;<br> si->cluster_next = offset+1; //页群中下一个准备分配的页面在<br> // swap_map 中的索引<br> return offset;<br> }<br> return 0;<br>}<br> <br><br> <br> swap设备轮换分配算法:<br>/*<br> * 尽量在高优先级的设备中分配swap 页面<br> * 并且在这些高级别的swap设备中轮换分配<br> * 分担io压力. 只有在高于当前级别的所有<br> * 设备都耗尽时才启用的优先级设备.<br> * <br> */<br>swp_entry_t __get_swap_page(unsigned short count)<br>{<br> struct swap_info_struct * p;<br> unsigned long offset;<br> swp_entry_t entry;<br> int type, wrapped = 0; /*wrapped:是否找遍所有的swap设备*/<br><br> entry.val = 0; /* Out of memory */<br> if (count >= SWAP_MAP_MAX)<br> goto bad_count;<br> swap_list_lock();<br> type = swap_list.next;<br> if (type < 0)<br> goto out;<br> if (nr_swap_pages == 0)<br> goto out;<br><br> while (1) {<br> p = &swap_info[type];<br> if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {<br> swap_device_lock(p);<br> offset = scan_swap_map(p, count);<br> swap_device_unlock(p);<br> if (offset) { <br> /* 分配成功,下一次在同(or high)优先级的下<br> *一个设备中分配swap entry*/<br> entry = SWP_ENTRY(type,offset);<br><br> type = swap_info[type].next;/*next*/<br> if (type < 0 || /*NULL*/ <br> p->prio != swap_info[type].prio ){/*优先级下降*/<br> swap_list.next = swap_list.head; /*从头开始*/<br> } else {<br> swap_list.next = type;<br> }<br> goto out;<br> }<br> }<br><br> /*当前设备, swap_list.head,空间耗尽*/<br> type = p->next; /*考察下一个设备*/<br><br> if (!wrapped) {<br> if (type < 0 || p->prio != swap_info[type].prio) {<br> type = swap_list.head; /*尽量使用高优先级设备*/<br> wrapped = 1;<br> }<br> } else/*高优先级的设备都耗尽才用低优先级设备*/<br> if (type < 0)/*全部耗尽*/<br> goto out; /* out of swap space */<br> }<br>out:<br> swap_list_unlock();<br> return entry;<br><br>bad_count:<br> printk(KERN_ERR "get_swap_page: bad count %hd from %p\n",<br> count, __builtin_return_address(0));<br> goto out;<br>}<br><br><br><br> 交换页面的释放算法就极为的简单了:__swap_free,代码略.<br> get_swaparea_info为proc文件系统提供数据,略.is_swap_partition,si_swapinfo,<br>swap_duplicate,swap_count,get_swaphandle_info等接口提供一些简单功能,不详细<br>介绍了.<br><br> int valid_swaphandles 在介绍sapin_readahead,的时候有提及.其功能是从cluster<br>边界开始,寻找一个连续可读取范围(无坏页,预留页,在使用中),并将引用计数增1.<br>/*<br> * Kernel_lock protects against swap device deletion. Grab an extra<br> * reference on the swaphandle so that it dos not become unused.<br> */<br> /*call from swapin_readahead*/<br>int valid_swaphandles(swp_entry_t entry, unsigned long *offset)<br>{<br> int ret = 0, i = 1 << page_cluster; /*一次预读一个cluster*/<br> unsigned long toff;<br> struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;<br><br> *offset = SWP_OFFSET(entry);<br> /*将预读设置到一个cluster的边界*/<br> toff = *offset = (*offset >> page_cluster) << page_cluster;<br><br> swap_device_lock(swapdev);<br> /*从cluster边界开始,寻找一个连续可读取范围*/<br> do {<br> <br> /* Don't read-ahead past the end of the swap area */<br> if (toff >= swapdev->max)<br> break;<br> /* Don't read in bad or busy pages */<br> if (!swapdev->swap_map[toff])<br> break;<br> if (swapdev->swap_map[toff] == SWAP_MAP_BAD)<br> break;<br> swapdev->swap_map[toff]++;<br> toff++;<br> ret++;<br> } while (--i);<br> swap_device_unlock(swapdev);<br> return ret;<br>}<br><br><br> 剩下的部分是系统调用,sys_swapon和sys_swapoff. swapon就是打开交换设备,建立swap<br>info结构,读取swap header以设置swap info.<br>/*<br> * Written 01/25/92 by Simmule Turner, heavily changed by Linus.<br> *<br> * The swapon system call<br> */<br>/*<br> * 加载swap 分区,或者启用swap 文件<br> */<br>asmlinkage long sys_swapon(const char * specialfile, int swap_flags)<br>{<br> struct swap_info_struct * p;<br> struct nameidata nd;<br> struct inode * swap_inode;<br> unsigned int type;<br> int i, j, prev;<br> int error;<br> static int least_priority = 0;<br> union swap_header *swap_header = 0;<br> int swap_header_version;<br> int nr_good_pages = 0;<br> unsigned long maxpages;<br> int swapfilesize;<br> struct block_device *bdev = NULL;<br> <br> if (!capable(CAP_SYS_ADMIN))<br> return -EPERM;<br> lock_kernel();<br><br> /*寻找空闲swap info,初始化swap info*/<br> .... //略<br> <br> if (swap_flags & SWAP_FLAG_PREFER) {/*指定了优先级*/<br> p->prio =<br> (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;<br> } else {<br> p->prio = --least_priority;<br> }<br><br> /*找到文件或者设备*/<br> error = user_path_walk(specialfile, &nd);<br> if (error)<br> goto bad_swap_2;<br><br> p->swap_file = nd.dentry;<br> p->swap_vfsmnt = nd.mnt;<br> swap_inode = nd.dentry->d_inode;<br> error = -EINVAL;<br><br> if (S_ISBLK(swap_inode->i_mode)) {/*真正的交换设备*/<br> kdev_t dev = swap_inode->i_rdev;<br> struct block_device_operations *bdops;<br><br> /*强制交换设备的block为PAGE_SIZE*/<br> p->swap_device = dev;<br> set_blocksize(dev, PAGE_SIZE);<br><br> /*打开交换设备*/<br> bdev = swap_inode->i_bdev;<br> bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode));<br> if (bdops) bdev->bd_op = bdops;<br><br> error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);<br> if (error)<br> goto bad_swap_2;<br> set_blocksize(dev, PAGE_SIZE);<br> <br> error = -ENODEV;<br> if (!dev || (blk_size[MAJOR(dev)] &&<br> !blk_size[MAJOR(dev)][MINOR(dev)]))<br> goto bad_swap;<br> error = -EBUSY;<br> /*是否已经是交换设备*/<br> for (i = 0 ; i < nr_swapfiles ; i++) {<br> if (i == type)<br> continue;<br> if (dev == swap_info[i].swap_device)<br> goto bad_swap;<br> }<br> swapfilesize = 0;<br> if (blk_size[MAJOR(dev)])<br> swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]<br> >> (PAGE_SHIFT - 10);/*blk_size 记录的大小是以1024为单位的*/<br> } else if (S_ISREG(swap_inode->i_mode)) {/*交换文件*/<br> error = -EBUSY;<br> for (i = 0 ; i < nr_swapfiles ; i++) {<br> if (i == type || !swap_info[i].swap_file)<br> continue;<br> if (swap_inode == swap_info[i].swap_file->d_inode)<br> goto bad_swap;<br> }<br> swapfilesize = swap_inode->i_size >> PAGE_SHIFT;<br> } else<br> goto bad_swap;<br><br> /*读入交换设备/文件的交换信息*/<br> swap_header = (void *) __get_free_page(GFP_USER);<br> if (!swap_header) {<br> printk("Unable to start swapping: out of memory :-)\n");<br> error = -ENOMEM;<br> goto bad_swap;<br> }<br><br> lock_page(virt_to_page(swap_header));<br> rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header, 1);<br><br> /*有两个版本的swap*/<br> if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))<br> swap_header_version = 1;<br> else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))<br> swap_header_version = 2;<br> else {<br> printk("Unable to find swap-space signature\n");<br> error = -EINVAL;<br> goto bad_swap;<br> }<br> <br> switch (swap_header_version) {<br> case 1:/*swap version 1*/<br> memset(((char *) swap_header)+PAGE_SIZE-10,0,10);/*clear magic*/<br> /*查找可使用swap 页面的范围和数量*/<br> j = 0;<br> p->lowest_bit = 0;<br> p->highest_bit = 0;<br> for (i = 1 ; i < 8*PAGE_SIZE ; i++) {<br> if (test_bit(i,(char *) swap_header)) {<br> if (!p->lowest_bit)<br> p->lowest_bit = i;<br> p->highest_bit = i;<br> p->max = i+1;<br> j++;<br> }<br> }<br> /*预留交换页面,设置mem map(引用技术)*/<br> nr_good_pages = j;<br> p->swap_map = vmalloc(p->max * sizeof(short));<br> if (!p->swap_map) {<br> error = -ENOMEM; <br> goto bad_swap;<br> }<br> for (i = 1 ; i < p->max ; i++) {<br> if (test_bit(i,(char *) swap_header))<br> p->swap_map[i] = 0;<br> else<br> p->swap_map[i] = SWAP_MAP_BAD;<br> }<br> break;<br><br> case 2: /*swap version 2*/<br> /* Check the swap header's sub-version and the size of<br> the swap file and bad block lists */<br> if (swap_header->info.version != 1) {<br> printk(KERN_WARNING<br> "Unable to handle swap header version %d\n",<br> swap_header->info.version);<br> error = -EINVAL;<br> goto bad_swap;<br> }<br> /*version 2的范围和数量有记录*/<br> p->lowest_bit = 1;<br> p->highest_bit = swap_header->info.last_page - 1;<br> p->max = swap_header->info.last_page;<br><br> maxpages = SWP_OFFSET(SWP_ENTRY(0,~0UL));<br> if (p->max >= maxpages)<br> p->max = maxpages-1;<br><br> error = -EINVAL;<br> if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)<br> goto bad_swap;<br> <br> /* OK, set up the swap map and apply the bad block list */<br> if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) {<br> error = -ENOMEM;<br> goto bad_swap;<br> }<br> /*查找预留页面即可*/<br> error = 0;<br> memset(p->swap_map, 0, p->max * sizeof(short));<br> for (i=0; i<swap_header->info.nr_badpages; i++) {<br> int page = swap_header->info.badpages[i];<br> if (page <= 0 || page >= swap_header->info.last_page)<br> error = -EINVAL;<br> else<br> p->swap_map[page] = SWAP_MAP_BAD;<br> }<br> nr_good_pages = swap_header->info.last_page -<br> swap_header->info.nr_badpages -<br> 1 /* header page */;<br> if (error) <br> goto bad_swap;<br> }<br> <br> ...... //检查,忽略<br> p->swap_map[0] = SWAP_MAP_BAD; /*第一个swap page是交换设备信息*/<br> p->flags = SWP_WRITEOK;<br> p->pages = nr_good_pages;<br> swap_list_lock();<br> nr_swap_pages += nr_good_pages;<br> printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",<br> nr_good_pages<<(PAGE_SHIFT-10), p->prio);<br><br> /* insert swap space into swap_list: */<br> prev = -1;<br> for (i = swap_list.head; i >= 0; i = swap_info[i].next) {<br> if (p->prio >= swap_info[i].prio) {<br> break;<br> }<br> prev = i;<br> }<br> p->next = i;<br> if (prev < 0) {<br> swap_list.head = swap_list.next = p - swap_info;<br> } else {<br> swap_info[prev].next = p - swap_info;<br> }<br> swap_list_unlock();<br> error = 0;<br> goto out;<br> ..........//失败时的clear工作,略<br> return error;<br>}<br><br><br> 相对swap on,swap off就复杂些. 关闭swap设备的时候需要将已经交换到swap设备上的页<br>面重新读入内存. 然后才能释放交换设备. <br> 思路是这样的: 只有user使用的页面才能够被swap out,内核自己使用的页面是不可以swap<br>out的,所以遍历用户的页目录,页表,逐项检查pte,如果是not in mem,并且是一个swap entry<br>则释放他.不过要遍历所有进程的页表.所以速度是不快的.<br> <br> 不过,内核使用的页面真的不能交换吗? maybe吧,不过特殊的是tmpfs(shmmem.c),从内核引<br>用了swap entry. 介绍shmem.c的时候已经提及过那个函数了:shmem_unuse.参考 shmem.c的分<br>析.<br><br>/*<br> * 关闭指定交换设备(读入所有交换设备上的page)<br> */<br>asmlinkage long sys_swapoff(const char * specialfile)<br>{<br> struct swap_info_struct * p = NULL;<br> struct nameidata nd;<br> int i, type, prev;<br> int err;<br> <br> ........//capable check<br> <br> /*找到要关闭的文件*/<br> err = user_path_walk(specialfile, &nd);<br> if (err)<br> goto out;<br><br> lock_kernel();<br> prev = -1;<br> swap_list_lock();<br> /*swap_list遍历在看看要关闭那个设备,略*/<br> ...............<br><br> /*关闭设备前调整一下分配策略*/<br> if (prev < 0) {<br> swap_list.head = p->next;<br> } else {<br> swap_info[prev].next = p->next;<br> }<br> if (type == swap_list.next) {<br> /* just pick something that's safe... */<br> swap_list.next = swap_list.head;<br> }<br> nr_swap_pages -= p->pages;<br> swap_list_unlock();<br> p->flags = SWP_USED;<br> <br> err = try_to_unuse(type); //释放所有swap entry,将在交换设备上的page读入内存<br> <br> if (err) {/*由于内存不足关闭失败,重新启用此swap设备*/<br> /* re-insert swap space back into swap_list */<br> swap_list_lock();<br> for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)<br> if (p->prio >= swap_info[i].prio)<br> break;<br> p->next = i;<br> if (prev < 0)<br> swap_list.head = swap_list.next = p - swap_info;<br> else<br> swap_info[prev].next = p - swap_info;<br> nr_swap_pages += p->pages;<br> swap_list_unlock();<br> p->flags = SWP_WRITEOK;<br> goto out_dput;<br> }<br><br> /*释放交换设备*/<br> ............<br>}<br><br>核心函数:<br><br>/*<br> * We completely avoid races by reading each swap page in advance,<br> * and then search for the process using it. All the necessary<br> * page table adjustments can then be made atomically.<br> */<br> /*除非内存耗尽,否则肯定可以释放swap entry*/<br>static int try_to_unuse(unsigned int type)<br>{<br> struct swap_info_struct * si = &swap_info[type];<br> struct task_struct *p;<br> struct page *page;<br> swp_entry_t entry;<br> int i;<br><br> while (1) {<br> /*<br> * Find a swap page in use and read it in.<br> */<br> swap_device_lock(si);<br> for (i = 1; i < si->max ; i++) {<br> if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {<br> /*<br> * Prevent swaphandle from being completely<br> * unused by swap_free while we are trying<br> * to read in the page - this prevents warning<br> * messages from rw_swap_page_base.<br> */<br> if (si->swap_map[i] != SWAP_MAP_MAX)<br> si->swap_map[i]++; /*我们要从此swap page读入*/<br> swap_device_unlock(si);<br> goto found_entry;<br> }<br> }<br> swap_device_unlock(si);<br> break;<br><br> found_entry:<br> entry = SWP_ENTRY(type, i);<br><br> /* Get a page for the entry, using the existing swap<br> cache page if there is one. Otherwise, get a clean<br> page and read the swap into it. */<br> page = read_swap_cache(entry);<br> if (!page) {/*swap entry 不再有人用,或者内存分配失败见read_swap_cache*/<br> swap_free(entry); /*不可能无人用,swap off还用呢*/<br> return -ENOMEM; /*所以就是内存分配失败*/<br> }<br><br> /*有必要,可能进程已经读入另外一个page*/<br> if (PageSwapCache(page)) <br> delete_from_swap_cache(page);/*那时必须彻底释放此page*/<br><br><br> read_lock(&tasklist_lock);<br> for_each_task(p)<br> unuse_process(p->mm, entry, page);/*已经读入page,让各个进程释放swap entry*/<br> read_unlock(&tasklist_lock);<br> shmem_unuse(entry, page); /*让shmem 也释放对swap entry的引用*/<br> /* Now get rid of the extra reference to the temporary<br> page we've been using. */<br> page_cache_release(page);/* read_swap_cache -> alloc */<br> /*<br> * Check for and clear any overflowed swap map counts.<br> */<br> swap_free(entry); /* over*/<br> swap_list_lock();<br> swap_device_lock(si);<br> if (si->swap_map[i] > 0) {<br> if (si->swap_map[i] != SWAP_MAP_MAX)<br> printk("VM: Undead swap entry %08lx\n", <br> entry.val);<br> nr_swap_pages++;<br> si->swap_map[i] = 0;<br> }<br> swap_device_unlock(si);<br> swap_list_unlock();<br> }<br> return 0;<br>}<br><br> shmem_unuse我们就不提了.看unuse_process,这是一个遍进程vma,遍历每个vma涉及到的<br>pmd,page table, pte.这种遍历我们见过很多了.只看看unuse_pte,<br>/*<br> * The swap entry has been read in advance, and we return 1 to indicate<br> * that the page has been used or is no longer needed.<br> *<br> * Always set the resulting pte to be nowrite (the same as COW pages<br> * after one process has exited). We don't know just how many PTEs will<br> * share this swap entry, so be cautious and let do_wp_page work out<br> * what to do if a write is requested later.<br> */<br>static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,<br> pte_t *dir, swp_entry_t entry, struct page* page)<br>{<br> pte_t pte = *dir;<br><br> if (pte_none(pte))<br> return;<br> if (pte_present(pte)) {<br> /* If this entry is swap-cached, then page must already<br> hold the right address for any copies in physical<br> memory */<br> if (pte_page(pte) != page)<br> return;<br> /* We will be removing the swap cache in a moment, so... */<br> ptep_mkdirty(dir);<br> return;<br> }<br><br> /*swap out的page 进程页表 设置成swap entry,这里是一个理由*/<br> if (pte_to_swp_entry(pte).val != entry.val) /*赫赫,动作真快,已经换了一个swap设备*/<br> return;<br> set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));<br> swap_free(entry);<br> get_page(page); /*此进程使用此page*/<br> ++vma->vm_mm->rss;<br>}<br><br><br><br> over. 2006.8.9<br> <br><br></pre>
</td>
</tr>
</tbody>
</table></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -