__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;
}
/*
* 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上被修改。 兄台的分析很有道理。明白了,谢谢
页:
[1]