在内核代码中经常看到下面的用法:
/** * copy_to_user_nofault(): safely attempt to write to a user-space location * @dst: address to write to * @src: pointer to the data that shall be written * @size: size of the data chunk * * Safely write to address @dst from the buffer at @src. If a kernel fault * happens, handle that and return -EFAULT. */ long copy_to_user_nofault(void __user *dst, const void *src, size_t size) { long ret = -EFAULT; if (access_ok(dst, size)) { pagefault_disable(); ret = __copy_to_user_inatomic(dst, src, size); pagefault_enable(); } if (ret) return -EFAULT; return 0; }
上面的pagefault_disable的实现如下:
/* * These routines enable/disable the pagefault handler. If disabled, it will * not take any locks and go straight to the fixup table. * * User access methods will not sleep when called from a pagefault_disabled() * environment. */ static inline void pagefault_disable(void) { pagefault_disabled_inc(); /* * make sure to have issued the store before a pagefault * can hit. */ barrier(); } static inline void pagefault_enable(void) { /* * make sure to issue those last loads/stores before enabling * the pagefault handler again. */ barrier(); pagefault_disabled_dec(); }
根据注释,如果缺页被关闭,当发生缺页后,在缺页处理程序中会直接利用fixup表来修复,
并不会去处理缺页。所以__copy_to_user_inatomic会返回实际要拷贝的数size。
下面是一个测试程序:
- 驱动
点击查看代码
- 应用
点击查看代码
- 测试结果
# /mnt/test Evicting ./test.bin Files: 1 Directories: 0 Evicted Pages: 4096 (16M) Elapsed: 0.001014 seconds Evicting ./test.bin Files: 1 Directories: 0 Evicted Pages: 4096 (16M) Elapsed: 0.001705 seconds
内核日志:
[199215.187377] pagefault_disable: arg: 0x7fd349400000 ret: 64, buf: [199215.188557] pagefault_enable: arg: 0x7fd349400000 ret: 0, buf: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ [199215.219537] pagefault_disable: arg: 0x7fd349400000 ret: 64, buf: [199215.220701] pagefault_enable: arg: 0x7fd349400000 ret: 0, buf: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