Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sysctl: Move UINT converter macros to sysctl header

Move SYSCTL_USER_TO_KERN_UINT_CONV and SYSCTL_UINT_CONV_CUSTOM macros to
include/linux/sysctl.h. No need to embed sysctl_kern_to_user_uint_conv
in a macro as it will not need a custom kernel pointer operation. This
is a preparation commit to enable jiffies converter creation outside
kernel/sysctl.c.

Signed-off-by: Joel Granados <joel.granados@kernel.org>

+42 -39
+40
include/linux/sysctl.h
··· 134 134 return 0; \ 135 135 } 136 136 137 + #define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \ 138 + int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\ 139 + unsigned int *k_ptr) \ 140 + { \ 141 + unsigned long u = u_ptr_op(*u_ptr); \ 142 + if (u > UINT_MAX) \ 143 + return -EINVAL; \ 144 + WRITE_ONCE(*k_ptr, u); \ 145 + return 0; \ 146 + } 147 + 148 + #define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 149 + k_ptr_range_check) \ 150 + int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \ 151 + int dir, const struct ctl_table *tbl) \ 152 + { \ 153 + if (SYSCTL_KERN_TO_USER(dir)) \ 154 + return kern_to_user(u_ptr, k_ptr); \ 155 + \ 156 + if (k_ptr_range_check) { \ 157 + unsigned int tmp_k; \ 158 + int ret; \ 159 + if (!tbl) \ 160 + return -EINVAL; \ 161 + ret = user_to_kern(u_ptr, &tmp_k); \ 162 + if (ret) \ 163 + return ret; \ 164 + if ((tbl->extra1 && \ 165 + *(unsigned int *)tbl->extra1 > tmp_k) || \ 166 + (tbl->extra2 && \ 167 + *(unsigned int *)tbl->extra2 < tmp_k)) \ 168 + return -ERANGE; \ 169 + WRITE_ONCE(*k_ptr, tmp_k); \ 170 + } else \ 171 + return user_to_kern(u_ptr, k_ptr); \ 172 + return 0; \ 173 + } 174 + 175 + 137 176 extern const unsigned long sysctl_long_vals[]; 138 177 139 178 typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer, ··· 205 166 int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *); 206 167 int proc_do_static_key(const struct ctl_table *table, int write, void *buffer, 207 168 size_t *lenp, loff_t *ppos); 169 + int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, const unsigned int *k_ptr); 208 170 209 171 /* 210 172 * Register a set of sysctl names by calling register_sysctl
+2 -39
kernel/sysctl.c
··· 387 387 sysctl_user_to_kern_int_conv_ms, 388 388 sysctl_kern_to_user_int_conv_ms, true) 389 389 390 - #define SYSCTL_USER_TO_KERN_UINT_CONV(name, u_ptr_op) \ 391 - int sysctl_user_to_kern_uint_conv##name(const unsigned long *u_ptr,\ 392 - unsigned int *k_ptr) \ 393 - { \ 394 - unsigned long u = u_ptr_op(*u_ptr); \ 395 - if (u > UINT_MAX) \ 396 - return -EINVAL; \ 397 - WRITE_ONCE(*k_ptr, u); \ 398 - return 0; \ 399 - } 400 390 401 391 static SYSCTL_USER_TO_KERN_UINT_CONV(, SYSCTL_CONV_IDENTITY) 402 392 403 - static int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, 404 - const unsigned int *k_ptr) 393 + int sysctl_kern_to_user_uint_conv(unsigned long *u_ptr, 394 + const unsigned int *k_ptr) 405 395 { 406 396 unsigned int val = READ_ONCE(*k_ptr); 407 397 *u_ptr = (unsigned long)val; 408 398 return 0; 409 - } 410 - 411 - #define SYSCTL_UINT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 412 - k_ptr_range_check) \ 413 - int do_proc_uint_conv##name(unsigned long *u_ptr, unsigned int *k_ptr, \ 414 - int dir, const struct ctl_table *tbl) \ 415 - { \ 416 - if (SYSCTL_KERN_TO_USER(dir)) \ 417 - return kern_to_user(u_ptr, k_ptr); \ 418 - \ 419 - if (k_ptr_range_check) { \ 420 - unsigned int tmp_k; \ 421 - int ret; \ 422 - if (!tbl) \ 423 - return -EINVAL; \ 424 - ret = user_to_kern(u_ptr, &tmp_k); \ 425 - if (ret) \ 426 - return ret; \ 427 - if ((tbl->extra1 && \ 428 - *(unsigned int *)tbl->extra1 > tmp_k) || \ 429 - (tbl->extra2 && \ 430 - *(unsigned int *)tbl->extra2 < tmp_k)) \ 431 - return -ERANGE; \ 432 - WRITE_ONCE(*k_ptr, tmp_k); \ 433 - } else \ 434 - return user_to_kern(u_ptr, k_ptr); \ 435 - return 0; \ 436 399 } 437 400 438 401 static SYSCTL_UINT_CONV_CUSTOM(, sysctl_user_to_kern_uint_conv,