/proc/sys/kernel/printk
/proc/sys/kernel/printkはファイルのprocfsのinod->sysctl_entryにtable["printk"]を設定し、table["printk"].proc_handlerをコール事で実装されます。引数のログレベルはスペースを区切りとし、正負および8進数/10進数/16進数の設定が可能です。/proc/sys/kernel/printkの引数は.maxlen = 4*sizeof(int)の4つですが、引数を1つとしconsole_loglevelだけ設定する事も可能で、また、syslogシステムコール様な制限はなく、minimum_console_loglevel以下のconsole_loglevelを設定でき、console_loglevel=-1とする事で、ログレベル0のKERN_EMERG等一切のシスログの画面表示を停止できます。CONFIG_PRINTKは/proc/sys/kernel/printkについてでなく、シスログその物の実装にかかるマクロです。
extern int console_printk[]; #define console_loglevel (console_printk[0]) #define default_message_loglevel (console_printk[1]) #define minimum_console_loglevel (console_printk[2]) #define default_console_loglevel (console_printk[3])
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, }, { } }; [root@localhost ~]# ls -l /proc/sys 合計 0 dr-xr-xr-x 0 root root 0 7月 28 23:25 crypto dr-xr-xr-x 0 root root 0 7月 28 23:52 debug dr-xr-xr-x 0 root root 0 7月 28 23:52 dev dr-xr-xr-x 0 root root 0 7月 28 23:25 fs dr-xr-xr-x 0 root root 0 7月 28 23:25 kernel dr-xr-xr-x 0 root root 0 7月 28 23:25 net dr-xr-xr-x 0 root root 0 7月 28 23:52 sunrpc dr-xr-xr-x 0 root root 0 7月 28 23:52 vm
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, }, #ifdef CONFIG_SCHED_DEBUG { .procname = "sched_min_granularity_ns", .data = &sysctl_sched_min_granularity, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_proc_update_handler, .extra1 = &min_sched_granularity_ns, .extra2 = &max_sched_granularity_ns, }, { .procname = "sched_latency_ns", .data = &sysctl_sched_latency, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_proc_update_handler, .extra1 = &min_sched_granularity_ns, .extra2 = &max_sched_granularity_ns, }, { .procname = "sched_wakeup_granularity_ns", .data = &sysctl_sched_wakeup_granularity, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_proc_update_handler, .extra1 = &min_wakeup_granularity_ns, .extra2 = &max_wakeup_granularity_ns, }, { .procname = "sched_tunable_scaling", .data = &sysctl_sched_tunable_scaling, .maxlen = sizeof(enum sched_tunable_scaling), .mode = 0644, .proc_handler = sched_proc_update_handler, .extra1 = &min_sched_tunable_scaling, .extra2 = &max_sched_tunable_scaling, }, { .procname = "sched_migration_cost", .data = &sysctl_sched_migration_cost, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "sched_nr_migrate", .data = &sysctl_sched_nr_migrate, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "sched_time_avg", .data = &sysctl_sched_time_avg, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "sched_shares_window", .data = &sysctl_sched_shares_window, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "timer_migration", .data = &sysctl_timer_migration, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &one, }, #endif { .procname = "sched_rt_period_us", .data = &sysctl_sched_rt_period, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_rt_handler, }, { .procname = "sched_rt_runtime_us", .data = &sysctl_sched_rt_runtime, .maxlen = sizeof(int), .mode = 0644, .proc_handler = sched_rt_handler, }, #ifdef CONFIG_SCHED_AUTOGROUP { .procname = "sched_autogroup_enabled", .data = &sysctl_sched_autogroup_enabled, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &one, }, #endif #ifdef CONFIG_CFS_BANDWIDTH { .procname = "sched_cfs_bandwidth_slice_us", .data = &sysctl_sched_cfs_bandwidth_slice, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &one, }, #endif #ifdef CONFIG_PROVE_LOCKING { .procname = "prove_locking", .data = &prove_locking, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_LOCK_STAT { .procname = "lock_stat", .data = &lock_stat, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "panic", .data = &panic_timeout, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "core_uses_pid", .data = &core_uses_pid, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "core_pattern", .data = core_pattern, .maxlen = CORENAME_MAX_SIZE, .mode = 0644, .proc_handler = proc_dostring, }, { .procname = "core_pipe_limit", .data = &core_pipe_limit, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec, }, #ifdef CONFIG_PROC_SYSCTL { .procname = "tainted", .maxlen = sizeof(long), .mode = 0644, .proc_handler = proc_taint, }, #endif #ifdef CONFIG_LATENCYTOP { .procname = "latencytop", .data = &latencytop_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_BLK_DEV_INITRD { .procname = "real-root-dev", .data = &real_root_dev, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "print-fatal-signals", .data = &print_fatal_signals, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #ifdef CONFIG_SPARC { .procname = "reboot-cmd", .data = reboot_command, .maxlen = 256, .mode = 0644, .proc_handler = proc_dostring, }, { .procname = "stop-a", .data = &stop_a_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "scons-poweroff", .data = &scons_pwroff, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_SPARC64 { .procname = "tsb-ratio", .data = &sysctl_tsb_ratio, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef __hppa__ { .procname = "soft-power", .data = &pwrsw_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "unaligned-trap", .data = &unaligned_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "ctrl-alt-del", .data = &C_A_D, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #ifdef CONFIG_FUNCTION_TRACER { .procname = "ftrace_enabled", .data = &ftrace_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = ftrace_enable_sysctl, }, #endif #ifdef CONFIG_STACK_TRACER { .procname = "stack_tracer_enabled", .data = &stack_tracer_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = stack_trace_sysctl, }, #endif #ifdef CONFIG_TRACING { .procname = "ftrace_dump_on_oops", .data = &ftrace_dump_on_oops, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_MODULES { .procname = "modprobe", .data = &modprobe_path, .maxlen = KMOD_PATH_LEN, .mode = 0644, .proc_handler = proc_dostring, }, { .procname = "modules_disabled", .data = &modules_disabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &one, .extra2 = &one, }, #endif #ifdef CONFIG_HOTPLUG { .procname = "hotplug", .data = &uevent_helper, .maxlen = UEVENT_HELPER_PATH_LEN, .mode = 0644, .proc_handler = proc_dostring, }, #endif #ifdef CONFIG_CHR_DEV_SG { .procname = "sg-big-buff", .data = &sg_big_buff, .maxlen = sizeof (int), .mode = 0444, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_BSD_PROCESS_ACCT { .procname = "acct", .data = &acct_parm, .maxlen = 3*sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_MAGIC_SYSRQ { .procname = "sysrq", .data = &__sysrq_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = sysrq_sysctl_handler, }, #endif #ifdef CONFIG_PROC_SYSCTL { .procname = "cad_pid", .data = NULL, .maxlen = sizeof (int), .mode = 0600, .proc_handler = proc_do_cad_pid, }, #endif { .procname = "threads-max", .data = &max_threads, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "random", .mode = 0555, .child = random_table, }, { .procname = "usermodehelper", .mode = 0555, .child = usermodehelper_table, }, { .procname = "overflowuid", .data = &overflowuid, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &minolduid, .extra2 = &maxolduid, }, { .procname = "overflowgid", .data = &overflowgid, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &minolduid, .extra2 = &maxolduid, }, #ifdef CONFIG_S390 #ifdef CONFIG_MATHEMU { .procname = "ieee_emulation_warnings", .data = &sysctl_ieee_emulation_warnings, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "userprocess_debug", .data = &show_unhandled_signals, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "pid_max", .data = &pid_max, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &pid_max_min, .extra2 = &pid_max_max, }, { .procname = "panic_on_oops", .data = &panic_on_oops, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #if defined CONFIG_PRINTK { .procname = "printk", <----------------- /proc/sys/kernel/printk .data = &console_loglevel, .maxlen = 4*sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "printk_ratelimit", .data = &printk_ratelimit_state.interval, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "printk_ratelimit_burst", .data = &printk_ratelimit_state.burst, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "printk_delay", .data = &printk_delay_msec, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &ten_thousand, }, { .procname = "dmesg_restrict", .data = &dmesg_restrict, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax_sysadmin, .extra1 = &zero, .extra2 = &one, }, { .procname = "kptr_restrict", .data = &kptr_restrict, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax_sysadmin, .extra1 = &zero, .extra2 = &two, }, #endif { .procname = "ngroups_max", .data = &ngroups_max, .maxlen = sizeof (int), .mode = 0444, .proc_handler = proc_dointvec, }, { .procname = "cap_last_cap", .data = (void *)&cap_last_cap, .maxlen = sizeof(int), .mode = 0444, .proc_handler = proc_dointvec, }, #if defined(CONFIG_LOCKUP_DETECTOR) { .procname = "watchdog", .data = &watchdog_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dowatchdog, .extra1 = &zero, .extra2 = &one, }, { .procname = "watchdog_thresh", .data = &watchdog_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dowatchdog, .extra1 = &neg_one, .extra2 = &sixty, }, { .procname = "softlockup_panic", .data = &softlockup_panic, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &one, }, { .procname = "nmi_watchdog", .data = &watchdog_enabled, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dowatchdog, .extra1 = &zero, .extra2 = &one, }, #endif #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) { .procname = "unknown_nmi_panic", .data = &unknown_nmi_panic, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #if defined(CONFIG_X86) { .procname = "panic_on_unrecovered_nmi", .data = &panic_on_unrecovered_nmi, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "panic_on_io_nmi", .data = &panic_on_io_nmi, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #ifdef CONFIG_DEBUG_STACKOVERFLOW { .procname = "panic_on_stackoverflow", .data = &sysctl_panic_on_stackoverflow, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "bootloader_type", .data = &bootloader_type, .maxlen = sizeof (int), .mode = 0444, .proc_handler = proc_dointvec, }, { .procname = "bootloader_version", .data = &bootloader_version, .maxlen = sizeof (int), .mode = 0444, .proc_handler = proc_dointvec, }, { .procname = "kstack_depth_to_print", .data = &kstack_depth_to_print, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "io_delay_type", .data = &io_delay_type, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #if defined(CONFIG_MMU) { .procname = "randomize_va_space", .data = &randomize_va_space, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #if defined(CONFIG_S390) && defined(CONFIG_SMP) { .procname = "spin_retry", .data = &spin_retry, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #if defined(CONFIG_ACPI_SLEEP) && defined(CONFIG_X86) { .procname = "acpi_video_flags", .data = &acpi_realmode_flags, .maxlen = sizeof (unsigned long), .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, #endif #ifdef CONFIG_IA64 { .procname = "ignore-unaligned-usertrap", .data = &no_unaligned_warning, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "unaligned-dump-stack", .data = &unaligned_dump_stack, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_DETECT_HUNG_TASK { .procname = "hung_task_panic", .data = &sysctl_hung_task_panic, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &one, }, { .procname = "hung_task_check_count", .data = &sysctl_hung_task_check_count, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, { .procname = "hung_task_timeout_secs", .data = &sysctl_hung_task_timeout_secs, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = proc_dohung_task_timeout_secs, }, { .procname = "hung_task_warnings", .data = &sysctl_hung_task_warnings, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, #endif #ifdef CONFIG_COMPAT { .procname = "compat-log", .data = &compat_log, .maxlen = sizeof (int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_RT_MUTEXES { .procname = "max_lock_depth", .data = &max_lock_depth, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "poweroff_cmd", .data = &poweroff_cmd, .maxlen = POWEROFF_CMD_PATH_LEN, .mode = 0644, .proc_handler = proc_dostring, }, #ifdef CONFIG_KEYS { .procname = "keys", .mode = 0555, .child = key_sysctls, }, #endif #ifdef CONFIG_RCU_TORTURE_TEST { .procname = "rcutorture_runnable", .data = &rcutorture_runnable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_PERF_EVENTS { .procname = "perf_event_paranoid", .data = &sysctl_perf_event_paranoid, .maxlen = sizeof(sysctl_perf_event_paranoid), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "perf_event_mlock_kb", .data = &sysctl_perf_event_mlock, .maxlen = sizeof(sysctl_perf_event_mlock), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "perf_event_max_sample_rate", .data = &sysctl_perf_event_sample_rate, .maxlen = sizeof(sysctl_perf_event_sample_rate), .mode = 0644, .proc_handler = perf_proc_update_handler, }, #endif #ifdef CONFIG_KMEMCHECK { .procname = "kmemcheck", .data = &kmemcheck_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_BLOCK { .procname = "blk_iopoll", .data = &blk_iopoll_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { } }; [root@localhost ~]# ls -l /proc/sys/kernel/ 合計 0 -rw-r--r-- 1 root root 0 7月 28 23:52 acct -rw-r--r-- 1 root root 0 7月 28 23:52 acpi_video_flags -rw-r--r-- 1 root root 0 7月 28 23:52 auto_msgmni -rw-r--r-- 1 root root 0 7月 28 23:52 blk_iopoll -r--r--r-- 1 root root 0 7月 28 23:52 bootloader_type -r--r--r-- 1 root root 0 7月 28 23:52 bootloader_version -rw------- 1 root root 0 7月 28 23:52 cad_pid -r--r--r-- 1 root root 0 7月 28 23:52 cap_last_cap -rw-r--r-- 1 root root 0 7月 28 23:25 core_pattern -rw-r--r-- 1 root root 0 7月 28 23:25 core_pipe_limit -rw-r--r-- 1 root root 0 7月 28 23:25 core_uses_pid -rw-r--r-- 1 root root 0 7月 28 23:52 ctrl-alt-del -rw-r--r-- 1 root root 0 7月 28 23:52 dmesg_restrict -rw-r--r-- 1 root root 0 7月 28 23:52 domainname -rw-r--r-- 1 root root 0 7月 28 23:52 ftrace_dump_on_oops -rw-r--r-- 1 root root 0 7月 28 23:52 ftrace_enabled -rw-r--r-- 1 root root 0 7月 28 23:52 hostname -rw-r--r-- 1 root root 0 7月 28 23:52 hotplug -rw-r--r-- 1 root root 0 7月 28 23:52 io_delay_type dr-xr-xr-x 0 root root 0 7月 28 23:52 keys -rw-r--r-- 1 root root 0 7月 28 23:52 kptr_restrict -rw-r--r-- 1 root root 0 7月 28 23:52 kstack_depth_to_print -rw-r--r-- 1 root root 0 7月 28 23:52 latencytop -rw-r--r-- 1 root root 0 7月 28 23:52 max_lock_depth -rw-r--r-- 1 root root 0 7月 28 23:52 modprobe -rw-r--r-- 1 root root 0 7月 28 23:52 modules_disabled -rw-r--r-- 1 root root 0 7月 28 23:52 msgmax -rw-r--r-- 1 root root 0 7月 28 23:52 msgmnb -rw-r--r-- 1 root root 0 7月 28 23:52 msgmni -r--r--r-- 1 root root 0 7月 28 23:25 ngroups_max -rw-r--r-- 1 root root 0 7月 28 23:52 nmi_watchdog -rw-rw-rw- 1 root root 0 7月 28 23:52 ns_last_pid -r--r--r-- 1 root root 0 7月 28 23:52 osrelease -r--r--r-- 1 root root 0 7月 28 23:52 ostype -rw-r--r-- 1 root root 0 7月 28 23:52 overflowgid -rw-r--r-- 1 root root 0 7月 28 23:52 overflowuid -rw-r--r-- 1 root root 0 7月 28 23:52 panic -rw-r--r-- 1 root root 0 7月 28 23:52 panic_on_io_nmi -rw-r--r-- 1 root root 0 7月 28 23:52 panic_on_oops -rw-r--r-- 1 root root 0 7月 28 23:52 panic_on_stackoverflow -rw-r--r-- 1 root root 0 7月 28 23:52 panic_on_unrecovered_nmi -rw-r--r-- 1 root root 0 7月 28 23:52 perf_event_max_sample_rate -rw-r--r-- 1 root root 0 7月 28 23:52 perf_event_mlock_kb -rw-r--r-- 1 root root 0 7月 28 23:52 perf_event_paranoid -rw-r--r-- 1 root root 0 7月 28 23:52 pid_max -rw-r--r-- 1 root root 0 7月 28 23:52 poweroff_cmd -rw-r--r-- 1 root root 0 7月 28 23:52 print-fatal-signals -rw-r--r-- 1 root root 0 7月 29 01:08 printk -rw-r--r-- 1 root root 0 7月 28 23:52 printk_delay -rw-r--r-- 1 root root 0 7月 28 23:52 printk_ratelimit -rw-r--r-- 1 root root 0 7月 28 23:52 printk_ratelimit_burst dr-xr-xr-x 0 root root 0 7月 28 23:52 pty dr-xr-xr-x 0 root root 0 7月 28 23:25 random -rw-r--r-- 1 root root 0 7月 28 23:52 randomize_va_space -rw-r--r-- 1 root root 0 7月 28 23:52 real-root-dev -rw-r--r-- 1 root root 0 7月 28 23:52 sched_autogroup_enabled -rw-r--r-- 1 root root 0 7月 28 23:52 sched_cfs_bandwidth_slice_us -rw-r--r-- 1 root root 0 7月 28 23:52 sched_child_runs_first dr-xr-xr-x 0 root root 0 7月 28 23:52 sched_domain -rw-r--r-- 1 root root 0 7月 28 23:52 sched_latency_ns -rw-r--r-- 1 root root 0 7月 28 23:52 sched_migration_cost -rw-r--r-- 1 root root 0 7月 28 23:52 sched_min_granularity_ns -rw-r--r-- 1 root root 0 7月 28 23:52 sched_nr_migrate -rw-r--r-- 1 root root 0 7月 28 23:52 sched_rt_period_us -rw-r--r-- 1 root root 0 7月 28 23:52 sched_rt_runtime_us -rw-r--r-- 1 root root 0 7月 28 23:52 sched_shares_window -rw-r--r-- 1 root root 0 7月 28 23:52 sched_time_avg -rw-r--r-- 1 root root 0 7月 28 23:52 sched_tunable_scaling -rw-r--r-- 1 root root 0 7月 28 23:52 sched_wakeup_granularity_ns -rw-r--r-- 1 root root 0 7月 28 23:52 sem -r--r--r-- 1 root root 0 7月 28 23:52 sg-big-buff -rw-r--r-- 1 root root 0 7月 28 23:52 shm_rmid_forced -rw-r--r-- 1 root root 0 7月 28 23:52 shmall -rw-r--r-- 1 root root 0 7月 28 23:52 shmmax -rw-r--r-- 1 root root 0 7月 28 23:52 shmmni -rw-r--r-- 1 root root 0 7月 28 23:52 softlockup_panic -rw-r--r-- 1 root root 0 7月 28 23:52 stack_tracer_enabled -rw-r--r-- 1 root root 0 7月 28 23:25 sysrq -rw-r--r-- 1 root root 0 7月 28 23:52 tainted -rw-r--r-- 1 root root 0 7月 28 23:52 threads-max -rw-r--r-- 1 root root 0 7月 28 23:52 timer_migration -rw-r--r-- 1 root root 0 7月 28 23:52 unknown_nmi_panic dr-xr-xr-x 0 root root 0 7月 28 23:52 usermodehelper -r--r--r-- 1 root root 0 7月 28 23:52 version -rw-r--r-- 1 root root 0 7月 28 23:52 watchdog -rw-r--r-- 1 root root 0 7月 28 23:52 watchdog_thresh
static const struct file_operations proc_sys_file_operations = { .open = proc_sys_open, .poll = proc_sys_poll, .read = proc_sys_read, .write = proc_sys_write, .llseek = default_llseek, }; static ssize_t proc_sys_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0); } static ssize_t proc_sys_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); } static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, size_t count, loff_t *ppos, int write) { struct inode *inode = filp->f_path.dentry->d_inode; struct ctl_table_header *head = grab_header(inode); struct ctl_table *table = PROC_I(inode)->sysctl_entry; ssize_t error; size_t res; if (IS_ERR(head)) return PTR_ERR(head); error = -EPERM; if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ)) goto out; error = -EINVAL; if (!table->proc_handler) goto out; res = count; error = table->proc_handler(table, write, buf, &res, ppos); if (!error) error = res; out: sysctl_head_finish(head); return error; } int proc_dointvec(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { return do_proc_dointvec(table,write,buffer,lenp,ppos, NULL,NULL); } static int do_proc_dointvec(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *lvalp, int *valp, int write, void *data), void *data) { return __do_proc_dointvec(table->data, table, write, buffer, lenp, ppos, conv, data); } static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *lvalp, int *valp, int write, void *data), void *data) { int *i, vleft, first = 1, err = 0; unsigned long page = 0; size_t left; char *kbuf; if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { *lenp = 0; return 0; } i = (int *) tbl_data; vleft = table->maxlen / sizeof(*i); left = *lenp; if (!conv) conv = do_proc_dointvec_conv; if (write) { if (left > PAGE_SIZE - 1) left = PAGE_SIZE - 1; page = __get_free_page(GFP_TEMPORARY); kbuf = (char *) page; if (!kbuf) return -ENOMEM; if (copy_from_user(kbuf, buffer, left)) { err = -EFAULT; goto free; } kbuf[left] = 0; } for (; left && vleft--; i++, first=0) { unsigned long lval; bool neg; if (write) { left -= proc_skip_spaces(&kbuf); if (!left) break; err = proc_get_long(&kbuf, &left, &lval, &neg, proc_wspace_sep, sizeof(proc_wspace_sep), NULL); if (err) break; if (conv(&neg, &lval, i, 1, data)) { err = -EINVAL; break; } } else { if (conv(&neg, &lval, i, 0, data)) { err = -EINVAL; break; } if (!first) err = proc_put_char(&buffer, &left, '\t'); if (err) break; err = proc_put_long(&buffer, &left, lval, neg); if (err) break; } } if (!write && !first && left && !err) err = proc_put_char(&buffer, &left, '\n'); if (write && !err && left) left -= proc_skip_spaces(&kbuf); free: if (write) { free_page(page); if (first) return err ? : -EINVAL; } *lenp -= left; *ppos += *lenp; return err; }正負および8進数/10進数/16進数の取得。
static int proc_get_long(char **buf, size_t *size, unsigned long *val, bool *neg, const char *perm_tr, unsigned perm_tr_len, char *tr) { int len; char *p, tmp[TMPBUFLEN]; if (!*size) return -EINVAL; len = *size; if (len > TMPBUFLEN - 1) len = TMPBUFLEN - 1; memcpy(tmp, *buf, len); tmp[len] = 0; p = tmp; if (*p == '-' && *size > 1) { *neg = true; p++; } else *neg = false; if (!isdigit(*p)) return -EINVAL; *val = simple_strtoul(p, &p, 0); len = p - tmp; if (len == TMPBUFLEN - 1) return -EINVAL; if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len)) return -EINVAL; if (tr && (len < *size)) *tr = *p; *buf += len; *size -= len; return 0; } unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { return simple_strtoull(cp, endp, base); } unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) { unsigned long long result; unsigned int rv; cp = _parse_integer_fixup_radix(cp, &base); rv = _parse_integer(cp, base, &result); cp += (rv & ~KSTRTOX_OVERFLOW); if (endp) *endp = (char *)cp; return result; } const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) { if (*base == 0) { if (s[0] == '0') { if (_tolower(s[1]) == 'x' && isxdigit(s[2])) *base = 16; else *base = 8; } else *base = 10; } if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') s += 2; return s; }
補足
/proc/sys下の struct ctl_table kern_table[]等のinodeを作成時、struct proc_inode *ei->sysctl_entry = tableで、掛かるファイルinodeからの参照領域の取得を実装します。static struct inode *proc_sys_make_inode(struct super_block *sb, struct ctl_table_header *head, struct ctl_table *table) { struct inode *inode; struct proc_inode *ei; inode = new_inode(sb); if (!inode) goto out; inode->i_ino = get_next_ino(); sysctl_head_get(head); ei = PROC_I(inode); ei->sysctl = head; ei->sysctl_entry = table; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mode = table->mode; if (!table->child) { inode->i_mode |= S_IFREG; inode->i_op = &proc_sys_inode_operations; inode->i_fop = &proc_sys_file_operations; } else { inode->i_mode |= S_IFDIR; clear_nlink(inode); inode->i_op = &proc_sys_dir_operations; inode->i_fop = &proc_sys_dir_file_operations; } out: return inode; } static const struct file_operations proc_sys_dir_file_operations = { .read = generic_read_dir, .readdir = proc_sys_readdir, .llseek = generic_file_llseek, }; static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct ctl_table_header *head = grab_header(inode); struct ctl_table *table = PROC_I(inode)->sysctl_entry; struct ctl_table_header *h = NULL; unsigned long pos; int ret = -EINVAL; if (IS_ERR(head)) return PTR_ERR(head); if (table && !table->child) { WARN_ON(1); goto out; } table = table ? table->child : head->ctl_table; ret = 0; if (filp->f_pos == 0) { if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos++; } if (filp->f_pos == 1) { if (filldir(dirent, "..", 2, filp->f_pos, parent_ino(dentry), DT_DIR) < 0) goto out; filp->f_pos++; } pos = 2; ret = scan(head, table, &pos, filp, dirent, filldir); if (ret) goto out; for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { if (h->attached_to != table) continue; ret = scan(h, h->attached_by, &pos, filp, dirent, filldir); if (ret) { sysctl_head_finish(h); break; } } ret = 1; out: sysctl_head_finish(head); return ret; } static int scan(struct ctl_table_header *head, ctl_table *table, unsigned long *pos, struct file *file, void *dirent, filldir_t filldir) { for (; table->procname; table++, (*pos)++) { int res; if (!table->procname) continue; if (*pos < file->f_pos) continue; res = proc_sys_fill_cache(file, dirent, filldir, head, table); if (res) return res; file->f_pos = *pos + 1; } return 0; } static int proc_sys_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct ctl_table_header *head, struct ctl_table *table) { struct dentry *child, *dir = filp->f_path.dentry; struct inode *inode; struct qstr qname; ino_t ino = 0; unsigned type = DT_UNKNOWN; qname.name = table->procname; qname.len = strlen(table->procname); qname.hash = full_name_hash(qname.name, qname.len); child = d_lookup(dir, &qname); if (!child) { child = d_alloc(dir, &qname); if (child) { inode = proc_sys_make_inode(dir->d_sb, head, table); if (!inode) { dput(child); return -ENOMEM; } else { d_set_d_op(child, &proc_sys_dentry_operations); d_add(child, inode); } } else { return -ENOMEM; } } inode = child->d_inode; ino = inode->i_ino; type = inode->i_mode >> 12; dput(child); return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); } static struct inode *proc_sys_make_inode(struct super_block *sb, struct ctl_table_header *head, struct ctl_table *table) { struct inode *inode; struct proc_inode *ei; inode = new_inode(sb); if (!inode) goto out; inode->i_ino = get_next_ino(); sysctl_head_get(head); ei = PROC_I(inode); ei->sysctl = head; ei->sysctl_entry = table; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mode = table->mode; if (!table->child) { inode->i_mode |= S_IFREG; inode->i_op = &proc_sys_inode_operations; inode->i_fop = &proc_sys_file_operations; } else { inode->i_mode |= S_IFDIR; clear_nlink(inode); inode->i_op = &proc_sys_dir_operations; inode->i_fop = &proc_sys_dir_file_operations; } out: return inode; }
補足
proc_dointvec_minmax()はdo_proc_dointvec()でのvoid *data=NULLでなく、struct ctl_table *table->extra1/extra2の最大値/最小値をチェックするdo_proc_dointvec_minmax_convをコールバックにします。int proc_dointvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct do_proc_dointvec_minmax_conv_param param = { .min = (int *) table->extra1, .max = (int *) table->extra2, }; return do_proc_dointvec(table, write, buffer, lenp, ppos, do_proc_dointvec_minmax_conv, ¶m); } static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, int *valp, int write, void *data) { struct do_proc_dointvec_minmax_conv_param *param = data; if (write) { int val = *negp ? -*lvalp : *lvalp; if ((param->min && *param->min > val) || (param->max && *param->max < val)) return -EINVAL; *valp = val; } else { int val = *valp; if (val < 0) { *negp = true; *lvalp = (unsigned long)-val; } else { *negp = false; *lvalp = (unsigned long)val; } } return 0; }