Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3115253
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-09-03 19:28:57

原文地址:http://blog.chinaunix.net/uid-14518381-id-3409876.html

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目录下的组织结构:

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