littlenewer 发表于 2015-01-25 14:02

__get_user_pages_fast为什么不用锁

__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;
}

humjb_1983 发表于 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上被修改。

littlenewer 发表于 2015-02-02 19:25

兄台的分析很有道理。明白了,谢谢
页: [1]
查看完整版本: __get_user_pages_fast为什么不用锁