Linux操作系统sysctl机制的思想与实现(转)

在内核中sysctl机制的实现十分简单,和linux内核的大多数机制一样,采用先注册后使用的方式,只要你register了一个sysctl的实体,那么在用户空间你就可以控制你注册的实体变量了,然后在内核中你就可以用这些变量,根据这些变量的不同值来采取不同的动作,内核中的sysctl实现根本不涉及任何用户策略方面的东西,仅仅是注册,具体如何使用,那纯粹是用户设计该sysctl实体时要考虑的事情。下面就是一个例子:
static struct ctl_table zhaoya_test[] = {
        {
                .ctl_name       = 1,
                .procname       = "value",
                .data           = &value,
                .maxlen         = sizeof(int),
                .mode           = 0666,
                .proc_handler   = &proc_dointvec,  //这个回调函数是为procfs提供了。
        },
        {
                .ctl_name = 0
        }
};
static struct ctl_table zhaoya_root = {
        .ctl_name       = CTL_CPU + 10,
        .procname       = "zhaoya",
        .mode           = 0555,
        .child          = zhaoya_test,
};
static int __init test_init(void)
{
        register_sysctl_table(&zhaoya_root, 0);
        return 0;
}
就这就完事了,当我用sysctl的-w命令来改写value变量的时候,proc_dointvec就会将我传入的新值赋给value,其实加载模块后你会发现,在/proc/sys下有了zhaoya目录,在这个目录下有了value文件,那么如果你读/proc/sys/zhaoya/value的话就会读到新值。sysctl的内核实现就是sys_sysctl,最终调用do_sysctl:
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen)
{
         struct list_head *tmp;
         if (nlen <= 0 || nlen >= CTL_MAXNAME)
                 return -ENOTDIR;
         if (oldval) {
                 int old_len;
                 if (!oldlenp || get_user(old_len, oldlenp))
                         return -EFAULT;
         }
         tmp = &root_table_header.ctl_entry;
         do {
                 struct ctl_table_header *head =
                         list_entry(tmp, struct ctl_table_header, ctl_entry);
                 void *context = NULL;
                 int error = parse_table(name, nlen, oldval, oldlenp,  newval, newlen, head->ctl_table, &context);
                 if (context)
                         kfree(context);
                 if (error != -ENOTDIR)
                         return error;
                 tmp = tmp->next;
         } while (tmp != &root_table_header.ctl_entry);
         return -ENOTDIR;
}
static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, ctl_table *table, void **context)
{
         int n;
repeat:
...
         for ( ; table->ctl_name; table++) {
                 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
                         int error;
                         if (table->child) {
                                 if (ctl_perm(table, 001))  //测试权限,ctl_table中的mode字段就是权限字段,每一位都有解释。
                                         return -EPERM;
...//有table->strategy的情况,我的例子没有,故忽略。
                         }
                         error = do_sysctl_strategy(table, name, nlen, oldval, oldlenp, newval, newlen, context);
                         return error;
                 }
         }
         return -ENOTDIR;
}
最后的do_sysctl_strategy实现了变量的替换,该函数中的ctl_perm很有意思,它就是利用ctl_table中的mode字段和sysctl中的操作字段来判断当前操作是否被允许的,其实也没有什么意思。
int do_sysctl_strategy (ctl_table *table,  int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context)
{
         int op = 0, rc;
         size_t len;
         if (oldval)
                 op |= 004;
         if (newval)
                 op |= 002;
         if (ctl_perm(table, op))
                 return -EPERM;
...
         if (table->data && table->maxlen) {
                 if (oldval && oldlenp) {
                         if (get_user(len, oldlenp))
                                 return -EFAULT;
                         if (len) {
                                 if (len > table->maxlen)
                                         len = table->maxlen;
                                 if(copy_to_user(oldval, table->data, len))
                                         return -EFAULT;
                                 if(put_user(len, oldlenp))
                                         return -EFAULT;
                         }
                 }
                 if (newval && newlen) {
                         len = newlen;
                         if (len > table->maxlen)
                                 len = table->maxlen;
                         if(copy_from_user(table->data, newval, len))
                                 return -EFAULT;
                 }
         }
         return 0;
}
这就是sysctl的几乎全部了,十分简单,为何如此简单,正是因为linux内核没有那么多策略性的东西,它只实现机制。记住,只要是机制和策略分离的东西,你要想提供一个功能你就必须提供一套程序,一个来实现机制,另一个实现策略,正如sysctl和netlink一样。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dog250/archive/2010/02/09/5303434.aspx

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值