Commit ef153851 authored by Joel Granados's avatar Joel Granados
Browse files

sysctl: Replace unidirectional INT converter macros with functions



Replace SYSCTL_USER_TO_KERN_INT_CONV and SYSCTL_KERN_TO_USER_INT_CONV
macros with function implementing the same logic.This makes debugging
easier and aligns with the functions preference described in
coding-style.rst. Update all jiffies converters to use explicit function
implementations instead of macro-generated versions.

Signed-off-by: default avatarJoel Granados <joel.granados@kernel.org>
parent b3af263b
Loading
Loading
Loading
Loading
+7 −49
Original line number Diff line number Diff line
@@ -74,40 +74,6 @@ extern const int sysctl_vals[];
#define SYSCTL_KERN_TO_USER(dir) (!dir)

#ifdef CONFIG_PROC_SYSCTL
#define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op)		\
int sysctl_user_to_kern_int_conv##name(const bool *negp,	\
				       const unsigned long *u_ptr,\
				       int *k_ptr)		\
{								\
	unsigned long u = u_ptr_op(*u_ptr);			\
	if (*negp) {						\
		if (u > (unsigned long) INT_MAX + 1)		\
			return -EINVAL;				\
		WRITE_ONCE(*k_ptr, -u);				\
	} else {						\
		if (u > (unsigned long) INT_MAX)		\
			return -EINVAL;				\
		WRITE_ONCE(*k_ptr, u);				\
	}							\
	return 0;						\
}

#define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op)		\
int sysctl_kern_to_user_int_conv##name(bool *negp,		\
				       unsigned long *u_ptr,	\
				       const int *k_ptr)	\
{								\
	int val = READ_ONCE(*k_ptr);				\
	if (val < 0) {						\
		*negp = true;					\
		*u_ptr = -k_ptr_op((unsigned long)val);		\
	} else {						\
		*negp = false;					\
		*u_ptr = k_ptr_op((unsigned long)val);		\
	}							\
	return 0;						\
}

/**
 * To range check on a converted value, use a temp k_ptr
 * When checking range, value should be within (tbl->extra1, tbl->extra2)
@@ -135,22 +101,8 @@ int do_proc_int_conv##name(bool *negp, unsigned long *u_ptr, int *k_ptr,\
		return user_to_kern(negp, u_ptr, k_ptr);		\
	return 0;							\
}
#else // CONFIG_PROC_SYSCTL
#define SYSCTL_USER_TO_KERN_INT_CONV(name, u_ptr_op)		\
int sysctl_user_to_kern_int_conv##name(const bool *negp,	\
				       const unsigned long *u_ptr,\
				       int *k_ptr)		\
{								\
	return -ENOSYS;						\
}

#define SYSCTL_KERN_TO_USER_INT_CONV(name, k_ptr_op)		\
int sysctl_kern_to_user_int_conv##name(bool *negp,		\
				       unsigned long *u_ptr,	\
				       const int *k_ptr)	\
{								\
	return -ENOSYS;						\
}
#else // CONFIG_PROC_SYSCTL

#define SYSCTL_INT_CONV_CUSTOM(name, user_to_kern, kern_to_user,	\
			       k_ptr_range_check)			\
@@ -170,6 +122,7 @@ typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
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,
			 size_t *lenp, loff_t *ppos);
@@ -177,6 +130,11 @@ 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));
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_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);
+67 −2
Original line number Diff line number Diff line
@@ -458,8 +458,73 @@ static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir,
			      proc_uint_u2k_conv, proc_uint_k2u_conv);
}

static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
/**
 * proc_int_k2u_conv_kop - Assign kernel value to a user space pointer
 * @u_ptr: pointer to user space variable
 * @k_ptr: pointer to kernel variable
 * @negp: assigned %TRUE if the converted kernel value is negative;
 *        %FALSE otherweise
 * @k_ptr_op: execute this function before assigning to u_ptr
 *
 * Uses READ_ONCE to get value from k_ptr. Executes k_ptr_op before assigning
 * to u_ptr if not NULL. Does **not** check for overflow.
 *
 * Returns: 0 on success.
 */
int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp,
			  ulong (*k_ptr_op)(const ulong))
{
	int val = READ_ONCE(*k_ptr);

	if (val < 0) {
		*negp = true;
		*u_ptr = k_ptr_op ? -k_ptr_op((ulong)val) : -(ulong)val;
	} else {
		*negp = false;
		*u_ptr = k_ptr_op ? k_ptr_op((ulong)val) : (ulong) val;
	}
	return 0;
}

/**
 * proc_int_u2k_conv_uop - Assign user value to a kernel pointer
 * @u_ptr: pointer to user space variable
 * @k_ptr: pointer to kernel variable
 * @negp: If %TRUE, the converted user value is made negative.
 * @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. Check for overflow with UINT_MAX.
 *
 * Returns: 0 on success.
 */
int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
			  ulong (*u_ptr_op)(const ulong))
{
	ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr;

	if (*negp) {
		if (u > (ulong) INT_MAX + 1)
			return -EINVAL;
		WRITE_ONCE(*k_ptr, -u);
	} else {
		if (u > (ulong) INT_MAX)
			return -EINVAL;
		WRITE_ONCE(*k_ptr, u);
	}
	return 0;
}

