Skip to content

Commit adfd671

Browse files
committed
Merge tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux
Pull sysctl updates from Luis Chamberlain: "Long ago we set out to remove the kitchen sink on kernel/sysctl.c arrays and placings sysctls to their own sybsystem or file to help avoid merge conflicts. Matthew Wilcox pointed out though that if we're going to do that we might as well also *save* space while at it and try to remove the extra last sysctl entry added at the end of each array, a sentintel, instead of bloating the kernel by adding a new sentinel with each array moved. Doing that was not so trivial, and has required slowing down the moves of kernel/sysctl.c arrays and measuring the impact on size by each new move. The complex part of the effort to help reduce the size of each sysctl is being done by the patient work of el señor Don Joel Granados. A lot of this is truly painful code refactoring and testing and then trying to measure the savings of each move and removing the sentinels. Although Joel already has code which does most of this work, experience with sysctl moves in the past shows is we need to be careful due to the slew of odd build failures that are possible due to the amount of random Kconfig options sysctls use. To that end Joel's work is split by first addressing the major housekeeping needed to remove the sentinels, which is part of this merge request. The rest of the work to actually remove the sentinels will be done later in future kernel releases. The preliminary math is showing this will all help reduce the overall build time size of the kernel and run time memory consumed by the kernel by about ~64 bytes per array where we are able to remove each sentinel in the future. That also means there is no more bloating the kernel with the extra ~64 bytes per array moved as no new sentinels are created" * tag 'sysctl-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux: sysctl: Use ctl_table_size as stopping criteria for list macro sysctl: SIZE_MAX->ARRAY_SIZE in register_net_sysctl vrf: Update to register_net_sysctl_sz networking: Update to register_net_sysctl_sz netfilter: Update to register_net_sysctl_sz ax.25: Update to register_net_sysctl_sz sysctl: Add size to register_net_sysctl function sysctl: Add size arg to __register_sysctl_init sysctl: Add size to register_sysctl sysctl: Add a size arg to __register_sysctl_table sysctl: Add size argument to init_header sysctl: Add ctl_table_size to ctl_table_header sysctl: Use ctl_table_header in list_for_each_table_entry sysctl: Prefer ctl_table_header in proc_sysctl
2 parents daa22f5 + 53f3811 commit adfd671

40 files changed

+222
-113
lines changed

arch/arm64/kernel/armv8_deprecated.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ static void __init register_insn_emulation(struct insn_emulation *insn)
569569
sysctl->extra2 = &insn->max;
570570
sysctl->proc_handler = emulation_proc_handler;
571571

572-
register_sysctl("abi", sysctl);
572+
register_sysctl_sz("abi", sysctl, 1);
573573
}
574574
}
575575

arch/s390/appldata/appldata_base.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ int appldata_register_ops(struct appldata_ops *ops)
365365
ops->ctl_table[0].proc_handler = appldata_generic_handler;
366366
ops->ctl_table[0].data = ops;
367367

368-
ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table);
368+
ops->sysctl_header = register_sysctl_sz(appldata_proc_name, ops->ctl_table, 1);
369369
if (!ops->sysctl_header)
370370
goto out;
371371
return 0;

drivers/net/vrf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,8 @@ static int vrf_netns_init_sysctl(struct net *net, struct netns_vrf *nn_vrf)
19771977
/* init the extra1 parameter with the reference to current netns */
19781978
table[0].extra1 = net;
19791979

1980-
nn_vrf->ctl_hdr = register_net_sysctl(net, "net/vrf", table);
1980+
nn_vrf->ctl_hdr = register_net_sysctl_sz(net, "net/vrf", table,
1981+
ARRAY_SIZE(vrf_table));
19811982
if (!nn_vrf->ctl_hdr) {
19821983
kfree(table);
19831984
return -ENOMEM;

fs/proc/proc_sysctl.c

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
#include <linux/kmemleak.h>
2020
#include "internal.h"
2121

22-
#define list_for_each_table_entry(entry, table) \
23-
for ((entry) = (table); (entry)->procname; (entry)++)
22+
#define list_for_each_table_entry(entry, header) \
23+
entry = header->ctl_table; \
24+
for (size_t i = 0 ; i < header->ctl_table_size && entry->procname; ++i, entry++)
2425

2526
static const struct dentry_operations proc_sys_dentry_operations;
2627
static const struct file_operations proc_sys_file_operations;
@@ -43,7 +44,7 @@ static struct ctl_table sysctl_mount_point[] = {
4344
*/
4445
struct ctl_table_header *register_sysctl_mount_point(const char *path)
4546
{
46-
return register_sysctl(path, sysctl_mount_point);
47+
return register_sysctl_sz(path, sysctl_mount_point, 0);
4748
}
4849
EXPORT_SYMBOL(register_sysctl_mount_point);
4950

@@ -188,9 +189,10 @@ static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)
188189

189190
static void init_header(struct ctl_table_header *head,
190191
struct ctl_table_root *root, struct ctl_table_set *set,
191-
struct ctl_node *node, struct ctl_table *table)
192+
struct ctl_node *node, struct ctl_table *table, size_t table_size)
192193
{
193194
head->ctl_table = table;
195+
head->ctl_table_size = table_size;
194196
head->ctl_table_arg = table;
195197
head->used = 0;
196198
head->count = 1;
@@ -204,7 +206,7 @@ static void init_header(struct ctl_table_header *head,
204206
if (node) {
205207
struct ctl_table *entry;
206208

207-
list_for_each_table_entry(entry, table) {
209+
list_for_each_table_entry(entry, head) {
208210
node->header = head;
209211
node++;
210212
}
@@ -215,7 +217,7 @@ static void erase_header(struct ctl_table_header *head)
215217
{
216218
struct ctl_table *entry;
217219

218-
list_for_each_table_entry(entry, head->ctl_table)
220+
list_for_each_table_entry(entry, head)
219221
erase_entry(head, entry);
220222
}
221223

@@ -242,7 +244,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
242244
err = insert_links(header);
243245
if (err)
244246
goto fail_links;
245-
list_for_each_table_entry(entry, header->ctl_table) {
247+
list_for_each_table_entry(entry, header) {
246248
err = insert_entry(header, entry);
247249
if (err)
248250
goto fail;
@@ -973,7 +975,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
973975
memcpy(new_name, name, namelen);
974976
table[0].procname = new_name;
975977
table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
976-
init_header(&new->header, set->dir.header.root, set, node, table);
978+
init_header(&new->header, set->dir.header.root, set, node, table, 1);
977979

978980
return new;
979981
}
@@ -1125,11 +1127,11 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table)
11251127
return err;
11261128
}
11271129

1128-
static int sysctl_check_table(const char *path, struct ctl_table *table)
1130+
static int sysctl_check_table(const char *path, struct ctl_table_header *header)
11291131
{
11301132
struct ctl_table *entry;
11311133
int err = 0;
1132-
list_for_each_table_entry(entry, table) {
1134+
list_for_each_table_entry(entry, header) {
11331135
if ((entry->proc_handler == proc_dostring) ||
11341136
(entry->proc_handler == proc_dobool) ||
11351137
(entry->proc_handler == proc_dointvec) ||
@@ -1159,8 +1161,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
11591161
return err;
11601162
}
11611163

1162-
static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
1163-
struct ctl_table_root *link_root)
1164+
static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_header *head)
11641165
{
11651166
struct ctl_table *link_table, *entry, *link;
11661167
struct ctl_table_header *links;
@@ -1170,7 +1171,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table
11701171

11711172
name_bytes = 0;
11721173
nr_entries = 0;
1173-
list_for_each_table_entry(entry, table) {
1174+
list_for_each_table_entry(entry, head) {
11741175
nr_entries++;
11751176
name_bytes += strlen(entry->procname) + 1;
11761177
}
@@ -1189,31 +1190,33 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table
11891190
link_name = (char *)&link_table[nr_entries + 1];
11901191
link = link_table;
11911192

1192-
list_for_each_table_entry(entry, table) {
1193+
list_for_each_table_entry(entry, head) {
11931194
int len = strlen(entry->procname) + 1;
11941195
memcpy(link_name, entry->procname, len);
11951196
link->procname = link_name;
11961197
link->mode = S_IFLNK|S_IRWXUGO;
1197-
link->data = link_root;
1198+
link->data = head->root;
11981199
link_name += len;
11991200
link++;
12001201
}
1201-
init_header(links, dir->header.root, dir->header.set, node, link_table);
1202+
init_header(links, dir->header.root, dir->header.set, node, link_table,
1203+
head->ctl_table_size);
12021204
links->nreg = nr_entries;
12031205

12041206
return links;
12051207
}
12061208

12071209
static bool get_links(struct ctl_dir *dir,
1208-
struct ctl_table *table, struct ctl_table_root *link_root)
1210+
struct ctl_table_header *header,
1211+
struct ctl_table_root *link_root)
12091212
{
1210-
struct ctl_table_header *head;
1213+
struct ctl_table_header *tmp_head;
12111214
struct ctl_table *entry, *link;
12121215

12131216
/* Are there links available for every entry in table? */
1214-
list_for_each_table_entry(entry, table) {
1217+
list_for_each_table_entry(entry, header) {
12151218
const char *procname = entry->procname;
1216-
link = find_entry(&head, dir, procname, strlen(procname));
1219+
link = find_entry(&tmp_head, dir, procname, strlen(procname));
12171220
if (!link)
12181221
return false;
12191222
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
@@ -1224,10 +1227,10 @@ static bool get_links(struct ctl_dir *dir,
12241227
}
12251228

12261229
/* The checks passed. Increase the registration count on the links */
1227-
list_for_each_table_entry(entry, table) {
1230+
list_for_each_table_entry(entry, header) {
12281231
const char *procname = entry->procname;
1229-
link = find_entry(&head, dir, procname, strlen(procname));
1230-
head->nreg++;
1232+
link = find_entry(&tmp_head, dir, procname, strlen(procname));
1233+
tmp_head->nreg++;
12311234
}
12321235
return true;
12331236
}
@@ -1246,21 +1249,21 @@ static int insert_links(struct ctl_table_header *head)
12461249
if (IS_ERR(core_parent))
12471250
return 0;
12481251

1249-
if (get_links(core_parent, head->ctl_table, head->root))
1252+
if (get_links(core_parent, head, head->root))
12501253
return 0;
12511254

12521255
core_parent->header.nreg++;
12531256
spin_unlock(&sysctl_lock);
12541257

1255-
links = new_links(core_parent, head->ctl_table, head->root);
1258+
links = new_links(core_parent, head);
12561259

12571260
spin_lock(&sysctl_lock);
12581261
err = -ENOMEM;
12591262
if (!links)
12601263
goto out;
12611264

12621265
err = 0;
1263-
if (get_links(core_parent, head->ctl_table, head->root)) {
1266+
if (get_links(core_parent, head, head->root)) {
12641267
kfree(links);
12651268
goto out;
12661269
}
@@ -1310,6 +1313,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
13101313
* should not be free'd after registration. So it should not be
13111314
* used on stack. It can either be a global or dynamically allocated
13121315
* by the caller and free'd later after sysctl unregistration.
1316+
* @table_size : The number of elements in table
13131317
*
13141318
* Register a sysctl table hierarchy. @table should be a filled in ctl_table
13151319
* array. A completely 0 filled entry terminates the table.
@@ -1352,26 +1356,21 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
13521356
*/
13531357
struct ctl_table_header *__register_sysctl_table(
13541358
struct ctl_table_set *set,
1355-
const char *path, struct ctl_table *table)
1359+
const char *path, struct ctl_table *table, size_t table_size)
13561360
{
13571361
struct ctl_table_root *root = set->dir.header.root;
13581362
struct ctl_table_header *header;
13591363
struct ctl_dir *dir;
1360-
struct ctl_table *entry;
13611364
struct ctl_node *node;
1362-
int nr_entries = 0;
1363-
1364-
list_for_each_table_entry(entry, table)
1365-
nr_entries++;
13661365

13671366
header = kzalloc(sizeof(struct ctl_table_header) +
1368-
sizeof(struct ctl_node)*nr_entries, GFP_KERNEL_ACCOUNT);
1367+
sizeof(struct ctl_node)*table_size, GFP_KERNEL_ACCOUNT);
13691368
if (!header)
13701369
return NULL;
13711370

13721371
node = (struct ctl_node *)(header + 1);
1373-
init_header(header, root, set, node, table);
1374-
if (sysctl_check_table(path, table))
1372+
init_header(header, root, set, node, table, table_size);
1373+
if (sysctl_check_table(path, header))
13751374
goto fail;
13761375

13771376
spin_lock(&sysctl_lock);
@@ -1401,7 +1400,7 @@ struct ctl_table_header *__register_sysctl_table(
14011400
}
14021401

14031402
/**
1404-
* register_sysctl - register a sysctl table
1403+
* register_sysctl_sz - register a sysctl table
14051404
* @path: The path to the directory the sysctl table is in. If the path
14061405
* doesn't exist we will create it for you.
14071406
* @table: the table structure. The calller must ensure the life of the @table
@@ -1411,18 +1410,20 @@ struct ctl_table_header *__register_sysctl_table(
14111410
* to call unregister_sysctl_table() and can instead use something like
14121411
* register_sysctl_init() which does not care for the result of the syctl
14131412
* registration.
1413+
* @table_size: The number of elements in table.
14141414
*
14151415
* Register a sysctl table. @table should be a filled in ctl_table
14161416
* array. A completely 0 filled entry terminates the table.
14171417
*
14181418
* See __register_sysctl_table for more details.
14191419
*/
1420-
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
1420+
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
1421+
size_t table_size)
14211422
{
14221423
return __register_sysctl_table(&sysctl_table_root.default_set,
1423-
path, table);
1424+
path, table, table_size);
14241425
}
1425-
EXPORT_SYMBOL(register_sysctl);
1426+
EXPORT_SYMBOL(register_sysctl_sz);
14261427

14271428
/**
14281429
* __register_sysctl_init() - register sysctl table to path
@@ -1433,6 +1434,7 @@ EXPORT_SYMBOL(register_sysctl);
14331434
* lifetime use of the sysctl.
14341435
* @table_name: The name of sysctl table, only used for log printing when
14351436
* registration fails
1437+
* @table_size: The number of elements in table
14361438
*
14371439
* The sysctl interface is used by userspace to query or modify at runtime
14381440
* a predefined value set on a variable. These variables however have default
@@ -1445,12 +1447,12 @@ EXPORT_SYMBOL(register_sysctl);
14451447
* Context: if your base directory does not exist it will be created for you.
14461448
*/
14471449
void __init __register_sysctl_init(const char *path, struct ctl_table *table,
1448-
const char *table_name)
1450+
const char *table_name, size_t table_size)
14491451
{
1450-
struct ctl_table_header *hdr = register_sysctl(path, table);
1452+
struct ctl_table_header *hdr = register_sysctl_sz(path, table, table_size);
14511453

14521454
if (unlikely(!hdr)) {
1453-
pr_err("failed when register_sysctl %s to %s\n", table_name, path);
1455+
pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path);
14541456
return;
14551457
}
14561458
kmemleak_not_leak(hdr);
@@ -1471,7 +1473,7 @@ static void put_links(struct ctl_table_header *header)
14711473
if (IS_ERR(core_parent))
14721474
return;
14731475

1474-
list_for_each_table_entry(entry, header->ctl_table) {
1476+
list_for_each_table_entry(entry, header) {
14751477
struct ctl_table_header *link_head;
14761478
struct ctl_table *link;
14771479
const char *name = entry->procname;
@@ -1535,7 +1537,7 @@ void setup_sysctl_set(struct ctl_table_set *set,
15351537
{
15361538
memset(set, 0, sizeof(*set));
15371539
set->is_seen = is_seen;
1538-
init_header(&set->dir.header, root, set, NULL, root_table);
1540+
init_header(&set->dir.header, root, set, NULL, root_table, 1);
15391541
}
15401542

15411543
void retire_sysctl_set(struct ctl_table_set *set)

include/linux/sysctl.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,22 @@ struct ctl_node {
159159
struct ctl_table_header *header;
160160
};
161161

162-
/* struct ctl_table_header is used to maintain dynamic lists of
163-
struct ctl_table trees. */
162+
/**
163+
* struct ctl_table_header - maintains dynamic lists of struct ctl_table trees
164+
* @ctl_table: pointer to the first element in ctl_table array
165+
* @ctl_table_size: number of elements pointed by @ctl_table
166+
* @used: The entry will never be touched when equal to 0.
167+
* @count: Upped every time something is added to @inodes and downed every time
168+
* something is removed from inodes
169+
* @nreg: When nreg drops to 0 the ctl_table_header will be unregistered.
170+
* @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()"
171+
*
172+
*/
164173
struct ctl_table_header {
165174
union {
166175
struct {
167176
struct ctl_table *ctl_table;
177+
int ctl_table_size;
168178
int used;
169179
int count;
170180
int nreg;
@@ -205,6 +215,9 @@ struct ctl_path {
205215
const char *procname;
206216
};
207217

218+
#define register_sysctl(path, table) \
219+
register_sysctl_sz(path, table, ARRAY_SIZE(table))
220+
208221
#ifdef CONFIG_SYSCTL
209222

210223
void proc_sys_poll_notify(struct ctl_table_poll *poll);
@@ -216,14 +229,16 @@ extern void retire_sysctl_set(struct ctl_table_set *set);
216229

217230
struct ctl_table_header *__register_sysctl_table(
218231
struct ctl_table_set *set,
219-
const char *path, struct ctl_table *table);
220-
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
232+
const char *path, struct ctl_table *table, size_t table_size);
233+
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
234+
size_t table_size);
221235
void unregister_sysctl_table(struct ctl_table_header * table);
222236

223237
extern int sysctl_init_bases(void);
224238
extern void __register_sysctl_init(const char *path, struct ctl_table *table,
225-
const char *table_name);
226-
#define register_sysctl_init(path, table) __register_sysctl_init(path, table, #table)
239+
const char *table_name, size_t table_size);
240+
#define register_sysctl_init(path, table) \
241+
__register_sysctl_init(path, table, #table, ARRAY_SIZE(table))
227242
extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
228243

229244
void do_sysctl_args(void);
@@ -252,7 +267,9 @@ static inline struct ctl_table_header *register_sysctl_mount_point(const char *p
252267
return NULL;
253268
}
254269

255-
static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
270+
static inline struct ctl_table_header *register_sysctl_sz(const char *path,
271+
struct ctl_table *table,
272+
size_t table_size)
256273
{
257274
return NULL;
258275
}

0 commit comments

Comments
 (0)