Skip to content

Commit

Permalink
Merge branch 'sysctl-next' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/mcgrof/linux.git
  • Loading branch information
Stephen Rothwell committed Aug 1, 2023
2 parents 4e3d452 + c233d7a commit 7f91634
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 59 deletions.
2 changes: 1 addition & 1 deletion arch/arm64/kernel/armv8_deprecated.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ static void __init register_insn_emulation(struct insn_emulation *insn)
sysctl->extra2 = &insn->max;
sysctl->proc_handler = emulation_proc_handler;

register_sysctl("abi", sysctl);
register_sysctl_sz("abi", sysctl, 1);
}
}

Expand Down
2 changes: 1 addition & 1 deletion arch/s390/appldata/appldata_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ int appldata_register_ops(struct appldata_ops *ops)
ops->ctl_table[0].proc_handler = appldata_generic_handler;
ops->ctl_table[0].data = ops;

ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table);
ops->sysctl_header = register_sysctl_sz(appldata_proc_name, ops->ctl_table, 1);
if (!ops->sysctl_header)
goto out;
return 0;
Expand Down
89 changes: 45 additions & 44 deletions fs/proc/proc_sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
#include <linux/kmemleak.h>
#include "internal.h"

#define list_for_each_table_entry(entry, table) \
for ((entry) = (table); (entry)->procname; (entry)++)
#define list_for_each_table_entry(entry, header) \
for ((entry) = (header->ctl_table); (entry)->procname; (entry)++)

static const struct dentry_operations proc_sys_dentry_operations;
static const struct file_operations proc_sys_file_operations;
Expand All @@ -43,7 +43,7 @@ static struct ctl_table sysctl_mount_point[] = {
*/
struct ctl_table_header *register_sysctl_mount_point(const char *path)
{
return register_sysctl(path, sysctl_mount_point);
return register_sysctl_sz(path, sysctl_mount_point, 0);
}
EXPORT_SYMBOL(register_sysctl_mount_point);

Expand Down Expand Up @@ -188,9 +188,10 @@ static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)

static void init_header(struct ctl_table_header *head,
struct ctl_table_root *root, struct ctl_table_set *set,
struct ctl_node *node, struct ctl_table *table)
struct ctl_node *node, struct ctl_table *table, size_t table_size)
{
head->ctl_table = table;
head->ctl_table_size = table_size;
head->ctl_table_arg = table;
head->used = 0;
head->count = 1;
Expand All @@ -204,7 +205,7 @@ static void init_header(struct ctl_table_header *head,
if (node) {
struct ctl_table *entry;

list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, head) {
node->header = head;
node++;
}
Expand All @@ -215,7 +216,7 @@ static void erase_header(struct ctl_table_header *head)
{
struct ctl_table *entry;

list_for_each_table_entry(entry, head->ctl_table)
list_for_each_table_entry(entry, head)
erase_entry(head, entry);
}

Expand All @@ -242,7 +243,7 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
err = insert_links(header);
if (err)
goto fail_links;
list_for_each_table_entry(entry, header->ctl_table) {
list_for_each_table_entry(entry, header) {
err = insert_entry(header, entry);
if (err)
goto fail;
Expand Down Expand Up @@ -973,7 +974,7 @@ static struct ctl_dir *new_dir(struct ctl_table_set *set,
memcpy(new_name, name, namelen);
table[0].procname = new_name;
table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
init_header(&new->header, set->dir.header.root, set, node, table);
init_header(&new->header, set->dir.header.root, set, node, table, 1);

return new;
}
Expand Down Expand Up @@ -1125,11 +1126,11 @@ static int sysctl_check_table_array(const char *path, struct ctl_table *table)
return err;
}

static int sysctl_check_table(const char *path, struct ctl_table *table)
static int sysctl_check_table(const char *path, struct ctl_table_header *header)
{
struct ctl_table *entry;
int err = 0;
list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, header) {
if ((entry->proc_handler == proc_dostring) ||
(entry->proc_handler == proc_dobool) ||
(entry->proc_handler == proc_dointvec) ||
Expand Down Expand Up @@ -1159,8 +1160,7 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
return err;
}

static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
struct ctl_table_root *link_root)
static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table_header *head)
{
struct ctl_table *link_table, *entry, *link;
struct ctl_table_header *links;
Expand All @@ -1170,7 +1170,7 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table

name_bytes = 0;
nr_entries = 0;
list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, head) {
nr_entries++;
name_bytes += strlen(entry->procname) + 1;
}
Expand All @@ -1189,31 +1189,33 @@ static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table
link_name = (char *)&link_table[nr_entries + 1];
link = link_table;

list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, head) {
int len = strlen(entry->procname) + 1;
memcpy(link_name, entry->procname, len);
link->procname = link_name;
link->mode = S_IFLNK|S_IRWXUGO;
link->data = link_root;
link->data = head->root;
link_name += len;
link++;
}
init_header(links, dir->header.root, dir->header.set, node, link_table);
init_header(links, dir->header.root, dir->header.set, node, link_table,
head->ctl_table_size);
links->nreg = nr_entries;

return links;
}

