Commit bff97cf1 authored by Joel Granados's avatar Joel Granados Committed by Luis Chamberlain
Browse files

sysctl: Add a size arg to __register_sysctl_table



We make these changes in order to prepare __register_sysctl_table and
its callers for when we remove the sentinel element (empty element at
the end of ctl_table arrays). We don't actually remove any sentinels in
this commit, but we *do* make sure to use ARRAY_SIZE so the table_size
is available when the removal occurs.

We add a table_size argument to __register_sysctl_table and adjust
callers, all of which pass ctl_table pointers and need an explicit call
to ARRAY_SIZE. We implement a size calculation in register_net_sysctl in
order to forward the size of the array pointer received from the network
register calls.

The new table_size argument does not yet have any effect in the
init_header call which is still dependent on the sentinel's presence.
table_size *does* however drive the `kzalloc` allocation in
__register_sysctl_table with no adverse effects as the allocated memory
is either one element greater than the calculated ctl_table array (for
the calls in ipc_sysctl.c, mq_sysctl.c and ucount.c) or the exact size
of the calculated ctl_table array (for the call from sysctl_net.c and
register_sysctl). This approach will allows us to "just" remove the
sentinel without further changes to __register_sysctl_table as
table_size will represent the exact size for all the callers at that
point.

Signed-off-by: default avatarJoel Granados <j.granados@samsung.com>
Signed-off-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
parent b1f01e2b
Loading
Loading
Loading
Loading
+12 −11
Original line number Diff line number Diff line
@@ -1312,6 +1312,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
 * 	 should not be free'd after registration. So it should not be
 * 	 used on stack. It can either be a global or dynamically allocated
 * 	 by the caller and free'd later after sysctl unregistration.
 * @table_size : The number of elements in table
 *
 * Register a sysctl table hierarchy. @table should be a filled in ctl_table
 * array. A completely 0 filled entry terminates the table.
@@ -1354,27 +1355,20 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
 */
struct ctl_table_header *__register_sysctl_table(
	struct ctl_table_set *set,
	const char *path, struct ctl_table *table)
	const char *path, struct ctl_table *table, size_t table_size)
{
	struct ctl_table_root *root = set->dir.header.root;
	struct ctl_table_header *header;
	struct ctl_table_header h_tmp;
	struct ctl_dir *dir;
	struct ctl_table *entry;
	struct ctl_node *node;
	int nr_entries = 0;

	h_tmp.ctl_table = table;
	list_for_each_table_entry(entry, (&h_tmp))
		nr_entries++;

	header = kzalloc(sizeof(struct ctl_table_header) +
			 sizeof(struct ctl_node)*nr_entries, GFP_KERNEL_ACCOUNT);
			 sizeof(struct ctl_node)*table_size, GFP_KERNEL_ACCOUNT);
	if (!header)
		return NULL;

	node = (struct ctl_node *)(header + 1);
	init_header(header, root, set, node, table, nr_entries);
	init_header(header, root, set, node, table, table_size);
	if (sysctl_check_table(path, header))
		goto fail;

@@ -1423,8 +1417,15 @@ struct ctl_table_header *__register_sysctl_table(
 */
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
{
	int count = 0;
	struct ctl_table *entry;
	struct ctl_table_header t_hdr;

	t_hdr.ctl_table = table;
	list_for_each_table_entry(entry, (&t_hdr))
		count++;
	return __register_sysctl_table(&sysctl_table_root.default_set,
					path, table);
					path, table, count);
}
EXPORT_SYMBOL(register_sysctl);

+1 −1
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ extern void retire_sysctl_set(struct ctl_table_set *set);

struct ctl_table_header *__register_sysctl_table(
	struct ctl_table_set *set,
	const char *path, struct ctl_table *table);
	const char *path, struct ctl_table *table, size_t table_size);
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
void unregister_sysctl_table(struct ctl_table_header * table);

+3 −1
Original line number Diff line number Diff line
@@ -259,7 +259,9 @@ bool setup_ipc_sysctls(struct ipc_namespace *ns)
				tbl[i].data = NULL;
		}

		ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
		ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set,
							  "kernel", tbl,
							  ARRAY_SIZE(ipc_sysctls));
	}
	if (!ns->ipc_sysctls) {
		kfree(tbl);
+3 −1
Original line number Diff line number Diff line
@@ -109,7 +109,9 @@ bool setup_mq_sysctls(struct ipc_namespace *ns)
				tbl[i].data = NULL;
		}

		ns->mq_sysctls = __register_sysctl_table(&ns->mq_set, "fs/mqueue", tbl);
		ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
							 "fs/mqueue", tbl,
							 ARRAY_SIZE(mq_sysctls));
	}
	if (!ns->mq_sysctls) {
		kfree(tbl);
+2 −1
Original line number Diff line number Diff line
@@ -104,7 +104,8 @@ bool setup_userns_sysctls(struct user_namespace *ns)
		for (i = 0; i < UCOUNT_COUNTS; i++) {
			tbl[i].data = &ns->ucount_max[i];
		}
		ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
		ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl,
						      ARRAY_SIZE(user_table));
	}
	if (!ns->sysctls) {
		kfree(tbl);
Loading