设为首页 加入收藏

TOP

Linux 匿名页的反向映射(三)
2019-09-01 23:08:41 】 浏览:77
Tags:Linux 匿名 映射
ge count (while holding * page_table_lock, as we have here) to make sure that the page * cannot be freed. If we unmap that page here, a user write * access to the virtual address will bring back the page, but * its raised count will (ironically) be taken to mean it's not * an exclusive swap page, do_wp_page will replace it by a copy * page, and the user never get to see the data GUP was holding * the original page for. * * This test is also useful for when swapoff (unuse_process) has * to drop page lock: its reference to the page stops existing * ptes from being unmapped, so swapoff can make progress. */ if (PageSwapCache(page) && page_count(page) != page_mapcount(page) + 2) { ret = SWAP_FAIL; goto out_unmap; } /* Nuke the page table entry. */ flush_cache_page(vma, address); pteva l = ptep_clear_flush(vma, address, pte); /* Move the dirty bit to the physical page now the pte is gone. */ if (pte_dirty(pteva l)) set_page_dirty(page); if (PageAnon(page)) { swp_entry_t entry = { .val = page->private }; /* * Store the swap location in the pte. * See handle_pte_fault() ... */ BUG_ON(!PageSwapCache(page)); swap_duplicate(entry); if (list_empty(&mm->mmlist)) { spin_lock(&mmlist_lock); list_add(&mm->mmlist, &init_mm.mmlist); spin_unlock(&mmlist_lock); } set_pte(pte, swp_entry_to_pte(entry)); BUG_ON(pte_file(*pte)); mm->anon_rss--; } mm->rss--; acct_update_integrals(); page_remove_rmap(page); page_cache_release(page); out_unmap: pte_unmap(pte); out_unlock: spin_unlock(&mm->page_table_lock); out: return ret; } static inline unsigned long vma_address(struct page *page, struct vm_area_struct *vma) { pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); /* PAGE_CACHE_SHIFT - PAGE_SHIFT值为0,其实就是把page->index赋给pgoff * 至于为什么要这样右移一下,我也不清楚 */ unsigned long address; address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); /* page->index是页的偏移 * vma->vm_pgoff是内存区域首地址的偏移,都是以页为单位 * 相减后再<<PAGE_SHIFT便得到页在内存区域的中的偏移 * 再+vma->vma_start便得到页在内存区域中的地址 */ if (unlikely(address < vma->vm_start || address >= vma->vm_end)) { /* 得到的地址应该在vm->vm_start和vm_end之间,否则报错 */ /* page should be within any vma from prio_tree_next */ BUG_ON(!PageAnon(page)); return -EFAULT; } return address; } #define PGDIR_SHIFT 22 // 在i386机子上线性地址0-11位表PTE,12-21表PMD,22-31位表PGD,即线性地址右移22位的结果为其在全局页目录的偏移 #define PTRS_PER_PGD 1024 // 因PGD共10位,所以其最多可以有2^10=1024个全局描述符项 #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) // 得到线性地址address在全局页目录里面的偏移 #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) // 再加上全局描述符基地址(存储在内存描述符mm_struct中的pdg域)后便得到其在全局描述符中的具体位置
首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇keil4编译Error: User Command te.. 下一篇oom killer

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目