static bool get_links(struct ctl_dir *dir,
struct ctl_table *table, struct ctl_table_root *link_root)
struct ctl_table_header *header,
struct ctl_table_root *link_root)
{
struct ctl_table_header *head;
struct ctl_table_header *tmp_head;
struct ctl_table *entry, *link;

/* Are there links available for every entry in table? */
list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, header) {
const char *procname = entry->procname;
link = find_entry(&head, dir, procname, strlen(procname));
link = find_entry(&tmp_head, dir, procname, strlen(procname));
if (!link)
return false;
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
Expand All @@ -1224,10 +1226,10 @@ static bool get_links(struct ctl_dir *dir,
}

/* The checks passed. Increase the registration count on the links */
list_for_each_table_entry(entry, table) {
list_for_each_table_entry(entry, header) {
const char *procname = entry->procname;
link = find_entry(&head, dir, procname, strlen(procname));
head->nreg++;
link = find_entry(&tmp_head, dir, procname, strlen(procname));
tmp_head->nreg++;
}
return true;
}
Expand All @@ -1246,21 +1248,21 @@ static int insert_links(struct ctl_table_header *head)
if (IS_ERR(core_parent))
return 0;

if (get_links(core_parent, head->ctl_table, head->root))
if (get_links(core_parent, head, head->root))
return 0;

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

links = new_links(core_parent, head->ctl_table, head->root);
links = new_links(core_parent, head);

spin_lock(&sysctl_lock);
err = -ENOMEM;
if (!links)
goto out;

err = 0;
if (get_links(core_parent, head->ctl_table, head->root)) {
if (get_links(core_parent, head, head->root)) {
kfree(links);
goto out;
}
Expand Down Expand Up @@ -1310,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.
Expand Down Expand Up @@ -1352,26 +1355,21 @@ 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_dir *dir;
struct ctl_table *entry;
struct ctl_node *node;
int nr_entries = 0;

list_for_each_table_entry(entry, table)
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);
if (sysctl_check_table(path, table))
init_header(header, root, set, node, table, table_size);
if (sysctl_check_table(path, header))
goto fail;

spin_lock(&sysctl_lock);
Expand Down Expand Up @@ -1401,7 +1399,7 @@ struct ctl_table_header *__register_sysctl_table(
}

/**
* register_sysctl - register a sysctl table
* register_sysctl_sz - register a sysctl table
* @path: The path to the directory the sysctl table is in. If the path
* doesn't exist we will create it for you.
* @table: the table structure. The calller must ensure the life of the @table
Expand All @@ -1411,18 +1409,20 @@ struct ctl_table_header *__register_sysctl_table(
* to call unregister_sysctl_table() and can instead use something like
* register_sysctl_init() which does not care for the result of the syctl
* registration.
* @table_size: The number of elements in table.
*
* Register a sysctl table. @table should be a filled in ctl_table
* array. A completely 0 filled entry terminates the table.
*
* See __register_sysctl_table for more details.
*/
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
size_t table_size)
{
return __register_sysctl_table(&sysctl_table_root.default_set,
path, table);
path, table, table_size);
}
EXPORT_SYMBOL(register_sysctl);
EXPORT_SYMBOL(register_sysctl_sz);

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

