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

sysctl: Move INT converter macros to sysctl header

Move direction macros (SYSCTL_{USER_TO_KERN,KERN_TO_USER}) and the
integer converter macros (SYSCTL_{USER_TO_KERN,KERN_TO_USER}_INT_CONV,
SYSCTL_INT_CONV_CUSTOM) into include/linux/sysctl.h. This is a
preparation commit to enable jiffies converter creation outside
kernel/sysctl.c.

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

+75 -75
+75
include/linux/sysctl.h
··· 59 59 #define SYSCTL_LONG_ONE ((void *)&sysctl_long_vals[1]) 60 60 #define SYSCTL_LONG_MAX ((void *)&sysctl_long_vals[2]) 61 61 62 + /** 63 + * 64 + * "dir" originates from read_iter (dir = 0) or write_iter (dir = 1) 65 + * in the file_operations struct at proc/proc_sysctl.c. Its value means 66 + * one of two things for sysctl: 67 + * 1. SYSCTL_USER_TO_KERN(dir) Writing to an internal kernel variable from user 68 + * space (dir > 0) 69 + * 2. SYSCTL_KERN_TO_USER(dir) Writing to a user space buffer from a kernel 70 + * variable (dir == 0). 71 + */ 72 + #define SYSCTL_USER_TO_KERN(dir) (!!(dir)) 73 + #define SYSCTL_KERN_TO_USER(dir) (!dir) 74 + 75 + #define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \ 76 + int sysctl_user_to_kern_int_conv##name(const bool *negp, \ 77 + const unsigned long *u_ptr,\ 78 + int *k_ptr) \ 79 + { \ 80 + unsigned long u = u_ptr_op(*u_ptr); \ 81 + if (*negp) { \ 82 + if (u > (unsigned long) INT_MAX + 1) \ 83 + return -EINVAL; \ 84 + WRITE_ONCE(*k_ptr, -u); \ 85 + } else { \ 86 + if (u > (unsigned long) INT_MAX) \ 87 + return -EINVAL; \ 88 + WRITE_ONCE(*k_ptr, u); \ 89 + } \ 90 + return 0; \ 91 + } 92 + 93 + #define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op) \ 94 + int sysctl_kern_to_user_int_conv##name(bool *negp, \ 95 + unsigned long *u_ptr, \ 96 + const int *k_ptr) \ 97 + { \ 98 + int val = READ_ONCE(*k_ptr); \ 99 + if (val < 0) { \ 100 + *negp = true; \ 101 + *u_ptr = -k_ptr_op((unsigned long)val); \ 102 + } else { \ 103 + *negp = false; \ 104 + *u_ptr = k_ptr_op((unsigned long)val); \ 105 + } \ 106 + return 0; \ 107 + } 108 + 109 + /** 110 + * To range check on a converted value, use a temp k_ptr 111 + * When checking range, value should be within (tbl->extra1, tbl->extra2) 112 + */ 113 + #define SYSCTL_INT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 114 + k_ptr_range_check) \ 115 + int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\ 116 + int dir, const struct ctl_table *tbl) \ 117 + { \ 118 + if (SYSCTL_KERN_TO_USER(dir)) \ 119 + return kern_to_user(negp, u_ptr, k_ptr); \ 120 + \ 121 + if (k_ptr_range_check) { \ 122 + int tmp_k, ret; \ 123 + if (!tbl) \ 124 + return -EINVAL; \ 125 + ret = user_to_kern(negp, u_ptr, &tmp_k); \ 126 + if (ret) \ 127 + return ret; \ 128 + if ((tbl->extra1 && *(int *)tbl->extra1 > tmp_k) || \ 129 + (tbl->extra2 && *(int *)tbl->extra2 < tmp_k)) \ 130 + return -EINVAL; \ 131 + WRITE_ONCE(*k_ptr, tmp_k); \ 132 + } else \ 133 + return user_to_kern(negp, u_ptr, k_ptr); \ 134 + return 0; \ 135 + } 136 + 62 137 extern const unsigned long sysctl_long_vals[]; 63 138 64 139 typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
-75
kernel/sysctl.c
··· 30 30 const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX }; 31 31 EXPORT_SYMBOL_GPL(sysctl_long_vals); 32 32 33 - /** 34 - * 35 - * "dir" originates from read_iter (dir = 0) or write_iter (dir = 1) 36 - * in the file_operations struct at proc/proc_sysctl.c. Its value means 37 - * one of two things for sysctl: 38 - * 1. SYSCTL_USER_TO_KERN(dir) Writing to an internal kernel variable from user 39 - * space (dir > 0) 40 - * 2. SYSCTL_KERN_TO_USER(dir) Writing to a user space buffer from a kernel 41 - * variable (dir == 0). 42 - */ 43 - #define SYSCTL_USER_TO_KERN(dir) (!!(dir)) 44 - #define SYSCTL_KERN_TO_USER(dir) (!dir) 45 - 46 33 #if defined(CONFIG_SYSCTL) 47 34 48 35 /* Constants used for minimum and maximum */ ··· 353 366 (*buffer)++; 354 367 *buf = *buffer; 355 368 } 356 - } 357 - 358 - #define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op) \ 359 - int sysctl_user_to_kern_int_conv##name(const bool *negp, \ 360 - const unsigned long *u_ptr,\ 361 - int *k_ptr) \ 362 - { \ 363 - unsigned long u = u_ptr_op(*u_ptr); \ 364 - if (*negp) { \ 365 - if (u > (unsigned long) INT_MAX + 1) \ 366 - return -EINVAL; \ 367 - WRITE_ONCE(*k_ptr, -u); \ 368 - } else { \ 369 - if (u > (unsigned long) INT_MAX) \ 370 - return -EINVAL; \ 371 - WRITE_ONCE(*k_ptr, u); \ 372 - } \ 373 - return 0; \ 374 - } 375 - 376 - #define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op) \ 377 - int sysctl_kern_to_user_int_conv##name(bool *negp, \ 378 - unsigned long *u_ptr, \ 379 - const int *k_ptr) \ 380 - { \ 381 - int val = READ_ONCE(*k_ptr); \ 382 - if (val < 0) { \ 383 - *negp = true; \ 384 - *u_ptr = -k_ptr_op((unsigned long)val); \ 385 - } else { \ 386 - *negp = false; \ 387 - *u_ptr = k_ptr_op((unsigned long)val); \ 388 - } \ 389 - return 0; \ 390 - } 391 - 392 - /** 393 - * To range check on a converted value, use a temp k_ptr 394 - * When checking range, value should be within (tbl->extra1, tbl->extra2) 395 - */ 396 - #define SYSCTL_INT_CONV_CUSTOM(name, user_to_kern, kern_to_user, \ 397 - k_ptr_range_check) \ 398 - int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\ 399 - int dir, const struct ctl_table *tbl) \ 400 - { \ 401 - if (SYSCTL_KERN_TO_USER(dir)) \ 402 - return kern_to_user(negp, u_ptr, k_ptr); \ 403 - \ 404 - if (k_ptr_range_check) { \ 405 - int tmp_k, ret; \ 406 - if (!tbl) \ 407 - return -EINVAL; \ 408 - ret = user_to_kern(negp, u_ptr, &tmp_k); \ 409 - if (ret) \ 410 - return ret; \ 411 - if ((tbl->extra1 && *(int *)tbl->extra1 > tmp_k) || \ 412 - (tbl->extra2 && *(int *)tbl->extra2 < tmp_k)) \ 413 - return -EINVAL; \ 414 - WRITE_ONCE(*k_ptr, tmp_k); \ 415 - } else \ 416 - return user_to_kern(negp, u_ptr, k_ptr); \ 417 - return 0; \ 418 369 } 419 370 420 371 #define SYSCTL_CONV_IDENTITY(val) val