sysctl使用方法的变化
内核版本:3.6
Author:zhangskd @ csdn blog
Change
在v3.4中包含一个patch,提交者Eric W. Biederman描述如下:
Rewrite of sysctl for speed and charity.
Insert/remove/Lookup in sysctl are now O(NlogN) operations, and are no longer bottlenecks in the
process of adding and removing network devices.
sysctl is now focused on being a filesystem instead of system call and the code can be found in
fs/proc/proc_sysctl.c. Hopefully this means the code is now approachable.
可见sysctl的实现发生了较大的变化。
但是这对sysctl的使用有什么影响呢?再来看另一个相关patch:
sysctl: Add register_sysctl for normal sysctl users
The plan is to convert all callers of register_sysctl_table and register_sysctl_paths to register_sysctl.
The interface to register_sysctl is enough nicer. This should make the callers a bit more readable.
Additionally after the conversion the 230 lines of backwards compatibility can be removed.
可见sysctl的注册函数发生了变化,现在是:
/** * register_sysctl - register a sysctl table * @path: The path to the directory the sysctl table is in. * @table: the table structure * * Register a sysctl table. @table should be a filled in ctl_table array. * A completely 0 filled entry terminates the table. * * See __register_sysctl_table for more details. */ struct ctl_table_header *register_sysctl (const char *path, struct ctl_table *table);
之前的注册函数为:
struct ctl_table_header *register_sysctl_table (struct ctl_table *table);
也就是说现在可以通过注册函数来指定注册的路径,更加方便了。
注销函数不变:
/** * unregister_sysctl_table - unregister a sysctl table hierarchy * @header: the header returned from register_sysctl_table * * Unregisters the sysctl table and all children. proc entires may not actually * be removed until they are no longer used by anyone. */ void unregister_sysctl_table (struct ctl_table_header *header);
structure
现在的ctl_table:
@include/linux/sysctl.h
/* A sysctl table is an array of struct ctl_table: */ struct ctl_table { const char *procname; /* Text ID for /proc/sys, or zero,文件名 */ void * data; int maxlen; umode_t mode; struct ctl_table *child; /* Deprecated */ proc_handler *proc_handler; /* Callback for text formatting,读写操作函数 */ struct ctl_table_poll *poll; void *extra1; /* 变量的最小值min */ void *extra2; /* 变量的最大值max */ }
proc_handler的常用取值:
proc_dointvec /* 读写一个包含一个或多个整数的数组*/
proc_dostring /* 读写一个字符串*/
proc_dointvec_minmax /* 写的数组必须在min~max范围内*/
一个instance:
@net/ipv4/sysctl_net_ipv4.c
static struct ctl_table ipv4_table[] = { ... { .procname = "tcp_congestion_control", .mode = 0644; .maxlen = TCP_CA_NAME_MAX, .proc_handler = proc_tcp_congestion_control, }, ... { .procname = "tcp_early_retrans", .data = &sysctl_tcp_early_retrans, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &two, }, ... };
这些选项的简要说明在:Documentation/networking/ipv4/*
这些选项的定义在:net/ipv4/tcp_input.c
command
sysctl — configure kernel parameters at runtime
sysctl is used to modify kernel parameters at runtime. The parameters available are those listed under /proc/sys/.
Procfs is required for sysctl support in Linux. You can use sysctl to both read and write sysctl data.
使用:
sysctl net.ipv4.tcp_congestion_control // read
sysctl -w net.ipv4.tcp_congestion_control = "cubic" // write
example
这是新的使用方法示例:
#include <linux/init.h> #include <linux/module.h> #include <linux/sysctl.h> #include <linux/kernel.h> static char path[] = "net/test"; static int zero = 0; static int two = 2; int sysctl_tcp_new; static struct ctl_table_header *header; static struct ctl_table new[] = { { .procname = "tcp_new", .data = &sysctl_tcp_new, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &two }, { } }; static int __init sysctl_module_init(void) { header = register_sysctl(path, new); if(!header) { printk(KERN_ERR"register_sysctl() failed.\n"); return -1; } return 0; } static void __exit sysctl_module_exit(void) { if(header) unregister_sysctl_table(header); } module_init(sysctl_module_init); module_exit(sysctl_module_exit); MODULE_AUTHOR("zhangsk"); MODULE_LICENSE("GPL");
模块加载时,就自动创建目录/proc/sys/net/test/,并在其下创建文件tcp_new,取值可为0、1或2。
模块卸载时,此目录则会被删除,当然这是在没人使用了之后。
这是旧的使用方法示例:
#include <linux/init.h> #include <linux/module.h> #include <linux/sysctl.h> static int zero = 0; static int two = 2; int sysctl_tcp_new; static struct ctl_table_header *header; static struct ctl_table my_table[] = { { .procname = "tcp_new", .data = &sysctl_tcp_new, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &two, }, {}, }; static struct ctl_table test_dir_table[] = { { .procname = "test", .mode = 0555, .child = my_table, }, {}, }; static struct ctl_table net_dir_table[] = { { .procname = "net", .mode = 0555, .child = test_dir_table, }, {}, }; static int __init sysctl_module_init(void) { header = register_sysctl_table(net_dir_table); if(!header) { printk(KERN_ERR"register_sysctl_table() failed.\n"); return -1; } return 0; } static void __exit sysctl_module_exit(void) { if(header) unregister_sysctl_table(header); } module_init(sysctl_module_init); module_exit(sysctl_module_exit); MODULE_AUTHOR("zhangsk"); MODULE_LICENSE("GPL");