linux内存操作----kernel 3.5.X copy_from_user()和copy_to_user()

本文探讨了Linux内核中用户空间与内核空间交互的关键函数copy_from_user和copy_to_user的工作原理,并对比了mmap机制的优势,包括提高效率及减少缓存失效。

前面的一篇文章中简单的描述了一下内存映射的内容,http://blog.youkuaiyun.com/codectq/article/details/25658813,这篇文章作为用户把内存规划好之后,在用户空间使用IOCTL对设备进行控制时的常用函数的代码摘录。后续我会把这部分完善起来。

#ifdefCONFIG_MMU

externunsigned long __must_check __copy_from_user(void *to, const void __user *from,unsigned long n);

externunsigned long __must_check __copy_to_user(void __user *to, const void *from,unsigned long n);

externunsigned long __must_check __copy_to_user_std(void __user *to, const void*from, unsigned long n);

externunsigned long __must_check __clear_user(void __user *addr, unsigned long n);

externunsigned long __must_check __clear_user_std(void __user *addr, unsigned longn);

#else

#define__copy_from_user(to,from,n)

(memcpy(to, (void __force *)from, n),0)

#define__copy_to_user(to,from,n)

(memcpy((void __force *)to, from, n),0)

#define__clear_user(addr,n)

 

(memset((void __force *)addr, 0, n), 0)

#endif

 

externunsigned long __must_check __strncpy_from_user(char *to, const char __user*from, unsigned long count);

externunsigned long __must_check __strnlen_user(const char __user *s, long n);

 

staticinline unsigned long __must_check copy_from_user(void *to, const void __user*from, unsigned long n)

{

if (access_ok(VERIFY_READ, from, n))

n = __copy_from_user(to, from, n);

else /* security hole - plug it */

memset(to, 0, n);

return n;

}

 

staticinline unsigned long __must_check copy_to_user(void __user *to, const void*from, unsigned long n)

{

if (access_ok(VERIFY_WRITE, to, n))

n = __copy_to_user(to, from, n);

return n;

}

 

在新的内核中,修改了这部分代码。部分网上能够查到的资料还一直以很老的内核版本在说明。实在受不了有些对新内核讲解的文章不负责任的添加链接。

./arch/arm/lib/uaccess.S:288:/*Prototype: unsigned long __copy_from_user(void *to,const void *from,unsignedlong n);

./arch/arm/lib/uaccess.S:307:ENTRY(__copy_from_user)

./arch/arm/lib/uaccess.S:547:ENDPROC(__copy_from_user)


copy_to_user与mmap的工作原理

copy_to_user在每次拷贝时需要检测指针的合法性,也就是用户空间的指针所指向的地址的确是一段该进程本身的地址,而不是指向了不属于它的地方,而且每次都会拷贝一次数据,频繁访问内存,由于虚拟地址连续,物理地址不一定会连续,从而造成CPU的CACHE频繁失效,从而使速度降低  
  mmap仅在第一次使用时为进程建立页表,也就是将一段物理地址映射到一段虚拟地址上,以后操作时不再检测其地址的合法性(合法性交由CPU页保护异常来做),另一方面是内核下直接操作mmap地址,可以不用频繁拷贝,也就是说在内核下直接可用指针向该地址操作,而不再在内核中专门开一个缓冲区,然后将缓冲区中的数据拷贝一次进来,mmap一般是将一段连续的物理地址映射成一段虚拟地址,当然,也可以将每段连续,但各段不连续的物理地址映射成一段连续的虚拟地址,无论如何,其物理地址在每段之中是连续的,这样一来,就不会造成CPU的CACHE频繁失效,从而大大节约时间。


Linux内核开发中,`copy_from_user()` `copy_to_user()` 是用于在用户空间内核空间之间安全地复制数据的关键函数。这些函数的设计考虑了安全性与稳定性,因为直接操作用户空间地址可能带来风险,例如访问非法地址或未映射的内存区域[^2]。 ### 使用 `copy_from_user` `copy_from_user()` 用于从用户空间复制数据到内核空间。其函数原型如下: ```c unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); ``` - **参数说明**: - `to`: 内核空间的目标缓冲区指针。 - `from`: 用户空间的源数据指针。 - `n`: 要复制的字节数。 如果复制过程中遇到错误(如用户空间指针无效),该函数将返回未能复制的字节数;否则返回0表示成功。 #### 示例代码 ```c char kernel_buffer[100]; unsigned long result; result = copy_from_user(kernel_buffer, user_ptr, sizeof(kernel_buffer)); if (result) { printk(KERN_ERR "Failed to copy %lu bytes from user space\n", result); } ``` ### 使用 `copy_to_user` `copy_to_user()` 用于将数据从内核空间复制到用户空间。其函数原型如下: ```c unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); ``` - **参数说明**: - `to`: 用户空间的目标缓冲区指针。 - `from`: 内核空间的源数据指针。 - `n`: 要复制的字节数。 同样地,如果发生错误,该函数返回未能复制的字节数;否则返回0[^3]。 #### 示例代码 ```c const char *kernel_data = "Hello from kernel!"; unsigned long result; result = copy_to_user(user_ptr, kernel_data, strlen(kernel_data) + 1); if (result) { printk(KERN_ERR "Failed to copy %lu bytes to user space\n", result); } ``` ### 注意事项 1. **检查指针有效性**:尽管这两个函数内部已经处理了一些指针检查逻辑,但在调用之前确保用户提供的指针是合法且可访问的是非常重要的。 2. **避免空指针越界访问**:传递给这些函数的指针不应为空,并且应确保不会超出分配的缓冲区大小。 3. **性能考量**:频繁使用这些函数可能会导致性能下降,尤其是在大量数据传输场景下。因此,在设计系统架构时应尽量减少不必要的用户空间与内核空间之间的数据交换。 4. **体系结构依赖性**:这些函数的具体实现可能因不同的CPU架构而异。例如,在x86平台上,相关实现可以在`arch/x86/lib/`目录下找到[^4]。 通过正确使用这些函数,可以有效地保证Linux内核模块或驱动程序的安全性可靠性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值