static int sysctl_user_to_kern_int_conv(const bool *negp, const ulong *u_ptr,
					int *k_ptr)
{
	return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, NULL);
}

static int sysctl_kern_to_user_int_conv(bool *negp, ulong *u_ptr, const int *k_ptr)
{
	return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, NULL);
}

static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
			      sysctl_kern_to_user_int_conv, false)
+93 −18
Original line number Diff line number Diff line
@@ -100,26 +100,101 @@ void __init register_refined_jiffies(long cycles_per_second)
	__clocksource_register(&refined_jiffies);
}

#define SYSCTL_CONV_MULT_HZ(val) ((val) * HZ)
#define SYSCTL_CONV_DIV_HZ(val) ((val) / HZ)

static SYSCTL_USER_TO_KERN_INT_CONV(_hz, SYSCTL_CONV_MULT_HZ)
static SYSCTL_KERN_TO_USER_INT_CONV(_hz, SYSCTL_CONV_DIV_HZ)
static SYSCTL_USER_TO_KERN_INT_CONV(_userhz, clock_t_to_jiffies)
static SYSCTL_KERN_TO_USER_INT_CONV(_userhz, jiffies_to_clock_t)
static SYSCTL_USER_TO_KERN_INT_CONV(_ms, msecs_to_jiffies)
static SYSCTL_KERN_TO_USER_INT_CONV(_ms, jiffies_to_msecs)

static SYSCTL_INT_CONV_CUSTOM(_jiffies, sysctl_user_to_kern_int_conv_hz,
			      sysctl_kern_to_user_int_conv_hz, false)
#ifdef CONFIG_PROC_SYSCTL
static ulong mult_hz(const ulong val)
{
	return val * HZ;
}

static ulong div_hz(const ulong val)
{
	return val / HZ;
}

static int sysctl_u2k_int_conv_hz(const bool *negp, const ulong *u_ptr, int *k_ptr)
{
	return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, mult_hz);
}

static int sysctl_k2u_int_conv_hz(bool *negp, ulong *u_ptr, const int *k_ptr)
{
	return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, div_hz);
}

static int sysctl_u2k_int_conv_userhz(const bool *negp, const ulong *u_ptr, int *k_ptr)
{
	return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, clock_t_to_jiffies);
}

static ulong sysctl_jiffies_to_clock_t(const ulong val)
{
	return jiffies_to_clock_t(val);
}

static int sysctl_k2u_int_conv_userhz(bool *negp, ulong *u_ptr, const int *k_ptr)
{
	return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_clock_t);
}

static ulong sysctl_msecs_to_jiffies(const ulong val)
{
	return msecs_to_jiffies(val);
}

static int sysctl_u2k_int_conv_ms(const bool *negp, const ulong *u_ptr, int *k_ptr)
{
	return proc_int_u2k_conv_uop(u_ptr, k_ptr, negp, sysctl_msecs_to_jiffies);
}

static ulong sysctl_jiffies_to_msecs(const ulong val)
{
	return jiffies_to_msecs(val);
}

static int sysctl_k2u_int_conv_ms(bool *negp, ulong *u_ptr, const int *k_ptr)
{
	return proc_int_k2u_conv_kop(u_ptr, k_ptr, negp, sysctl_jiffies_to_msecs);
}


static SYSCTL_INT_CONV_CUSTOM(_jiffies, sysctl_u2k_int_conv_hz,
			      sysctl_k2u_int_conv_hz, false)
static SYSCTL_INT_CONV_CUSTOM(_userhz_jiffies,
			      sysctl_user_to_kern_int_conv_userhz,
			      sysctl_kern_to_user_int_conv_userhz, false)
static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies, sysctl_user_to_kern_int_conv_ms,
			      sysctl_kern_to_user_int_conv_ms, false)
			      sysctl_u2k_int_conv_userhz,
			      sysctl_k2u_int_conv_userhz, false)
static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies, sysctl_u2k_int_conv_ms,
			      sysctl_k2u_int_conv_ms, false)
static SYSCTL_INT_CONV_CUSTOM(_ms_jiffies_minmax,
			      sysctl_user_to_kern_int_conv_ms,
			      sysctl_kern_to_user_int_conv_ms, true)
			      sysctl_u2k_int_conv_ms,
			      sysctl_k2u_int_conv_ms, true)

#else // CONFIG_PROC_SYSCTL
static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
				    int dir, const struct ctl_table *tbl)
{
	return -ENOSYS;
}

static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr,
					   int *k_ptr, int dir,
					   const struct ctl_table *tbl)
{
	return -ENOSYS;
}

static int do_proc_int_conv_ms_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
				       int dir, const struct ctl_table *tbl)
{
	return -ENOSYS;
}

static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
					      int *k_ptr, int dir,
					      const struct ctl_table *tbl)
{
	return -ENOSYS;
}
#endif

/**
 * proc_dointvec_jiffies - read a vector of integers as seconds