if (unlikely(!hdr)) {
pr_err("failed when register_sysctl %s to %s\n", table_name, path);
pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path);
return;
}
kmemleak_not_leak(hdr);
Expand All @@ -1471,7 +1472,7 @@ static void put_links(struct ctl_table_header *header)
if (IS_ERR(core_parent))
return;

list_for_each_table_entry(entry, header->ctl_table) {
list_for_each_table_entry(entry, header) {
struct ctl_table_header *link_head;
struct ctl_table *link;
const char *name = entry->procname;
Expand Down Expand Up @@ -1535,7 +1536,7 @@ void setup_sysctl_set(struct ctl_table_set *set,
{
memset(set, 0, sizeof(*set));
set->is_seen = is_seen;
init_header(&set->dir.header, root, set, NULL, root_table);
init_header(&set->dir.header, root, set, NULL, root_table, 1);
}

void retire_sysctl_set(struct ctl_table_set *set)
Expand Down
31 changes: 24 additions & 7 deletions include/linux/sysctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,22 @@ struct ctl_node {
struct ctl_table_header *header;
};

/* struct ctl_table_header is used to maintain dynamic lists of
struct ctl_table trees. */
/**
* struct ctl_table_header - maintains dynamic lists of struct ctl_table trees
* @ctl_table: pointer to the first element in ctl_table array
* @ctl_table_size: number of elements pointed by @ctl_table
* @used: The entry will never be touched when equal to 0.
* @count: Upped every time something is added to @inodes and downed every time
* something is removed from inodes
* @nreg: When nreg drops to 0 the ctl_table_header will be unregistered.
* @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()"
*
*/
struct ctl_table_header {
union {
struct {
struct ctl_table *ctl_table;
int ctl_table_size;
int used;
int count;
int nreg;
Expand Down Expand Up @@ -205,6 +215,9 @@ struct ctl_path {
const char *procname;
};

#define register_sysctl(path, table) \
register_sysctl_sz(path, table, ARRAY_SIZE(table))

#ifdef CONFIG_SYSCTL

void proc_sys_poll_notify(struct ctl_table_poll *poll);
Expand All @@ -216,14 +229,16 @@ 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);
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
const char *path, struct ctl_table *table, size_t table_size);
struct ctl_table_header *register_sysctl_sz(const char *path, struct ctl_table *table,
size_t table_size);
void unregister_sysctl_table(struct ctl_table_header * table);

extern int sysctl_init_bases(void);
extern void __register_sysctl_init(const char *path, struct ctl_table *table,
const char *table_name);
#define register_sysctl_init(path, table) __register_sysctl_init(path, table, #table)
const char *table_name, size_t table_size);
#define register_sysctl_init(path, table) \
__register_sysctl_init(path, table, #table, ARRAY_SIZE(table))
extern struct ctl_table_header *register_sysctl_mount_point(const char *path);

void do_sysctl_args(void);
Expand Down Expand Up @@ -252,7 +267,9 @@ static inline struct ctl_table_header *register_sysctl_mount_point(const char *p
return NULL;
}

static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
static inline struct ctl_table_header *register_sysctl_sz(const char *path,
struct ctl_table *table,
size_t table_size)
{
return NULL;
}
Expand Down
4 changes: 3 additions & 1 deletion ipc/ipc_sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,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);
Expand Down
Loading

0 comments on commit 7f91634

Please sign in to comment.