sysctl

xiaoxiao2021-02-28  55

在kernel/sysctl.c 中有定义sysctl_init int __init sysctl_init(void) { struct ctl_table_header *hdr; hdr = register_sysctl_table(sysctl_base_table); kmemleak_not_leak(hdr); return 0; } 这个函数会在proc/sys 目录下新建四个目录,这四个新建的目录是在sysctl_base_table 中有定义 static struct ctl_table sysctl_base_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, }, { } }; 这四个目录下可以新建子目录或者新建文件,以kernel 这个目录为例 static struct ctl_table kern_table[] = { { .procname = "sched_child_runs_first", .data = &sysctl_sched_child_runs_first, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, } 通过cat 就可以读取或者echo就可以改变sched_child_runs_first 这个参数的值。从proc_dointvec 可以知道这个值是int类型的extern unsigned int sysctl_sched_child_runs_first;

如果想在自己的驱动中往proc/sys下面添加目录或者文件的话,可以参考下面在net目录下添加net/ipv4/route static __net_init int sysctl_route_net_init(struct net *net) { struct ctl_table *tbl; tbl = ipv4_route_flush_table; if (!net_eq(net, &init_net)) { tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); if (!tbl) goto err_dup; /* Don't export sysctls to unprivileged users */ if (net->user_ns != &init_user_ns) tbl[0].procname = NULL; } tbl[0].extra1 = net; net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl); if (!net->ipv4.route_hdr) goto err_reg; return 0; err_reg: if (tbl != ipv4_route_flush_table) kfree(tbl); err_dup: return -ENOMEM; } 那我们看看register_net_sysctl 是如何添加的呢? struct ctl_table_header *register_net_sysctl(struct net *net, const char *path, struct ctl_table *table) { //可以看到代表net device的struct net *net 有一个变量代表/proc/sys/net 这个sysctl的路径。第二个参数path 表示要插入的路径,第三个参数表示ctl_table *table return __register_sysctl_table(&net->sysctls, path, table); } struct ctl_table_header *__register_sysctl_table( struct ctl_table_set *set, const char *path, struct ctl_table *table) { struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *header; const char *name, *nextname; struct ctl_dir *dir; struct ctl_table *entry; struct ctl_node *node; int nr_entries = 0; for (entry = table; entry->procname; entry++) nr_entries++; header = kzalloc(sizeof(struct ctl_table_header) + sizeof(struct ctl_node)*nr_entries, GFP_KERNEL); if (!header) return NULL; node = (struct ctl_node *)(header + 1); init_header(header, root, set, node, table); if (sysctl_check_table(path, table)) goto fail; spin_lock(&sysctl_lock); dir = &set->dir; /* Reference moved down the diretory tree get_subdir */ dir->header.nreg++; spin_unlock(&sysctl_lock); /* Find the directory for the ctl_table */ for (name = path; name; name = nextname) { int namelen; nextname = strchr(name, '/'); if (nextname) { namelen = nextname - name; nextname++; } else { namelen = strlen(name); } if (namelen == 0) continue; //找到需要插入的目录 dir = get_subdir(dir, name, namelen); if (IS_ERR(dir)) goto fail; } spin_lock(&sysctl_lock); //出入当前需要注册的ctl_table *table if (insert_header(dir, header)) goto fail_put_dir_locked; drop_sysctl_table(&dir->header); spin_unlock(&sysctl_lock); return header; fail_put_dir_locked: drop_sysctl_table(&dir->header); spin_unlock(&sysctl_lock); fail: kfree(header); dump_stack(); return NULL; }

转载请注明原文地址: https://www.6miu.com/read-40446.html

最新回复(0)