diff --git a/arch/m68k/configs/amcore_defconfig b/arch/m68k/configs/amcore_defconfig index f310b5dacfd8..49f1de51d87e 100644 --- a/arch/m68k/configs/amcore_defconfig +++ b/arch/m68k/configs/amcore_defconfig @@ -74,7 +74,7 @@ CONFIG_RTC_DRV_DS1307=y # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY_USER is not set CONFIG_FSCACHE=y -# CONFIG_PROC_SYSCTL is not set +# CONFIG_SYSCTL is not set CONFIG_JFFS2_FS=y CONFIG_ROMFS_FS=y CONFIG_ROMFS_BACKED_BY_BOTH=y diff --git a/arch/m68k/configs/stmark2_defconfig b/arch/m68k/configs/stmark2_defconfig index b3fb95f73a95..cd454369bfe8 100644 --- a/arch/m68k/configs/stmark2_defconfig +++ b/arch/m68k/configs/stmark2_defconfig @@ -87,7 +87,7 @@ CONFIG_EXT4_FS_SECURITY=y # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY_USER is not set CONFIG_OVERLAY_FS=y -# CONFIG_PROC_SYSCTL is not set +# CONFIG_SYSCTL is not set CONFIG_SQUASHFS=y CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b6aa74480a25..e7d2b42ae02e 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -575,7 +575,7 @@ config HIPERDISPATCH_ON def_bool y bool "Use hiperdispatch on vertical polarization by default" depends on SCHED_TOPOLOGY - depends on PROC_SYSCTL + depends on SYSCTL help Hiperdispatch aims to improve the CPU scheduler's decision making when using vertical polarization by adjusting CPU @@ -893,7 +893,7 @@ config CMM_IUCV config APPLDATA_BASE def_bool n prompt "Linux - VM Monitor Stream, base infrastructure" - depends on PROC_SYSCTL + depends on SYSCTL help This provides a kernel interface for creating and updating z/VM APPLDATA monitor records. The monitor records are updated at certain time diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c index bba28607a59a..177f964d4d36 100644 --- a/arch/x86/kernel/cpu/bus_lock.c +++ b/arch/x86/kernel/cpu/bus_lock.c @@ -50,7 +50,7 @@ static struct ratelimit_state bld_ratelimit; static unsigned int sysctl_sld_mitigate = 1; static DEFINE_SEMAPHORE(buslock_sem, 1); -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static const struct ctl_table sld_sysctls[] = { { .procname = "split_lock_mitigate", diff --git a/fs/pipe.c b/fs/pipe.c index 0c77191a050c..292425a834dd 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1572,7 +1572,7 @@ static int u2k_pipe_maxsz(const ulong *u_ptr, uint *k_ptr) return proc_uint_u2k_conv_uop(u_ptr, k_ptr, round_pipe_size_ul); } -static int do_proc_uint_conv_pipe_maxsz(ulong *u_ptr, uint *k_ptr, +static int do_proc_uint_conv_pipe_maxsz(bool *negp, ulong *u_ptr, uint *k_ptr, int dir, const struct ctl_table *table) { return proc_uint_conv(u_ptr, k_ptr, dir, table, true, diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 6ae966c561e7..24f5a36f45df 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -80,10 +80,9 @@ config PROC_VMCORE_DEVICE_RAM Relevant architectures should select NEED_PROC_VMCORE_DEVICE_RAM. -config PROC_SYSCTL +config SYSCTL bool "Sysctl support (/proc/sys)" if EXPERT depends on PROC_FS - select SYSCTL default y help The sysctl interface provides a means of dynamically changing diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 8bc615ff84e5..27e2b26b2d42 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -29,7 +29,7 @@ proc-y += softirqs.o proc-y += namespaces.o proc-y += self.o proc-y += thread_self.o -proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o +proc-$(CONFIG_SYSCTL) += proc_sysctl.o proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b232e1098117..04bd6c9e65a7 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -351,7 +351,7 @@ extern void proc_thread_self_init(void); /* * proc_sysctl.c */ -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL extern int proc_sys_init(void); extern void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 2886fbceb5d6..e5d7226ab6f5 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -59,7 +59,7 @@ extern const int sysctl_vals[]; #define SYSCTL_LONG_ONE ((void *)&sysctl_long_vals[1]) #define SYSCTL_LONG_MAX ((void *)&sysctl_long_vals[2]) -/** +/* * * "dir" originates from read_iter (dir = 0) or write_iter (dir = 1) * in the file_operations struct at proc/proc_sysctl.c. Its value means @@ -74,53 +74,108 @@ extern const int sysctl_vals[]; extern const unsigned long sysctl_long_vals[]; -typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer, - size_t *lenp, loff_t *ppos); - -int proc_dostring(const struct ctl_table *, int, void *, size_t *, loff_t *); -int proc_dobool(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); - -int proc_dointvec(const struct ctl_table *, int, void *, size_t *, loff_t *); -int proc_dointvec_minmax(const struct ctl_table *table, int dir, void *buffer, +typedef int proc_handler(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, loff_t *ppos); -int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, + +/* proc_handler functions */ +int proc_dostring(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, + loff_t *ppos); +int proc_dobool(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, + loff_t *ppos); +int proc_dointvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, + loff_t *ppos); +int proc_dointvec_minmax(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); +int proc_douintvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, + loff_t *ppos); +int proc_douintvec_minmax(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); +int proc_dou8vec_minmax(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); +int proc_doulongvec_minmax(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); +int proc_do_large_bitmap(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); +int proc_do_static_key(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos); + +/* + * proc_handler aggregators + * + * Create a proc_handler with a custom converter. Use when the user space + * value is a transformation of the kernel value. Cannot be passed as + * proc_handlers. + * + * Example of creating your custom proc handler: + * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr, + * int dir, const struct ctl_table *ctl) {...} + * int custom_proc_handler(const struct ctl_table *ctl, int dir, + * void *buf, size_t *lenp, loff_t *ppos + * { return proc_dointvec_conv(ctl, dir, buf, lenp, ppos, custom_converter); } + */ +int proc_dointvec_conv(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, - int dir, const struct ctl_table *table)); -int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp, - ulong (*k_ptr_op)(const ulong)); -int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp, - ulong (*u_ptr_op)(const ulong)); + int dir, const struct ctl_table *ctl)); +int proc_douintvec_conv(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos, + int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr, + int dir, const struct ctl_table *ctl)); +int proc_doulongvec_conv(const struct ctl_table *ctl, int dir, void *buf, + size_t *lenp, loff_t *ppos, + int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *ctl)); + +/* + * bi-directional converter functions + * + * Specify the converter function for both directions (user to kernel & kernel + * to user). Use when you want to change the value of the variable before + * assignment. Used to create custom proc_handler aggregators. + * + * Example of creating your custom bi-directional converter: + * int custom_u2k(ulong *u_ptr, const uint *k_ptr) { ... } + * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr, + * int dir, const struct ctl_table *ctl) + * { return proc_uint_conv(u_ptr, k_ptr, dir, ctl, true, + * custom_u2k, proc_uint_k2u_conv} + */ int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir, const struct ctl_table *tbl, bool k_ptr_range_check, int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr), int (*kern_to_user)(bool *negp, ulong *u_ptr, const int *k_ptr)); - -int proc_douintvec(const struct ctl_table *, int, void *, size_t *, loff_t *); -int proc_douintvec_minmax(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); -int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *lvalp, unsigned int *valp, - int write, const struct ctl_table *table)); -int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr); -int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, - ulong (*u_ptr_op)(const ulong)); int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, const struct ctl_table *tbl, bool k_ptr_range_check, int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr), int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr)); +int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir, + const struct ctl_table *tbl, bool k_ptr_range_check, + int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr), + int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr)); -int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); -int proc_doulongvec_minmax(const struct ctl_table *, int, void *, size_t *, loff_t *); -int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, - void *buffer, size_t *lenp, loff_t *ppos, - unsigned long convmul, unsigned long convdiv); -int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *); -int proc_do_static_key(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); +/* + * uni-directional converter functions + * + * Specify the converter function for one directions (user to kernel or + * kernel to user). Use to call the actual value conversion. Used to Create + * bi-directional converters. + * + * Example of creating a uni-directional converter: + * ulong op(const ulong val) { ... } + * int custom_unidir_conv(ulong *u_ptr, const uint *k_ptr) + * { return proc_uint_k2u_conv_kop(u_ptr, k_ptr, op); } + */ +int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp, + ulong (*k_ptr_op)(const ulong)); +int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp, + ulong (*u_ptr_op)(const ulong)); +int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr); +int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, + ulong (*u_ptr_op)(const ulong)); +int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr, + ulong (*u_ptr_op)(const ulong)); +int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr, + ulong (*k_ptr_op)(const ulong)); /* * Register a set of sysctl names by calling register_sysctl @@ -190,9 +245,9 @@ struct ctl_node { * @nreg: When nreg drops to 0 the ctl_table_header will be unregistered. * @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()" * - * @type: Enumeration to differentiate between ctl target types - * @type.SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations - * @type.SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY: Identifies a permanently empty dir + * @type: Enumeration to differentiate between ctl target types: + * type.SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations + * type.SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY: Identifies a permanently empty dir * target to serve as a mount point */ struct ctl_table_header { diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 547bd4439706..dc5594ffffcc 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -18,7 +18,7 @@ enum uts_proc { UTS_PROC_DOMAINNAME, }; -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL extern void uts_proc_notify(enum uts_proc proc); #else static inline void uts_proc_notify(enum uts_proc proc) diff --git a/init/Kconfig b/init/Kconfig index db9f72d2061c..60448fd4ee12 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1665,9 +1665,6 @@ config LD_ORPHAN_WARN_LEVEL default "error" if WERROR default "warn" -config SYSCTL - bool - config HAVE_UID16 bool diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 2e55c493c98b..479e860aff70 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -54,7 +54,7 @@ void delayacct_init(void) set_delayacct(delayacct_on); } -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static int sysctl_delayacct(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { diff --git a/kernel/pid.c b/kernel/pid.c index d01d0dd7114b..95b8ccfa8269 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -766,29 +766,6 @@ static struct ctl_table_root pid_table_root = { .set_ownership = pid_table_root_set_ownership, }; -static int proc_do_cad_pid(const struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos) -{ - struct pid *new_pid; - pid_t tmp_pid; - int r; - struct ctl_table tmp_table = *table; - - tmp_pid = pid_vnr(cad_pid); - tmp_table.data = &tmp_pid; - - r = proc_dointvec(&tmp_table, write, buffer, lenp, ppos); - if (r || !write) - return r; - - new_pid = find_get_pid(tmp_pid); - if (!new_pid) - return -ESRCH; - - put_pid(xchg(&cad_pid, new_pid)); - return 0; -} - static const struct ctl_table pid_table[] = { { .procname = "pid_max", @@ -799,14 +776,6 @@ static const struct ctl_table pid_table[] = { .extra1 = &pid_max_min, .extra2 = &pid_max_max, }, -#ifdef CONFIG_PROC_SYSCTL - { - .procname = "cad_pid", - .maxlen = sizeof(int), - .mode = 0600, - .proc_handler = proc_do_cad_pid, - }, -#endif }; #endif diff --git a/kernel/reboot.c b/kernel/reboot.c index 695c33e75efd..f070c5c1103a 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -1366,6 +1366,29 @@ static struct attribute *reboot_attrs[] = { }; #ifdef CONFIG_SYSCTL +static int proc_do_cad_pid(const struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos) +{ + struct ctl_table tmp_table = *table; + struct pid *new_pid; + pid_t tmp_pid; + int r; + + tmp_pid = pid_vnr(cad_pid); + tmp_table.data = &tmp_pid; + + r = proc_dointvec(&tmp_table, write, buffer, lenp, ppos); + if (r || !write) + return r; + + new_pid = find_get_pid(tmp_pid); + if (!new_pid) + return -ESRCH; + + put_pid(xchg(&cad_pid, new_pid)); + return 0; +} + static const struct ctl_table kern_reboot_table[] = { { .procname = "poweroff_cmd", @@ -1381,6 +1404,12 @@ static const struct ctl_table kern_reboot_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "cad_pid", + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_do_cad_pid, + }, }; static void __init kernel_reboot_sysctls_init(void) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f5f7ff8c680a..6544e56925ee 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4638,7 +4638,7 @@ void set_numabalancing_state(bool enabled) __set_numabalancing_state(enabled); } -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static void reset_memory_tiering(void) { struct pglist_data *pgdat; @@ -4674,7 +4674,7 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write, } return err; } -#endif /* CONFIG_PROC_SYSCTL */ +#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_NUMA_BALANCING */ #ifdef CONFIG_SCHEDSTATS @@ -4718,7 +4718,7 @@ static int __init setup_schedstats(char *str) } __setup("schedstats=", setup_schedstats); -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static int sysctl_schedstats(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { @@ -4738,7 +4738,7 @@ static int sysctl_schedstats(const struct ctl_table *table, int write, void *buf set_schedstats(state); return err; } -#endif /* CONFIG_PROC_SYSCTL */ +#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SCHEDSTATS */ #ifdef CONFIG_SYSCTL diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 21e816ad23ee..0248227d983a 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -271,7 +271,7 @@ void rebuild_sched_domains_energy(void) mutex_unlock(&sched_energy_mutex); } -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static int sched_energy_aware_handler(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { @@ -317,7 +317,7 @@ static int __init sched_energy_aware_sysctl_init(void) } late_initcall(sched_energy_aware_sysctl_init); -#endif /* CONFIG_PROC_SYSCTL */ +#endif /* CONFIG_SYSCTL */ static void free_pd(struct perf_domain *pd) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c9efb17cc255..f7b75985d542 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -35,7 +35,7 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); static const int ngroups_max = NGROUPS_MAX; static const int cap_last_cap = CAP_LAST_CAP; -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL /** * enum sysctl_writes_mode - supported sysctl write modes @@ -64,14 +64,14 @@ enum sysctl_writes_mode { }; static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; -#endif /* CONFIG_PROC_SYSCTL */ +#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */ /* * /proc/sys support */ -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static int _proc_do_string(char *data, int maxlen, int dir, char *buffer, size_t *lenp, loff_t *ppos) @@ -148,7 +148,7 @@ static void warn_sysctl_write(const struct ctl_table *table) * @ppos: file position * @table: the sysctl table * - * Returns true if the first position is non-zero and the sysctl_writes_strict + * Returns: true if the first position is non-zero and the sysctl_writes_strict * mode indicates this is not allowed for numeric input types. String proc * handlers can ignore the return value. */ @@ -184,7 +184,7 @@ static bool proc_first_pos_non_zero_ignore(loff_t *ppos, * and a newline '\n' is added. It is truncated if the buffer is * not large enough. * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_dostring(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) @@ -225,11 +225,14 @@ static void proc_skip_char(char **buf, size_t *size, const char v) * @base: the base to use * @res: where the parsed integer will be stored * - * In case of success 0 is returned and @res will contain the parsed integer, - * @endp will hold any trailing characters. * This function will fail the parse on overflow. If there wasn't an overflow * the function will defer the decision what characters count as invalid to the * caller. + * + * Returns: + * * %0 on success and @res will contain the parsed integer, + * @endp will hold any trailing characters. + * * %-ERANGE on overflow. */ static int strtoul_lenient(const char *cp, char **endp, unsigned int base, unsigned long *res) @@ -263,10 +266,12 @@ static int strtoul_lenient(const char *cp, char **endp, unsigned int base, * @perm_tr_len: size of the perm_tr vector * @tr: pointer to store the trailer character * - * In case of success %0 is returned and @buf and @size are updated with - * the amount of bytes read. If @tr is non-NULL and a trailing - * character exists (size is non-zero after returning from this - * function), @tr is updated with the trailing character. + * Returns: + * * %0 on success and @buf and @size are updated with + * the amount of bytes read. If @tr is non-NULL and a trailing + * character exists (size is non-zero after returning from this + * function), @tr is updated with the trailing character. + * * %-EINVAL on failure. */ static int proc_get_long(char **buf, size_t *size, unsigned long *val, bool *neg, @@ -365,7 +370,7 @@ static void proc_put_char(void **buf, size_t *size, char c) * not NULL. Check that the values are less than UINT_MAX to avoid * having to support wrap around from userspace. * - * returns 0 on success. + * Returns: %0 on success. */ int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, ulong (*u_ptr_op)(const ulong)) @@ -386,7 +391,7 @@ int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr, * * Uses READ_ONCE to assign value to u_ptr. * - * returns 0 on success. + * Returns: %0 on success. */ int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) { @@ -409,7 +414,7 @@ int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr) * When direction is kernel to user, then the u_ptr is modified. * When direction is user to kernel, then the k_ptr is modified. * - * Returns 0 on success + * Returns: %0 on success */ int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, const struct ctl_table *tbl, bool k_ptr_range_check, @@ -444,15 +449,15 @@ static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr) return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL); } -static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir, +static int do_proc_uint_conv(bool *negp, ulong *u_ptr, uint *k_ptr, int dir, const struct ctl_table *tbl) { return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false, proc_uint_u2k_conv, proc_uint_k2u_conv); } -static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir, - const struct ctl_table *tbl) +static int do_proc_uint_conv_minmax(bool *negp, ulong *u_ptr, uint *k_ptr, + int dir, const struct ctl_table *tbl) { return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true, proc_uint_u2k_conv, proc_uint_k2u_conv); @@ -515,6 +520,23 @@ int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp, return 0; } +/** + * proc_int_conv - Change user or kernel pointer based on direction + * + * @negp: will be passed to uni-directional converters + * @u_ptr: pointer to user variable + * @k_ptr: pointer to kernel variable + * @dir: %TRUE if this is a write to the sysctl file + * @tbl: the sysctl table + * @k_ptr_range_check: Check range for k_ptr when %TRUE + * @user_to_kern: Callback used to assign value from user to kernel var + * @kern_to_user: Callback used to assign value from kernel to user var + * + * When direction is kernel to user, then the u_ptr is modified. + * When direction is user to kernel, then the k_ptr is modified. + * + * Returns: 0 on success + */ int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir, const struct ctl_table *tbl, bool k_ptr_range_check, int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr), @@ -572,14 +594,80 @@ static int do_proc_int_conv_minmax(bool *negp, unsigned long *u_ptr, int *k_ptr, static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; -static int do_proc_dointvec(const struct ctl_table *table, int dir, - void *buffer, size_t *lenp, loff_t *ppos, - int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, - int dir, const struct ctl_table *table)) +/* + * Element type processed by do_proc_vec(). The tag selects the element size + * and signedness, and it selects which member of union proc_vec_conv is live. + */ +enum proc_vec_type { + PROC_VEC_INT, + PROC_VEC_UINT, + PROC_VEC_ULONG, +}; + +/* + * Converter passed to do_proc_vec(). Only the member matching the + * enum proc_vec_type tag is ever read, so every dispatch stays fully typed and + * no void * converter pointer is needed. + */ +union proc_vec_conv { + int (*int_conv)(bool *negp, ulong *u_ptr, int *k_ptr, + int dir, const struct ctl_table *table); + int (*uint_conv)(bool *negp, ulong *u_ptr, uint *k_ptr, + int dir, const struct ctl_table *table); + int (*ulong_conv)(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *table); +}; + +/* + * Dispatch to the converter member selected by @type. @k_ptr walks + * table->data as raw bytes and is cast back to the element type here. + */ +static int proc_vec_conv(enum proc_vec_type type, union proc_vec_conv conv, + bool *negp, ulong *u_ptr, char *k_ptr, int dir, + const struct ctl_table *table) { - int *i, vleft, first = 1, err = 0; - size_t left; - char *p; + switch (type) { + case PROC_VEC_INT: + return conv.int_conv(negp, u_ptr, (int *)k_ptr, dir, table); + case PROC_VEC_UINT: + return conv.uint_conv(negp, u_ptr, (uint *)k_ptr, dir, table); + case PROC_VEC_ULONG: + return conv.ulong_conv(negp, u_ptr, (ulong *)k_ptr, dir, table); + } + return -EINVAL; +} + +/* + * Read/write a vector of @type elements. The element size and signedness are + * derived from @type, so a single runtime function replaces the per-type + * variants. table->data is walked as raw bytes (@i) advanced by @size; the + * converter performs the actual typed load/store. + */ +static int do_proc_vec(const struct ctl_table *table, int dir, + void *buffer, size_t *lenp, loff_t *ppos, + enum proc_vec_type type, union proc_vec_conv conv) +{ + int vleft, first = 1, err = 0; + size_t left, size; + bool is_unsigned; + char *i, *p; + + switch (type) { + case PROC_VEC_INT: + size = sizeof(int); + is_unsigned = false; + break; + case PROC_VEC_UINT: + size = sizeof(uint); + is_unsigned = true; + break; + case PROC_VEC_ULONG: + size = sizeof(ulong); + is_unsigned = true; + break; + default: + return -EINVAL; + } if (!table->data || !table->maxlen || !*lenp || (*ppos && SYSCTL_KERN_TO_USER(dir))) { @@ -587,12 +675,13 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir, return 0; } - i = (int *) table->data; - vleft = table->maxlen / sizeof(*i); + i = table->data; + vleft = table->maxlen / size; left = *lenp; - if (!conv) - conv = do_proc_int_conv; + /* uint arrays are not supported, *Do not* add support for them. */ + if (type == PROC_VEC_UINT && vleft != 1) + return -EINVAL; if (SYSCTL_USER_TO_KERN(dir)) { if (proc_first_pos_non_zero_ignore(ppos, table)) @@ -603,9 +692,9 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir, p = buffer; } - for (; left && vleft--; i++, first=0) { + for (; left && vleft--; i += size, first = 0) { unsigned long lval; - bool neg; + bool neg = false; if (SYSCTL_USER_TO_KERN(dir)) { proc_skip_spaces(&p, &left); @@ -613,16 +702,18 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir, if (!left) break; err = proc_get_long(&p, &left, &lval, &neg, - proc_wspace_sep, - sizeof(proc_wspace_sep), NULL); + proc_wspace_sep, + sizeof(proc_wspace_sep), NULL); + if (!err && neg && is_unsigned) + err = -EINVAL; if (err) break; - if (conv(&neg, &lval, i, 1, table)) { + if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) { err = -EINVAL; break; } } else { - if (conv(&neg, &lval, i, 0, table)) { + if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) { err = -EINVAL; break; } @@ -644,122 +735,6 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir, return err; } -static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer, - size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *u_ptr, - unsigned int *k_ptr, int dir, - const struct ctl_table *table)) -{ - unsigned long lval; - int err = 0; - size_t left; - bool neg; - char *p = buffer; - - left = *lenp; - - if (proc_first_pos_non_zero_ignore(ppos, table)) - goto bail_early; - - if (left > PAGE_SIZE - 1) - left = PAGE_SIZE - 1; - - proc_skip_spaces(&p, &left); - if (!left) { - err = -EINVAL; - goto out_free; - } - - err = proc_get_long(&p, &left, &lval, &neg, - proc_wspace_sep, - sizeof(proc_wspace_sep), NULL); - if (err || neg) { - err = -EINVAL; - goto out_free; - } - - if (conv(&lval, (unsigned int *) table->data, 1, table)) { - err = -EINVAL; - goto out_free; - } - - if (!err && left) - proc_skip_spaces(&p, &left); - -out_free: - if (err) - return -EINVAL; - - return 0; - -bail_early: - *ppos += *lenp; - return err; -} - -static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer, - size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *u_ptr, - unsigned int *k_ptr, int dir, - const struct ctl_table *table)) -{ - unsigned long lval; - int err = 0; - size_t left; - - left = *lenp; - - if (conv(&lval, (unsigned int *) table->data, 0, table)) { - err = -EINVAL; - goto out; - } - - proc_put_long(&buffer, &left, lval, false); - if (!left) - goto out; - - proc_put_char(&buffer, &left, '\n'); - -out: - *lenp -= left; - *ppos += *lenp; - - return err; -} - -static int do_proc_douintvec(const struct ctl_table *table, int dir, - void *buffer, size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *u_ptr, - unsigned int *k_ptr, int dir, - const struct ctl_table *table)) -{ - unsigned int vleft; - - if (!table->data || !table->maxlen || !*lenp || - (*ppos && SYSCTL_KERN_TO_USER(dir))) { - *lenp = 0; - return 0; - } - - vleft = table->maxlen / sizeof(unsigned int); - - /* - * Arrays are not supported, keep this simple. *Do not* add - * support for them. - */ - if (vleft != 1) { - *lenp = 0; - return -EINVAL; - } - - if (!conv) - conv = do_proc_uint_conv; - - if (SYSCTL_USER_TO_KERN(dir)) - return do_proc_douintvec_w(table, buffer, lenp, ppos, conv); - return do_proc_douintvec_r(table, buffer, lenp, ppos, conv); -} - /** * proc_douintvec_conv - read a vector of unsigned ints with a custom converter * @@ -774,14 +749,19 @@ static int do_proc_douintvec(const struct ctl_table *table, int dir, * values from/to the user buffer, treated as an ASCII string. Negative * strings are not allowed. * - * Returns 0 on success + * Returns: %0 on success */ int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr, + int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr, int dir, const struct ctl_table *table)) { - return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv); + + if (!conv) + conv = do_proc_uint_conv; + + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT, + (union proc_vec_conv){ .uint_conv = conv }); } /** @@ -798,7 +778,7 @@ int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer, * table->data must point to a bool variable and table->maxlen must * be sizeof(bool). * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_dobool(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) @@ -835,12 +815,13 @@ int proc_dobool(const struct ctl_table *table, int dir, void *buffer, * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string. * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_dointvec(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL); + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT, + (union proc_vec_conv){ .int_conv = do_proc_int_conv }); } /** @@ -854,13 +835,13 @@ int proc_dointvec(const struct ctl_table *table, int dir, void *buffer, * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer * values from/to the user buffer, treated as an ASCII string. * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_douintvec(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return do_proc_douintvec(table, dir, buffer, lenp, ppos, - do_proc_uint_conv); + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT, + (union proc_vec_conv){ .uint_conv = do_proc_uint_conv }); } /** @@ -877,14 +858,14 @@ int proc_douintvec(const struct ctl_table *table, int dir, void *buffer, * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). * - * Returns 0 on success or -EINVAL when the range check fails and + * Returns: %0 on success or -EINVAL when the range check fails and * SYSCTL_USER_TO_KERN(dir) == true */ int proc_dointvec_minmax(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return do_proc_dointvec(table, dir, buffer, lenp, ppos, - do_proc_int_conv_minmax); + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT, + (union proc_vec_conv){ .int_conv = do_proc_int_conv_minmax }); } /** @@ -904,14 +885,14 @@ int proc_dointvec_minmax(const struct ctl_table *table, int dir, * (max). And Check that the values are less than UINT_MAX to avoid having to * support wrap around uses from userspace. * - * Returns 0 on success or -ERANGE when range check failes and + * Returns: %0 on success or -ERANGE when range check failes and * SYSCTL_USER_TO_KERN(dir) == true */ int proc_douintvec_minmax(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return do_proc_douintvec(table, dir, buffer, lenp, ppos, - do_proc_uint_conv_minmax); + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT, + (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax }); } /** @@ -929,7 +910,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir, * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). * - * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true + * Returns: %0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true * and the range check fails. */ int proc_dou8vec_minmax(const struct ctl_table *table, int dir, @@ -954,8 +935,8 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir, tmp.extra2 = (unsigned int *) &max; val = READ_ONCE(*data); - res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos, - do_proc_uint_conv_minmax); + res = do_proc_vec(&tmp, dir, buffer, lenp, ppos, PROC_VEC_UINT, + (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax }); if (res) return res; if (SYSCTL_USER_TO_KERN(dir)) @@ -964,87 +945,129 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir, } EXPORT_SYMBOL_GPL(proc_dou8vec_minmax); -static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir, - void *buffer, size_t *lenp, loff_t *ppos, - unsigned long convmul, - unsigned long convdiv) +/** + * proc_ulong_conv - Change user or kernel pointer based on direction + * + * @u_ptr: pointer to user variable + * @k_ptr: pointer to kernel variable + * @dir: %TRUE if this is a write to the sysctl file + * @tbl: the sysctl table + * @k_ptr_range_check: Check range for k_ptr when %TRUE + * @user_to_kern: Callback used to assign value from user to kernel var + * @kern_to_user: Callback used to assign value from kernel to user var + * + * When direction is kernel to user, then the u_ptr is modified. + * When direction is user to kernel, then the k_ptr is modified. + * + * Returns: 0 on success + */ +int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir, + const struct ctl_table *tbl, bool k_ptr_range_check, + int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr), + int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr)) { - unsigned long *i, *min, *max; - int vleft, first = 1, err = 0; - size_t left; - char *p; + if (SYSCTL_KERN_TO_USER(dir)) + return kern_to_user(u_ptr, k_ptr); - if (!table->data || !table->maxlen || !*lenp || - (*ppos && SYSCTL_KERN_TO_USER(dir))) { - *lenp = 0; - return 0; - } + if (k_ptr_range_check) { + ulong tmp_k; + int ret; - i = table->data; - min = table->extra1; - max = table->extra2; - vleft = table->maxlen / sizeof(unsigned long); - left = *lenp; - - if (SYSCTL_USER_TO_KERN(dir)) { - if (proc_first_pos_non_zero_ignore(ppos, table)) - goto out; - - if (left > PAGE_SIZE - 1) - left = PAGE_SIZE - 1; - p = buffer; - } - - for (; left && vleft--; i++, first = 0) { - unsigned long val; - - if (SYSCTL_USER_TO_KERN(dir)) { - bool neg; - - proc_skip_spaces(&p, &left); - if (!left) - break; - - err = proc_get_long(&p, &left, &val, &neg, - proc_wspace_sep, - sizeof(proc_wspace_sep), NULL); - if (err || neg) { - err = -EINVAL; - break; - } - - val = convmul * val / convdiv; - if ((min && val < *min) || (max && val > *max)) { - err = -EINVAL; - break; - } - WRITE_ONCE(*i, val); - } else { - val = convdiv * READ_ONCE(*i) / convmul; - if (!first) - proc_put_char(&buffer, &left, '\t'); - proc_put_long(&buffer, &left, val, false); - } - } - - if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err) - proc_put_char(&buffer, &left, '\n'); - if (SYSCTL_USER_TO_KERN(dir) && !err) - proc_skip_spaces(&p, &left); - if (SYSCTL_USER_TO_KERN(dir) && first) - return err ? : -EINVAL; - *lenp -= left; -out: - *ppos += *lenp; - return err; + if (!tbl) + return -EINVAL; + ret = user_to_kern(u_ptr, &tmp_k); + if (ret) + return ret; + if ((tbl->extra1 && *(ulong *)tbl->extra1 > tmp_k) || + (tbl->extra2 && *(ulong *)tbl->extra2 < tmp_k)) + return -ERANGE; + WRITE_ONCE(*k_ptr, tmp_k); + } else + return user_to_kern(u_ptr, k_ptr); + return 0; } -int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, - void *buffer, size_t *lenp, loff_t *ppos, - unsigned long convmul, unsigned long convdiv) +/** + * proc_ulong_u2k_conv_uop - Assign user value to a kernel pointer + * + * @u_ptr: pointer to user space variable + * @k_ptr: pointer to kernel variable + * @u_ptr_op: execute this function before assigning to k_ptr + * + * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if + * not NULL. + * + * Returns: 0 on success. + */ +int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr, + ulong (*u_ptr_op)(const ulong)) { - return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos, - convmul, convdiv); + ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr; + + WRITE_ONCE(*k_ptr, u); + return 0; +} + +static int proc_ulong_u2k_conv(const ulong *u_ptr, ulong *k_ptr) +{ + return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, NULL); +} + +/** + * proc_ulong_k2u_conv_kop - Assign kernel value to a user space pointer + * + * @u_ptr: pointer to user space variable + * @k_ptr: pointer to kernel variable + * @k_ptr_op: Operation applied to k_ptr before assignment + * + * Uses READ_ONCE to assign value to u_ptr. Executes k_ptr_op if + * not NULL. + * + * Returns: 0 on success. + */ +int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr, + ulong (*k_ptr_op)(const ulong)) +{ + ulong val = k_ptr_op ? k_ptr_op(READ_ONCE(*k_ptr)) : READ_ONCE(*k_ptr); + *u_ptr = (ulong)val; + return 0; +} + +static int proc_ulong_k2u_conv(ulong *u_ptr, const ulong *k_ptr) +{ + return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, NULL); +} + +static int do_proc_ulong_conv(bool *negp, ulong *u_ptr, ulong *k_ptr, int dir, + const struct ctl_table *tbl) +{ + return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, true, + proc_ulong_u2k_conv, proc_ulong_k2u_conv); +} + +/** + * proc_doulongvec_conv - read a vector of unsigned longs with a custom converter + * + * @table: the sysctl table + * @dir: %TRUE if this is a write to the sysctl file + * @buffer: the user buffer + * @lenp: the size of the user buffer + * @ppos: file position + * @conv: Custom converter call back + * + * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long + * values from/to the user buffer, treated as an ASCII string. Negative + * strings are not allowed. + * + * Returns: 0 on success + */ +int proc_doulongvec_conv(const struct ctl_table *table, int dir, + void *buffer, size_t *lenp, loff_t *ppos, + int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *table)) +{ + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG, + (union proc_vec_conv){ .ulong_conv = conv }); } /** @@ -1061,12 +1084,13 @@ int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_doulongvec_minmax(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l); + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG, + (union proc_vec_conv){ .ulong_conv = do_proc_ulong_conv }); } /** @@ -1076,21 +1100,22 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir, * @buffer: the user buffer * @lenp: the size of the user buffer * @ppos: file position - * @conv: Custom converter call back + * @conv: Custom converter call back. Defaults to do_proc_int_conv * - * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer - * values from/to the user buffer, treated as an ASCII string. Negative - * strings are not allowed. + * Reads/writes up to table->maxlen/sizeof(int) integer values from/to the + * user buffer, treated as an ASCII string. * * Returns: 0 on success */ - int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos, int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr, int dir, const struct ctl_table *table)) { - return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv); + if (!conv) + conv = do_proc_int_conv; + return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT, + (union proc_vec_conv){ .int_conv = conv }); } /** @@ -1108,7 +1133,7 @@ int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer, * large bitmaps may be represented in a compact manner. Writing into * the file will clear the bitmap then update it with the given input. * - * Returns 0 on success. + * Returns: %0 on success. */ int proc_do_large_bitmap(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) @@ -1240,7 +1265,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int dir, return err; } -#else /* CONFIG_PROC_SYSCTL */ +#else /* CONFIG_SYSCTL */ int proc_dostring(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) @@ -1280,7 +1305,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir, int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos, - int (*conv)(unsigned long *lvalp, unsigned int *valp, + int (*conv)(bool *negp, ulong *lvalp, uint *valp, int write, const struct ctl_table *table)) { return -ENOSYS; @@ -1317,9 +1342,10 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir, return -ENOSYS; } -int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir, +int proc_doulongvec_conv(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos, - unsigned long convmul, unsigned long convdiv) + int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *table)) { return -ENOSYS; } @@ -1338,7 +1364,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int dir, return -ENOSYS; } -#endif /* CONFIG_PROC_SYSCTL */ +#endif /* CONFIG_SYSCTL */ #if defined(CONFIG_SYSCTL) int proc_do_static_key(const struct ctl_table *table, int dir, @@ -1372,7 +1398,7 @@ int proc_do_static_key(const struct ctl_table *table, int dir, } static const struct ctl_table sysctl_subsys_table[] = { -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL { .procname = "sysctl_writes_strict", .data = &sysctl_writes_strict, diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index d51428867a33..213ae1d6a014 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -98,7 +98,7 @@ void __init register_refined_jiffies(long cycles_per_second) __clocksource_register(&refined_jiffies); } -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static ulong mult_hz(const ulong val) { return val * HZ; @@ -185,7 +185,24 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms); } -#else // CONFIG_PROC_SYSCTL +static int sysctl_u2k_ulong_conv_ms(const ulong *u_ptr, ulong *k_ptr) +{ + return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, sysctl_msecs_to_jiffies); +} + +static int sysctl_k2u_ulong_conv_ms(ulong *u_ptr, const ulong *k_ptr) +{ + return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, sysctl_jiffies_to_msecs); +} + +static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *tbl) +{ + return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, false, + sysctl_u2k_ulong_conv_ms, sysctl_k2u_ulong_conv_ms); +} + +#else // CONFIG_SYSCTL static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr, int dir, const struct ctl_table *tbl) { @@ -211,6 +228,12 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr, { return -ENOSYS; } + +static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr, + int dir, const struct ctl_table *tbl) +{ + return -ENOSYS; +} #endif /** @@ -309,8 +332,8 @@ int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir, void *buffer, size_t *lenp, loff_t *ppos) { - return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, - HZ, 1000l); + return proc_doulongvec_conv(table, dir, buffer, lenp, ppos, + do_proc_ulong_conv_ms_jiffies); } EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c index bfbaaecb1dd4..6c1522201e39 100644 --- a/kernel/utsname_sysctl.c +++ b/kernel/utsname_sysctl.c @@ -13,7 +13,7 @@ #include #include -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL static void *get_uts(const struct ctl_table *table) { @@ -122,7 +122,7 @@ static const struct ctl_table uts_kern_table[] = { }, }; -#ifdef CONFIG_PROC_SYSCTL +#ifdef CONFIG_SYSCTL /* * Notify userspace about a change in a certain entry of uts_kern_table, * identified by the parameter proc. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1244dcac2294..73287ef2498c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2710,7 +2710,7 @@ config TEST_FIRMWARE config TEST_SYSCTL tristate "sysctl test driver" - depends on PROC_SYSCTL + depends on SYSCTL help This builds the "test_sysctl" module. This driver enables to test the proc sysctl interfaces available to drivers safely without affecting diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c index c02aa9c868f2..909cfcf76dbf 100644 --- a/lib/test_sysctl.c +++ b/lib/test_sysctl.c @@ -7,7 +7,7 @@ /* * This module provides an interface to the proc sysctl interfaces. This - * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the + * driver requires CONFIG_SYSCTL. It will not normally be loaded by the * system unless explicitly requested by name. You can also build this driver * into your kernel. */ diff --git a/net/mpls/Kconfig b/net/mpls/Kconfig index d672ab72ab12..829fb1788b1c 100644 --- a/net/mpls/Kconfig +++ b/net/mpls/Kconfig @@ -26,7 +26,7 @@ config NET_MPLS_GSO config MPLS_ROUTING tristate "MPLS: routing support" depends on NET_IP_TUNNEL || NET_IP_TUNNEL=n - depends on PROC_SYSCTL + depends on SYSCTL help Add support for forwarding of mpls packets. diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index d83e11298b01..30d5fcb09a83 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -118,7 +118,7 @@ CONFIG_NFT_NAT=m CONFIG_NUMA=y CONFIG_OPENVSWITCH=m CONFIG_PAGE_POOL_STATS=y -CONFIG_PROC_SYSCTL=y +CONFIG_SYSCTL=y CONFIG_PSAMPLE=m CONFIG_RPS=y CONFIG_SYN_COOKIES=y diff --git a/tools/testing/selftests/net/packetdrill/config b/tools/testing/selftests/net/packetdrill/config index c4a19a785521..83dde525c53c 100644 --- a/tools/testing/selftests/net/packetdrill/config +++ b/tools/testing/selftests/net/packetdrill/config @@ -4,7 +4,7 @@ CONFIG_IPV6=y CONFIG_NET_NS=y CONFIG_NET_SCH_FIFO=y CONFIG_NET_SCH_FQ=y -CONFIG_PROC_SYSCTL=y +CONFIG_SYSCTL=y CONFIG_SYN_COOKIES=y CONFIG_TCP_CONG_CUBIC=y CONFIG_TCP_MD5SIG=y diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config index bb89d2dfaa2a..368fd9d600c8 100644 --- a/tools/testing/selftests/wireguard/qemu/kernel.config +++ b/tools/testing/selftests/wireguard/qemu/kernel.config @@ -63,7 +63,7 @@ CONFIG_FILE_LOCKING=y CONFIG_POSIX_TIMERS=y CONFIG_DEVTMPFS=y CONFIG_PROC_FS=y -CONFIG_PROC_SYSCTL=y +CONFIG_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15