Chinaunix首页 | 论坛 | 博客
  • 博客访问: 639114
  • 博文数量: 51
  • 博客积分: 773
  • 博客等级: 军士长
  • 技术积分: 2392
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-07 21:32
文章分类
文章存档

2018年(1)

2013年(16)

2012年(34)

分类: LINUX

2012-11-16 21:23:24

Sysctl:目录/proc/sys

       在/proc/sys下看到的一个文件,实际都是一个内核变量。对于每个变量,内核可以将其放在/proc/sys的位置(与相同内核组件或功能相关联的变量通常都位于同一个目录中,如/proc/sys/net/ipv4目录中都是与ipv4相关的文件)、命名(多数时候文件名都是和相关联的内核变量相同的名字)、访问权限(如一个文件可以由任何人读,但只能由超级用户修改)。

       输出到/proc/sys中的变量内容可借助相关联的文件进行读写或直接用sysctl系统调用。有些目录和文件在引导期间静态定义,而其他则是在允许期间添加的。当一个内核模块实现一项新功能或一个协议被加载或卸载时;当一个新的网络设备被注册或注销时。都有可能创建目录或文件。

       /proc/sys中的文件和目录都是以ctl_table结构定义的。ctl_table结构的注册和注销是通过调用kernel/sysctl.c中定义的register_sysctl_table和unregister_sysctl_table:

struct ctl_table_header *register_sysctl_table(struct ctl_table *table);

void unregister_sysctl_table(struct ctl_table_header * header);

struct ctl_table
{
    const char *procname;        /* Text ID for /proc/sys, or zero */
    void *data;
    int maxlen;
    mode_t mode;
    struct ctl_table *child;
    struct ctl_table *parent;    /* Automatically set */
    proc_handler *proc_handler;    /* Callback for text formatting */
    void *extra1;
    void *extra2;
};

ctl_table的关键成员:

procname:在/proc/sys中所使用的文件名

maxlen:输出的内核变量的大小

mode:创建的/proc/sys猪相关文件或目录的访问权限

child:用于建立目录和文件直接的父子关系

proc_handler:当在/proc/sys中读取或写入一个文件时,完成读取或写入操作的函数。所有和文件相关联的ctl_instance都必须有proc_handler初始化,内内核会给目录分派一个默认值

extra1,extra2:可选参数,通常用于定义变量的最小值和最大值

根据与文件相关联的变量类型的不同,proc_handler所指的函数也不相同。

proc_dostring:读/写一个字符串

proc_dointvec:读写一个包含一个或多个整数的数组

proc_dointvec_minmax:同上,但是要确定输入数据在min/max范围内,不在该范围内的值会被拒绝

proc_dointvec_jiffies:读写一个整数数组,但此内核变量以jiffies为单位表示,在返回用户前会转化为秒数,写入前转化为jiffies

proc_dointvec_ms_jiffies:同上,只是这里是转化为毫秒数

proc_doulongvec_minmax:类似proc_dointvec_minmax,但其值为长整数。

proc_doulongvec_ms_jiffies_minmax:读取一个长整数数组。此内核变量以jiffies为单位,而用户空间已毫秒为单位。此值也必须指定min和max区间

ctl_table注册文件的结构实例:

static struct ctl_table ctl_forward_entry[] = {
    {
        .procname    = "ip_forward", //文件名
       .data        = &ipv4_devconf.data[
                    IPV4_DEVCONF_FORWARDING - 1], //输出参数
       .maxlen        = sizeof(int), //参数大小
       .mode        = 0644, //文件权限
       .proc_handler    = devinet_sysctl_forward, //指定函数
       .extra1        = &ipv4_devconf,
        .extra2        = &init_net,
    },
    { },
};

在这里还看不出这个文件在/proc/sys下的那个目录中。

这里是/proc/sys目录下建的默认目录:

static struct ctl_table root_table[] = {
    {
        .procname    = "kernel",
        .mode        = 0555,
        .child        = kern_table,
    },
    {
        .procname    = "vm",
        .mode        = 0555,
        .child        = vm_table,
    },
    {
        .procname    = "fs",
        .mode        = 0555,
        .child        = fs_table,
    },
    {
        .procname    = "debug",
        .mode        = 0555,
        .child        = debug_table,
    },
    {
        .procname    = "dev",
        .mode        = 0555,
        .child        = dev_table,
    },
    { }
};

目录不需要proc_handler函数指针但却有一个child字段。child是一个指针,指向另一个ctl_table结构,这个地址是ctl_table结构列表的头元素地址

 

在/proc/sys中注册文件

函数register_sysctl_table的输入并不包括输入参数ctl_table应该被添加到/proc/sys文件目录的那个子目录中。原因在于所有的插入都是针对/proc/sys目录进行的,所以若想将一个文件注册到/proc/sys的子目录中,就必须建立一棵树由多个child字段链接成ctl_table实体以提供完整路径,然后将代表刚健的树根的ctl_table传递给register_sysctl_table函数。

drivers/scsi/scsi_sysctl.c显示了文件logging_level的定义已经放置到/proc/sys/dev/scsi/目录下的方法:

static ctl_table scsi_table[] = {                                    //logging_level文件
       .procname    = "logging_level",
      .data        = &scsi_logging_level,
      .maxlen    = sizeof(scsi_logging_level),
      .mode        = 0644,
      .proc_handler    = proc_dointvec },
    { }
};

static ctl_table scsi_dir_table[] = {                 //scsi目录
    { .procname    = "scsi",
      .mode        = 0555,
      .child    = scsi_table },
    { }
};

static ctl_table scsi_root_table[] = {      //dev目录
    { .procname    = "dev",
      .mode        = 0555,
      .child    = scsi_dir_table },
    { }
};

static struct ctl_table_header *scsi_table_header;

int __init scsi_init_sysctl(void) //注册
{
    scsi_table_header = register_sysctl_table(scsi_root_table);
    if (!scsi_table_header)
        return -ENOMEM;
    return 0;
}

void scsi_exit_sysctl(void) //注销
{
    unregister_sysctl_table(scsi_table_header);
}

 

若需要添加多个文件到同一个目录下,可以定义一个模板,每次有新文件要添加到同一个目录下就重用。使用模板的好处是ctl_table结构只需要初始化一个便可贯穿整个目录。

下图显示了/proc/sys/net目录下的组织结构:

阅读(5728) | 评论(1) | 转发(2) |
给主人留下些什么吧!~~

faf882012-11-16 22:30:01

謝謝分享~
与其羡慕别人富有!到不如自己来创造自己的财富!
只要您愿意做,只要您愿意开始做,不用入会费,不用加盟金,
免费注册网址>> http://migre.me/bFG4O
觉得适合你再投入(合法经营,需满18岁)