Robert Love 在 quora 上关于 Linux Kernel 的问答摘录之一

  入门Linux Kernel就是看的Robert Love所著的《linux kernel development》和 《linux system programming》,感觉真的是深入浅出娓娓道来。这几天在Quora上看到大神对 Linux Kernel 的一些回答,也是深有启发,特此将一些有意思的问题翻译过来。


(1)什么是“SMP 安全”以及为什么linux kernel是SMP安全的?

答:SMP安全的意思是代码是线程安全的,也就是说代码在多线程并发访问时也会正确执行。非SMP安全的代码可能导致线程敌对(thread hostile)或线程竞争(racey),也就是说多线程可能在code内竞争,导致bug。

    Linux内核是SMP安全的,因为它是高度线程化的,而且可以工作在多处理器的环境下。换句话说,它必须是SMP安全的。


(2)如何查看系统在系统调用(system call)上所用的时间比例?

答:top和vmstat是查看此信息的最简单方法。“sy”那一列所表示的就是CPU在内核里的开销,也就包括了系统调用的开销。对于很多工作而言,这个数据非常接近系统调用所占用的时间,因为非系统调用不会占用内核太久的时间。

    对于单独的进程而言,可以使用time命令来查看运行时间信息。比如time df,就会告诉你执行df命令所占用的全部运行时间,用户空间运行时间,内核空间运行时间。


(3)copy_to_user如何工作?

答:copy_to_user是linux内核定义的函数(定义在<asm/uaccess.h>中),用来把数据从内核空间拷贝到用户空间。函数具体的实现取决于系统的架构,但是一般都是如下形式:

#include <asm/uaccess.h>

int copy_to_user(void *dst, const void *src, unsigned int size);

如果成功的话,copy_to_user会从内核地址src拷贝size大小的字节到用户空间地址dst。copy_to_user返回没有被拷贝的字节数,因此当所有数据全部拷贝成功的时候,函数返回0.

为什么不直接调用memcpy()呢?有两个原因。第一,内核可以往任意地址写入数据。但是用户程序不可以。copy_to_user需要检查dst,保证该地址是可以访问的以及可以被当前进程写入。第二,随着系统架构不同,我们不能简单地把数据从内核拷贝到用户空间。我们可能需要先做一些特别的准备工作,比如刷新cache,或者一些其它的特殊操作。

让我们看看copy_to_user在大家最熟知的x86架构上做了什么。首先,copy_to_user调用access_ok来检查dst是否可以被写入(检查类型为VERIFY_WRITE)。如果access_ok返回非0值,那么copy_to_user就开始进行拷贝了。对于486和486以前的x86处理器而言,由于页表随时可能变化,所以目的地址所在页必须在内存中。对于486以后的x86处理器,WPbit。最后,copy_to_user通过__copy_to_user_ll来拷贝内存,拷贝的最终实现方式是一个优化版本的memcpy。

让我们看一个例子。这是linux内核3.6里面定义的gethostname系统调用。

  1. int gethostname(char*name,int len)
    {
        int i, errno;
        struct new_utsname*u;
        if(len<0)
            return-EINVAL;
        down_read(&uts_sem);
        u= utsname();
        i=1+ strlen(u->nodename);
        if(i> len)
            i= len;
        errno=0;
        if(copy_to_user(name, u->nodename, i))
            errno=-EFAULT;
        up_read(&uts_sem);
        return errno;
    }

这个系统调用非常简单:首先获取一个读信号量,然后再得到一个指向utsname结构体的指针。这个结构体里面含有很多系统信息,其中的hostname信息就被拷贝到用户提供的内存name中。如果失败了,系统调用返回EFAULT,表明在往用户内存写入时出现了问题。如果成功则返回0.
copy_from_user函数的行为与copy_to_user顺序相反。

(4)Linux内核是可重入的吗?
是的,Linux内核是可重入的。中断处理程序可以嵌套,多个进程可以同时发起系统调用进入内核,多个内核进程可以并行运行。高级别的进程可以抢占低级别的进程,即便后者可能当时正在内核空间里面运行(也就是大家喜闻乐见的可抢占内核)。
内核在一些很小的临界区是不可重入的:比如中断被禁止(不管是全局中断还是某一根中断线)的区域;占有锁(阻止同时访问的锁)的区域;禁止内核抢占的区域。

(5)Linux内核是不是也像用户态进程一样拥有自己的虚拟地址空间?
是的,Linux内核和用户进程一样使用虚拟地址。内核的虚拟地址有一些特殊(毕竟是内核在使用),但是它仍然是虚拟的,不是物理的。
Linux内核为了避免反复进入和离开内核空间所带来的内存地址空间转换开销,把 内核的虚拟地址映射到了每个用户进程的虚拟地址空间。因此,每个用户进程都和内核共享虚拟地址空间,避免了进入和离开内核空间时的转换开销。
在x86-32上,内核占据了虚拟地址空间的前1GB,用户进程占据了剩下的3GB。内核通过内存权限来保证用户进程不能读写内核所在的1GB内存。像这样分割内存空间的好处是可以避免每次上下文切换带来的地址空间切换,坏处是内核和用户进程都不能完全使用32位系统可以提供的4GB空间。这种权衡仍然是值得的。在64位系统上,由于其提供的内存空间几乎是无穷无尽的,这种内存分割方式的缺点就可以忽略不计了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值