免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2897 | 回复: 4
打印 上一主题 下一主题

swap 页面引用何时降为0呢 [复制链接]

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-09-09 16:01 |只看该作者 |倒序浏览
看2.4代码看到, 当分配swap page时, 引用计数为1, 然后将该swap page 信息写入页表时, 引用计数+1, 那就不明白了, 照此而言, 自然是swap in 的时候, 计数减一, 但怎么减也减不到0, 也就是说, 这个swap page再也无法释放了。

static int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask)
  39{
  40        pte_t pte;
  41        swp_entry_t entry;
  42        struct page * page;
  43        int onlist;
  44
  45        pte = *page_table;
  46        if (!pte_present(pte))
  47                goto out_failed;
  48        page = pte_page(pte);
  49        if ((!VALID_PAGE(page)) || PageReserved(page))
  50                goto out_failed;
  51
  52        if (!mm->swap_cnt)
  53                return 1;
  54
  55        mm->swap_cnt--;
  56
  57        onlist = PageActive(page);
  58        /* Don't look at this pte if it's been accessed recently. */
  59        if (ptep_test_and_clear_young(page_table)) {
  60                age_page_up(page);
  61                goto out_failed;
  62        }
  63        if (!onlist)
  64                /* The page is still mapped, so it can't be freeable... */
  65                age_page_down_ageonly(page);
  66
  67        /*
  68         * If the page is in active use by us, or if the page
  69         * is in active use by others, don't unmap it or
  70         * (worse) start unneeded IO.
  71         */
  72        if (page->age > 0)
  73                goto out_failed;
  74
  75        if (TryLockPage(page))
  76                goto out_failed;
  77
  78        /* From this point on, the odds are that we're going to
  79         * nuke this pte, so read and clear the pte.  This hook
  80         * is needed on CPUs which update the accessed and dirty
  81         * bits in hardware.
  82         */
  83        pte = ptep_get_and_clear(page_table);
  84        flush_tlb_page(vma, address);
  85
  86        /*
  87         * Is the page already in the swap cache? If so, then
  88         * we can just drop our reference to it without doing
  89         * any IO - it's already up-to-date on disk.
  90         *
  91         * Return 0, as we didn't actually free any real
  92         * memory, and we should just continue our scan.
  93         */
  94        if (PageSwapCache(page)) {
  95                entry.val = page->index;
  96                if (pte_dirty(pte))
  97                        set_page_dirty(page);
  98set_swap_pte:
  99                swap_duplicate(entry);  // swap page 引用计数 +1
100                set_pte(page_table, swp_entry_to_pte(entry));
101drop_pte:
102                UnlockPage(page);
103                mm->rss--;
104                deactivate_page(page);
105                page_cache_release(page);
106out_failed:
107                return 0;
108        }
109
110        /*
111         * Is it a clean page? Then it must be recoverable
112         * by just paging it in again, and we can just drop
113         * it..
114         *
115         * However, this won't actually free any real
116         * memory, as the page will just be in the page cache
117         * somewhere, and as such we should just continue
118         * our scan.
119         *
120         * Basically, this just makes it possible for us to do
121         * some real work in the future in "refill_inactive()".
122         */
123        flush_cache_page(vma, address);
124        if (!pte_dirty(pte))
125                goto drop_pte;
126
127        /*
128         * Ok, it's really dirty. That means that
129         * we should either create a new swap cache
130         * entry for it, or we should write it back
131         * to its own backing store.
132         */
133        if (page->mapping) {
134                set_page_dirty(page);
135                goto drop_pte;
136        }
137
138        /*
139         * This is a dirty, swappable page.  First of all,
140         * get a suitable swap entry for it, and make sure
141         * we have the swap cache set up to associate the
142         * page with that swap entry.
143         */
144        entry = get_swap_page(); // swa page 引用计数初始化 1
145        if (!entry.val)
146                goto out_unlock_restore; /* No swap space left */
147
148        /* Add it to the swap cache and mark it dirty */
149        add_to_swap_cache(page, entry);
150        set_page_dirty(page);
151        goto set_swap_pte;
152
153out_unlock_restore:
154        set_pte(page_table, pte);
155        UnlockPage(page);
156        return 0;
157}
158

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
2 [报告]
发表于 2011-09-09 16:06 |只看该作者
OK, 明白了, 在 __delete_from_swap_cache 中有这个调用

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
3 [报告]
发表于 2011-09-13 16:58 |只看该作者
还是不明白, 因为我又看到 swapin 中, read_swap_cache_async中, 如果从交换设备中读页面进来前, 又将引用计数 +1 了, 那么现在的问题是:

1。 分配swap page的时候, 初始化 1
2.   无论几个进程映射该页面, swap page的引用计数不变
3.  一个进程由于 paging 原因断开映射, 引用计数 + 1, 假设只有一个, 那么现在为 2
4.  在__delete_from_swap_cache, 计数减一, 现在为 1
5. 开始 swapin,  read_swap_cache_async 中, 由于确实从磁盘中读取了该页面, 计数 +1, 现在为 2
6. 重新映射进进程页表, 计数 -1, 现在为 1

这就是说, 无论怎么者, 它的计数就是不变成 0 了
曾怀疑写page到磁盘的时候, 计数会 -1, 但找来找去, 没有发现相应代码

论坛徽章:
0
4 [报告]
发表于 2011-09-13 18:57 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
5 [报告]
发表于 2011-09-21 10:43 |只看该作者
终于明白了, 貌似我发帖总是没人回答。。。。。。。。。。。


1。 分配swap page的时候, 初始化 1  -------并不是因为分配而初始化1的, 而是之后被加入swapper_space中,  page->index 记录了swap_entry_t 才加1的, 也就是说, page 本身占一个引用。
2.   无论几个进程映射该页面, swap page的引用计数不变
3.  一个进程由于 paging 原因断开映射, 引用计数 + 1, 假设只有一个, 那么现在为 2
4.  在__delete_from_swap_cache, 计数减一, 现在为 1 ------从swapper_space中删除, 减小的是page->index的引用
5. 开始 swapin,  read_swap_cache_async 中, 由于确实从磁盘中读取了该页面, 计数 +1, 现在为 2---->真正意思是该页面又被加入了swapper_space, 还是因为page->index的引用
6. 重新映射进进程页表, 计数 -1, 现在为 1------>最终效果: 数据在物理页面时, 只要页面本身和swap 设备关联上了(该部分数据至少发生了一次断开页面映射事件), 则引用计数不会降为 0; 虽然现在是可以扔掉 swap 设备关联的, 但这样的话, 下一次swap out的时候, 又要重新找swap_entry了, 实现上的取舍而已;

最后, 该引用最终释放是在虚存最终被释放时, 这里应该根据页面分配时的具体情急, 有若干个地方, 比如通过 brk 分配的匿名页面:

  262static inline int free_pte(pte_t pte)
263{
264        if (pte_present(pte)) {
265                struct page *page = pte_page(pte);
266                if ((!VALID_PAGE(page)) || PageReserved(page))
267                        return 0;
268                /*
269                 * free_page() used to be able to clear swap cache
270                 * entries.  We may now have to do it manually.  
271                 */
272                if (pte_dirty(pte) && page->mapping)
273                        set_page_dirty(page);
274                free_page_and_swap_cache(page);
275                return 1;
276        }
277        swap_free(pte_to_swp_entry(pte));
278        return 0;
279}
如果pte_present(page) 发现本进程没有映射, 则不为page->index 引用负责, 如果实际上相关物理页面还存在, 则1。 要么在其他进程被映射, 则在free其他进程的pte时处理2, 要么在 inactive list 中, 则在 inactive list 到 free list的过程中处理;

如果物理页面被映射, 则调用free_page_and_swap_cache代码如下:
138void free_page_and_swap_cache(struct page *page)
139{
140        /*
141         * If we are the only user, then try to free up the swap cache.
142         */
143        if (PageSwapCache(page) && !TryLockPage(page)) {
144                if (!is_page_shared(page)) {
145                        delete_from_swap_cache_nolock(page);
146                }
147                UnlockPage(page);
148        }

149        page_cache_release(page);
150}
151
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP