📄 sysctl.c
字号:
#ifdef CONFIG_NUMA { .ctl_name = VM_ZONE_RECLAIM_MODE, .procname = "zone_reclaim_mode", .data = &zone_reclaim_mode, .maxlen = sizeof(zone_reclaim_mode), .mode = 0644, .proc_handler = &proc_dointvec, .strategy = &sysctl_intvec, .extra1 = &zero, }, { .ctl_name = VM_MIN_UNMAPPED, .procname = "min_unmapped_ratio", .data = &sysctl_min_unmapped_ratio, .maxlen = sizeof(sysctl_min_unmapped_ratio), .mode = 0644, .proc_handler = &sysctl_min_unmapped_ratio_sysctl_handler, .strategy = &sysctl_intvec, .extra1 = &zero, .extra2 = &one_hundred, }, { .ctl_name = VM_MIN_SLAB, .procname = "min_slab_ratio", .data = &sysctl_min_slab_ratio, .maxlen = sizeof(sysctl_min_slab_ratio), .mode = 0644, .proc_handler = &sysctl_min_slab_ratio_sysctl_handler, .strategy = &sysctl_intvec, .extra1 = &zero, .extra2 = &one_hundred, },#endif#ifdef CONFIG_SMP { .ctl_name = CTL_UNNUMBERED, .procname = "stat_interval", .data = &sysctl_stat_interval, .maxlen = sizeof(sysctl_stat_interval), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, },#endif#ifdef CONFIG_SECURITY { .ctl_name = CTL_UNNUMBERED, .procname = "mmap_min_addr", .data = &mmap_min_addr, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = &proc_doulongvec_minmax, },#endif#ifdef CONFIG_NUMA { .ctl_name = CTL_UNNUMBERED, .procname = "numa_zonelist_order", .data = &numa_zonelist_order, .maxlen = NUMA_ZONELIST_ORDER_LEN, .mode = 0644, .proc_handler = &numa_zonelist_order_handler, .strategy = &sysctl_string, },#endif#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \ (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) { .ctl_name = VM_VDSO_ENABLED, .procname = "vdso_enabled", .data = &vdso_enabled, .maxlen = sizeof(vdso_enabled), .mode = 0644, .proc_handler = &proc_dointvec, .strategy = &sysctl_intvec, .extra1 = &zero, },#endif#ifdef CONFIG_HIGHMEM { .ctl_name = CTL_UNNUMBERED, .procname = "highmem_is_dirtyable", .data = &vm_highmem_is_dirtyable, .maxlen = sizeof(vm_highmem_is_dirtyable), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, .extra1 = &zero, .extra2 = &one, },#endif/* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt */ { .ctl_name = 0 }};#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)static struct ctl_table binfmt_misc_table[] = { { .ctl_name = 0 }};#endifstatic struct ctl_table fs_table[] = { { .ctl_name = FS_NRINODE, .procname = "inode-nr", .data = &inodes_stat, .maxlen = 2*sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, { .ctl_name = FS_STATINODE, .procname = "inode-state", .data = &inodes_stat, .maxlen = 7*sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, { .procname = "file-nr", .data = &files_stat, .maxlen = 3*sizeof(int), .mode = 0444, .proc_handler = &proc_nr_files, }, { .ctl_name = FS_MAXFILE, .procname = "file-max", .data = &files_stat.max_files, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, .procname = "nr_open", .data = &sysctl_nr_open, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .extra1 = &sysctl_nr_open_min, .extra2 = &sysctl_nr_open_max, }, { .ctl_name = FS_DENTRY, .procname = "dentry-state", .data = &dentry_stat, .maxlen = 6*sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, { .ctl_name = FS_OVERFLOWUID, .procname = "overflowuid", .data = &fs_overflowuid, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, .extra1 = &minolduid, .extra2 = &maxolduid, }, { .ctl_name = FS_OVERFLOWGID, .procname = "overflowgid", .data = &fs_overflowgid, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, .extra1 = &minolduid, .extra2 = &maxolduid, }, { .ctl_name = FS_LEASES, .procname = "leases-enable", .data = &leases_enable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },#ifdef CONFIG_DNOTIFY { .ctl_name = FS_DIR_NOTIFY, .procname = "dir-notify-enable", .data = &dir_notify_enable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },#endif#ifdef CONFIG_MMU { .ctl_name = FS_LEASE_TIME, .procname = "lease-break-time", .data = &lease_break_time, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, .extra1 = &zero, .extra2 = &two, }, { .procname = "aio-nr", .data = &aio_nr, .maxlen = sizeof(aio_nr), .mode = 0444, .proc_handler = &proc_doulongvec_minmax, }, { .procname = "aio-max-nr", .data = &aio_max_nr, .maxlen = sizeof(aio_max_nr), .mode = 0644, .proc_handler = &proc_doulongvec_minmax, },#ifdef CONFIG_INOTIFY_USER { .ctl_name = FS_INOTIFY, .procname = "inotify", .mode = 0555, .child = inotify_table, },#endif #endif { .ctl_name = KERN_SETUID_DUMPABLE, .procname = "suid_dumpable", .data = &suid_dumpable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) { .ctl_name = CTL_UNNUMBERED, .procname = "binfmt_misc", .mode = 0555, .child = binfmt_misc_table, },#endif/* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt */ { .ctl_name = 0 }};static struct ctl_table debug_table[] = {#if defined(CONFIG_X86) || defined(CONFIG_PPC) { .ctl_name = CTL_UNNUMBERED, .procname = "exception-trace", .data = &show_unhandled_signals, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec },#endif { .ctl_name = 0 }};static struct ctl_table dev_table[] = { { .ctl_name = 0 }};static DEFINE_SPINLOCK(sysctl_lock);/* called under sysctl_lock */static int use_table(struct ctl_table_header *p){ if (unlikely(p->unregistering)) return 0; p->used++; return 1;}/* called under sysctl_lock */static void unuse_table(struct ctl_table_header *p){ if (!--p->used) if (unlikely(p->unregistering)) complete(p->unregistering);}/* called under sysctl_lock, will reacquire if has to wait */static void start_unregistering(struct ctl_table_header *p){ /* * if p->used is 0, nobody will ever touch that entry again; * we'll eliminate all paths to it before dropping sysctl_lock */ if (unlikely(p->used)) { struct completion wait; init_completion(&wait); p->unregistering = &wait; spin_unlock(&sysctl_lock); wait_for_completion(&wait); spin_lock(&sysctl_lock); } else { /* anything non-NULL; we'll never dereference it */ p->unregistering = ERR_PTR(-EINVAL); } /* * do not remove from the list until nobody holds it; walking the * list in do_sysctl() relies on that. */ list_del_init(&p->ctl_entry);}void sysctl_head_get(struct ctl_table_header *head){ spin_lock(&sysctl_lock); head->count++; spin_unlock(&sysctl_lock);}void sysctl_head_put(struct ctl_table_header *head){ spin_lock(&sysctl_lock); if (!--head->count) kfree(head); spin_unlock(&sysctl_lock);}struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head){ if (!head) BUG(); spin_lock(&sysctl_lock); if (!use_table(head)) head = ERR_PTR(-ENOENT); spin_unlock(&sysctl_lock); return head;}void sysctl_head_finish(struct ctl_table_header *head){ if (!head) return; spin_lock(&sysctl_lock); unuse_table(head); spin_unlock(&sysctl_lock);}static struct ctl_table_set *lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces){ struct ctl_table_set *set = &root->default_set; if (root->lookup) set = root->lookup(root, namespaces); return set;}static struct list_head *lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces){ struct ctl_table_set *set = lookup_header_set(root, namespaces); return &set->list;}struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, struct ctl_table_header *prev){ struct ctl_table_root *root; struct list_head *header_list; struct ctl_table_header *head; struct list_head *tmp; spin_lock(&sysctl_lock); if (prev) { head = prev; tmp = &prev->ctl_entry; unuse_table(prev); goto next; } tmp = &root_table_header.ctl_entry; for (;;) { head = list_entry(tmp, struct ctl_table_header, ctl_entry); if (!use_table(head)) goto next; spin_unlock(&sysctl_lock); return head; next: root = head->root; tmp = tmp->next; header_list = lookup_header_list(root, namespaces); if (tmp != header_list) continue; do { root = list_entry(root->root_list.next, struct ctl_table_root, root_list); if (root == &sysctl_table_root) goto out; header_list = lookup_header_list(root, namespaces); } while (list_empty(header_list)); tmp = header_list->next; }out: spin_unlock(&sysctl_lock); return NULL;}struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev){ return __sysctl_head_next(current->nsproxy, prev);}void register_sysctl_root(struct ctl_table_root *root){ spin_lock(&sysctl_lock); list_add_tail(&root->root_list, &sysctl_table_root.root_list); spin_unlock(&sysctl_lock);}#ifdef CONFIG_SYSCTL_SYSCALL/* Perform the actual read/write of a sysctl table entry. */static int do_sysctl_strategy(struct ctl_table_root *root, struct ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen){ int op = 0, rc; if (oldval) op |= MAY_READ; if (newval) op |= MAY_WRITE; if (sysctl_perm(root, table, op)) return -EPERM; if (table->strategy) { rc = table->strategy(table, name, nlen, oldval, oldlenp, newval, newlen); if (rc < 0) return rc; if (rc > 0) return 0; } /* If there is no strategy routine, or if the strategy returns * zero, proceed with automatic r/w */ if (table->data && table->maxlen) { rc = sysctl_data(table, name, nlen, oldval, oldlenp, newval, newlen); if (rc < 0) return rc; } return 0;}static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, struct ctl_table_root *root, struct ctl_table *table){ int n;repeat: if (!nlen) return -ENOTDIR; if (get_user(n, name)) return -EFAULT; for ( ; table->ctl_name || table->procname; table++) { if (!table->ctl_name) continue; if (n == table->ctl_name) { int error; if (table->child) { if (sysctl_perm(root, table, MAY_EXEC)) return -EPERM; name++; nlen--; table = table->child; goto repeat; } error = do_sysctl_strategy(root, table, name, nlen, oldval, oldlenp, newval, newlen); return error; } } return -ENOTDIR;}int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen){ struct ctl_table_header *head; int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; if (oldval) { int old_len; if (!oldlenp || get_user(old_len, oldlenp)) return -EFAULT; } for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) { error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->root, head->ctl_table); if (error != -ENOTDIR) { sysctl_head_finish(head); break; } } return error;}asmlinkage long sys_sysctl(struct __sysctl_args __user *args){ struct __sysctl_args tmp; int error; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; error = deprecated_sysctl_warning(&tmp); if (error) goto out; lock_kernel(); error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, tmp.newval, tmp.newlen); unlock_kernel();out: return error;}#endif /* CONFIG_SYSCTL_SYSCALL *//* * sysctl_perm does NOT grant the superuser all rights automatically, because
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -