免费注册 查看新帖 |

Chinaunix

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

[内存管理] __get_user_pages_fast为什么不用锁 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-01-25 14:02 |只看该作者 |倒序浏览
__get_user_pages_fast会遍历当前进程的页表,如果两个线程共享内存空间,不就会引起冲突了吗。为何此处不用加锁呢?另外,如果这种访问时安全的,那为什么还要在遍历页表前关中断呢?这样做的目的是什么?一直没想通这两个问题。

int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
                          struct page **pages)
{
        struct mm_struct *mm = current->mm;
        unsigned long addr, len, end;
        unsigned long next;
        unsigned long flags;
        pgd_t *pgdp;
        int nr = 0;

        start &= PAGE_MASK;
        addr = start;
        len = (unsigned long) nr_pages << PAGE_SHIFT;
        end = start + len;
        if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
                                        (void __user *)start, len)))
                return 0;

        /*
         * XXX: batch / limit 'nr', to avoid large irq off latency
         * needs some instrumenting to determine the common sizes used by
         * important workloads (eg. DB2), and whether limiting the batch size
         * will decrease performance.
         *
         * It seems like we're in the clear for the moment. Direct-IO is
         * the main guy that batches up lots of get_user_pages, and even
         * they are limited to 64-at-a-time which is not so many.
         */
        /*
         * This doesn't prevent pagetable teardown, but does prevent
         * the pagetables and pages from being freed on x86.
         *
         * So long as we atomically load page table pointers versus teardown
         * (which we do on x86, with the above PAE exception), we can follow the
         * address down to the the page and take a ref on it.
         */
        local_irq_save(flags);
        pgdp = pgd_offset(mm, addr);
        do {
                pgd_t pgd = *pgdp;

                next = pgd_addr_end(addr, end);
                if (pgd_none(pgd))
                        break;
                if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
                        break;
        } while (pgdp++, addr = next, addr != end);
        local_irq_restore(flags);

        return nr;
}

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
2 [报告]
发表于 2015-01-29 10:51 |只看该作者
        /*
         * With get_user_pages_fast, we walk down the pagetables without taking
         * any locks.  For this we would like to load the pointers atomically,
         * but that is not possible (without expensive cmpxchg8b) on PAE.  What
         * we do have is the guarantee that a pte will only either go from not
         * present to present, or present to not present or both -- it will not
         * switch to a completely different present page without a TLB flush in
         * between; something that we are blocking by holding interrupts off.
...

个人理解:
__get_user_pages_fast是不保证成功的,如果需要保证,需要使用get_user_pages_fast,其中会先尝试fast,不行的话,再回到slow。
关中断的目的:不接收tlb flush的IPI,由于tlb_flush时发的是同步(wait=1)IPI,如果本CPU不处理该IPI的话,发送端CPU将一直阻塞等待;由于在修改(或释放)页表之前通常都是需要进行tlb flush的,所以这样应可以一定程度上避免页表在其它CPU上被修改。

论坛徽章:
0
3 [报告]
发表于 2015-02-02 19:25 |只看该作者
兄台的分析很有道理。明白了,谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP