Skip to content

Commit 124afe7

Browse files
atenartPaolo Abeni
authored andcommitted
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: Antoine Tenart <[email protected]> Reviewed-by: Simon Horman <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent a8cc8fa commit 124afe7

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

net/core/sysctl_net_core.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,32 @@ int sysctl_devconf_inherit_init_net __read_mostly;
5151
EXPORT_SYMBOL(sysctl_devconf_inherit_init_net);
5252

5353
#if IS_ENABLED(CONFIG_NET_FLOW_LIMIT) || IS_ENABLED(CONFIG_RPS)
54-
static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
55-
struct cpumask *mask)
54+
static int dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
55+
struct cpumask *mask)
5656
{
57-
char kbuf[128];
57+
char *kbuf;
5858
int len;
5959

6060
if (*ppos || !*lenp) {
6161
*lenp = 0;
62-
return;
62+
return 0;
63+
}
64+
65+
/* CPUs are displayed as a hex bitmap + a comma between each groups of 8
66+
* nibbles (except the last one which has a newline instead).
67+
* Guesstimate the buffer size at the group granularity level.
68+
*/
69+
len = min(DIV_ROUND_UP(nr_cpumask_bits, 32) * (8 + 1), *lenp);
70+
kbuf = kmalloc(len, GFP_KERNEL);
71+
if (!kbuf) {
72+
*lenp = 0;
73+
return -ENOMEM;
6374
}
6475

65-
len = min(sizeof(kbuf), *lenp);
6676
len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask));
6777
if (!len) {
6878
*lenp = 0;
69-
return;
79+
goto free_buf;
7080
}
7181

7282
/* 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,
7686
memcpy(buffer, kbuf, len);
7787
*lenp = len;
7888
*ppos += len;
89+
90+
free_buf:
91+
kfree(kbuf);
92+
return 0;
7993
}
8094
#endif
8195

@@ -119,8 +133,8 @@ static int rps_default_mask_sysctl(const struct ctl_table *table, int write,
119133
if (err)
120134
goto done;
121135
} else {
122-
dump_cpumask(buffer, lenp, ppos,
123-
net->core.rps_default_mask ? : cpu_none_mask);
136+
err = dump_cpumask(buffer, lenp, ppos,
137+
net->core.rps_default_mask ? : cpu_none_mask);
124138
}
125139

126140
done:
@@ -249,7 +263,7 @@ static int flow_limit_cpu_sysctl(const struct ctl_table *table, int write,
249263
}
250264
rcu_read_unlock();
251265

252-
dump_cpumask(buffer, lenp, ppos, mask);
266+
ret = dump_cpumask(buffer, lenp, ppos, mask);
253267
}
254268

255269
done:

0 commit comments

Comments
 (0)