函数源码

Linux Kernel

v5.5.9

Brick Technologies Co., Ltd

Source File:fs\userfaultfd.c Create Date:2022-07-29 10:52:29
首页 Copyright©Brick

258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#else
static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
                     struct vm_area_struct *vma,
                     unsigned long address,
                     unsigned long flags,
                     unsigned long reason)
{
    return false;   /* should never get here */
}
#endif /* CONFIG_HUGETLB_PAGE */
 
/*
 * Verify the pagetables are still not ok after having reigstered into
 * the fault_pending_wqh to avoid userland having to UFFDIO_WAKE any
 * userfault that has already been resolved, if userfaultfd_read and
 * UFFDIO_COPY|ZEROPAGE are being run simultaneously on two different
 * threads.
 */
static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
                     unsigned long address,
                     unsigned long flags,
                     unsigned long reason)
{
    struct mm_struct *mm = ctx->mm;
    pgd_t *pgd;
    p4d_t *p4d;
    pud_t *pud;
    pmd_t *pmd, _pmd;
    pte_t *pte;
    bool ret = true;
 
    VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
 
    pgd = pgd_offset(mm, address);
    if (!pgd_present(*pgd))
        goto out;
    p4d = p4d_offset(pgd, address);
    if (!p4d_present(*p4d))
        goto out;
    pud = pud_offset(p4d, address);
    if (!pud_present(*pud))
        goto out;
    pmd = pmd_offset(pud, address);
    /*
     * READ_ONCE must function as a barrier with narrower scope
     * and it must be equivalent to:
     *  _pmd = *pmd; barrier();
     *
     * This is to deal with the instability (as in
     * pmd_trans_unstable) of the pmd.
     */
    _pmd = READ_ONCE(*pmd);
    if (pmd_none(_pmd))
        goto out;
 
    ret = false;
    if (!pmd_present(_pmd))
        goto out;
 
    if (pmd_trans_huge(_pmd))
        goto out;
 
    /*
     * the pmd is stable (as in !pmd_trans_unstable) so we can re-read it
     * and use the standard pte_offset_map() instead of parsing _pmd.
     */
    pte = pte_offset_map(pmd, address);
    /*
     * Lockless access: we're in a wait_event so it's ok if it
     * changes under us.
     */
    if (pte_none(*pte))
        ret = true;
    pte_unmap(pte);
 
out:
    return ret;
}