参照元

説明

引数

返り値

参考

実装

static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
                                                struct mm_struct *mm,
                                                unsigned long start,
                                                unsigned long nr_pages,
                                                int write, int force,
                                                struct page **pages,
                                                struct vm_area_struct **vmas,
                                                int *locked, bool notify_drop,
                                                unsigned int flags)
{
        long ret, pages_done;
        bool lock_dropped;

        if (locked) {
                /* if VM_FAULT_RETRY can be returned, vmas become invalid */
                BUG_ON(vmas);
                /* check caller initialized locked */
                BUG_ON(*locked != 1);
        }
        if (pages)
                flags |= FOLL_GET;
        if (write)
                flags |= FOLL_WRITE;
        if (force)
                flags |= FOLL_FORCE;

        pages_done = 0;
        lock_dropped = false;
        for (;;) {
                ret = __get_user_pages(tsk, mm, start, nr_pages, flags, pages,
                                       vmas, locked);
                if (!locked)
                        /* VM_FAULT_RETRY couldn't trigger, bypass */
                        return ret;
                /* VM_FAULT_RETRY cannot return errors */
                if (!*locked) {
                        BUG_ON(ret < 0);
                        BUG_ON(ret >= nr_pages);
                }

                if (!pages)
                        /* If it's a prefault don't insist harder */
                        return ret;

                if (ret > 0) {
                        nr_pages -= ret;
                        pages_done += ret;
                        if (!nr_pages)
                                break;
                }
                if (*locked) {
                        /* VM_FAULT_RETRY didn't trigger */
                        if (!pages_done)
                                pages_done = ret;
                        break;
                }
                /* VM_FAULT_RETRY triggered, so seek to the faulting offset */
                pages += ret;
                start += ret << PAGE_SHIFT;

                /*
                 * Repeat on the address that fired VM_FAULT_RETRY
                 * without FAULT_FLAG_ALLOW_RETRY but with
                 * FAULT_FLAG_TRIED.
                 */
                *locked = 1;
                lock_dropped = true;
                down_read(&mm->mmap_sem);
                ret = __get_user_pages(tsk, mm, start, 1, flags | FOLL_TRIED,
                                       pages, NULL, NULL);
                if (ret != 1) {
                        BUG_ON(ret > 1);
                        if (!pages_done)
                                pages_done = ret;
                        break;
                }
                nr_pages--;
                pages_done++;
                if (!nr_pages)
                        break;
                pages++;
                start += PAGE_SIZE;
        }
        if (notify_drop && lock_dropped && *locked) {
                /*
                 * We must let the caller know we temporarily dropped the lock
                 * and so the critical section protected by it was lost.
                 */
                up_read(&mm->mmap_sem);
                *locked = 0;
        }
        return pages_done;
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-03-17 (木) 10:40:28