Commit 124afe77 authored by Antoine Tenart's avatar Antoine Tenart Committed by Paolo Abeni
Browse files

net: sysctl: allow dump_cpumask to handle higher numbers of CPUs



This fixes the output of rps_default_mask and flow_limit_cpu_bitmap when
the CPU count is > 448, as it was truncated.

The underlying values are actually stored correctly when writing to
these sysctl but displaying them uses a fixed length temporary buffer in
dump_cpumask. This buffer can be too small if the CPU count is > 448.

Fix this by dynamically allocating the buffer in dump_cpumask, using a
guesstimate of what we need.

Signed-off-by: default avatarAntoine Tenart <atenart@kernel.org>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent a8cc8fa1
Loading
Loading
Loading
Loading
+23 −9
Original line number Diff line number Diff line
@@ -51,22 +51,32 @@ int sysctl_devconf_inherit_init_net __read_mostly;
EXPORT_SYMBOL(sysctl_devconf_inherit_init_net);

#if IS_ENABLED(CONFIG_NET_FLOW_LIMIT) || IS_ENABLED(CONFIG_RPS)
static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
static int dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
			struct cpumask *mask)
{
	char kbuf[128];
	char *kbuf;
	int len;

	if (*ppos || !*lenp) {
		*lenp = 0;
		return;
		return 0;
	}

	/* CPUs are displayed as a hex bitmap + a comma between each groups of 8
	 * nibbles (except the last one which has a newline instead).
	 * Guesstimate the buffer size at the group granularity level.
	 */
	len = min(DIV_ROUND_UP(nr_cpumask_bits, 32) * (8 + 1), *lenp);
	kbuf = kmalloc(len, GFP_KERNEL);
	if (!kbuf) {
		*lenp = 0;
		return -ENOMEM;
	}

	len = min(sizeof(kbuf), *lenp);
	len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask));
	if (!len) {
		*lenp = 0;
		return;
		goto free_buf;
	}

	/* scnprintf writes a trailing null char not counted in the returned
@@ -76,6 +86,10 @@ static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
	memcpy(buffer, kbuf, len);
	*lenp = len;
	*ppos += len;

free_buf:
	kfree(kbuf);
	return 0;
}
#endif

@@ -119,7 +133,7 @@ static int rps_default_mask_sysctl(const struct ctl_table *table, int write,
		if (err)
			goto done;
	} else {
		dump_cpumask(buffer, lenp, ppos,
		err = dump_cpumask(buffer, lenp, ppos,
				   net->core.rps_default_mask ? : cpu_none_mask);
	}

@@ -249,7 +263,7 @@ static int flow_limit_cpu_sysctl(const struct ctl_table *table, int write,
		}
		rcu_read_unlock();

		dump_cpumask(buffer, lenp, ppos, mask);
		ret = dump_cpumask(buffer, lenp, ppos, mask);
	}

done: