内存管理API之get_user_pages
2018-01-18 08:20
525 查看
long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) 用于将用户空间的页映射到内存,并返回它们页结构的指针,即get_user_pages的第四个形参struct page **pages 其源码分析如下: long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { #可见这个函数在带当前进程中映射内存 return __get_user_pages_locked(current, current->mm, start, nr_pages, pages, vmas, NULL, false, gup_flags | FOLL_TOUCH); } static __always_inline long __get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, struct page **pages, struct vm_area_struct **vmas, int *locked, bool notify_drop, unsigned int flags) { long ret, pages_done; bool lock_dropped; #本例中locked 为null 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; pages_done = 0; lock_dropped = false; for (;;) { #从start 开始映射nr_pages的页,将页指针保存在pages中,这里的ret表示映射成功页的个数 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 条件成立,说明__get_user_pages 成功映射了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); #再从start 开始映射一个页,正常情况下这里会failed。 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; #正常情况下for 死循环会从这里退出 } #如果程序跑到这里,说明第一次映射nr_pages 页的时候failed了。但是第二次调用__get_user_pages #映射单页确成功了。因此总的要映射的page 数减一,且start起始地址加一个page 后,重新开始映射. 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; } #这里的pages_done 表示映射成功的页的个数. return pages_done; }
相关文章推荐
- 内存管理API之get_user_pages_fast
- 内存管理API之__get_free_pages
- 内存管理API之get_unmapped_area
- get_user_pages — 获取用户区进程使用内存的某个页
- 澄清一个get_user_pages的事实
- get_user_pages的意义
- Missing access checks in put_user/get_user kernel API (CVE-2013-6282)
- 澄清一个get_user_pages的事实
- 内存管理API之nr_free_buffer_pages
- get_user_pages
- 内存管理API之memdup_user
- 内存管理API之page_cache_get_speculative
- 内存管理API之vma_pages
- Linux2.6.29内核的get_user_pages的改进
- linux 内存管理之kmalloc、vmalloc、malloc、get_gree_pages的区别
- Safari支不支持HTML5录音? 现在浏览器中最好的解决方案是WebRTC下的 navigator.getUserMedia API。
- Linux2.6.29内核的get_user_pages的改进
- Missing access checks in put_user/get_user kernel API (CVE-2013-6282)
- 页面的引用计数和get_user_pages
- QQ登录成功后,没有调用- (void)getUserInfoResponse:(APIResponse *)response方法