v6.5-rc1-sysctl-next

The changes queued up for v6.5-rc1 for sysctl are in line with
 prior efforts to stop usage of deprecated routines which incur
 recursion and also make it hard to remove the empty array element
 in each sysctl array declaration. The most difficult user to modify
 was parport which required a bit of re-thinking of how to declare shared
 sysctls there, Joel Granados has stepped up to the plate to do most of
 this work and eventual removal of register_sysctl_table(). That work
 ended up saving us about 1465 bytes according to bloat-o-meter. Since
 we gained a few bloat-o-meter karma points I moved two rather small
 sysctl arrays from kernel/sysctl.c leaving us only two more sysctl
 arrays to move left.
 
 Most changes have been tested on linux-next for about a month. The last
 straggler patches are a minor parport fix, changes to the sysctl
 kernel selftest so to verify correctness and prevent regressions for
 the future change he made to provide an alternative solution for the
 special sysctl mount point target which was using the now deprecated
 sysctl child element.
 
 This is all prep work to now finally be able to remove the empty
 array element in all sysctl declarations / registrations which is
 expected to save us a bit of bytes all over the kernel. That work
 will be tested early after v6.5-rc1 is out.
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCgAwFiEENnNq2KuOejlQLZofziMdCjCSiKcFAmSceh0SHG1jZ3JvZkBr
 ZXJuZWwub3JnAAoJEM4jHQowkoinBFQQAK9WdpcU8ODoDzoSls4jsCQpZUCfZ+ED
 pbCgQqUqu9VPs6bnJ+aXVa6Fh3uCr6+TIfNFM55qI/Sbo2issZ7bm0nvKmGgc6/m
 giqDP7btvHqiAsEootci8DVdbBXKkdH4dx3pSwleyN8pdinewH0hrKImaPpahyo6
 1mB1du0iI89yjsZmheHVVSyfXXYAnP0PqRVy5Y+qxY7yYlIegQ5uAZmwRE62lfTf
 TuiV7OFuDZ2DBYOmqIhfGKGRnfOL5ZVF3iHCrfUpX3p+fEFzDmwvm3vr73PTSrFw
 /aRRLa/hOWr5ilw1bvnMcazgQzFEOlQb3DMhBKH7gLl3XHVrM+TaaqYHjUia1+6Y
 e2axz/duA2q9uLMW81daRApvHMCgy0exkpC7prfOxF5bgTe4TjA7ZWvGpqG1kPKT
 PPSxw80XvG5hLZm4tB0ZWJ5rOfFpiUGGneSeRQwyuClBt73SIO+F03jyGpt83slU
 jFE50ac14Zwh1oxpCQtYoR1+bXWdq1QwM5vQBNEuaoTSnJfVjrXqBz/BnqJChtjr
 m1vA27+4/dfki2P3gVWF1lGx43ir3uJvqk+BjWXm2CDDJqpRi3N0qcUwZwLuqAAz
 /LEgFqK61bpHi/C8c2NWAxIoeWRU4NUOaoiKmZwyt0sKAWU1Yzg70xssYeg7VYqZ
 3pvFNVBqkV+F
 =sXUU
 -----END PGP SIGNATURE-----

Merge tag 'v6.5-rc1-sysctl-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux

Pull sysctl updates from Luis Chamberlain:
 "The changes for sysctl are in line with prior efforts to stop usage of
  deprecated routines which incur recursion and also make it hard to
  remove the empty array element in each sysctl array declaration.

  The most difficult user to modify was parport which required a bit of
  re-thinking of how to declare shared sysctls there, Joel Granados has
  stepped up to the plate to do most of this work and eventual removal
  of register_sysctl_table(). That work ended up saving us about 1465
  bytes according to bloat-o-meter. Since we gained a few bloat-o-meter
  karma points I moved two rather small sysctl arrays from
  kernel/sysctl.c leaving us only two more sysctl arrays to move left.

  Most changes have been tested on linux-next for about a month. The
  last straggler patches are a minor parport fix, changes to the sysctl
  kernel selftest so to verify correctness and prevent regressions for
  the future change he made to provide an alternative solution for the
  special sysctl mount point target which was using the now deprecated
  sysctl child element.

  This is all prep work to now finally be able to remove the empty array
  element in all sysctl declarations / registrations which is expected
  to save us a bit of bytes all over the kernel. That work will be
  tested early after v6.5-rc1 is out"

* tag 'v6.5-rc1-sysctl-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux:
  sysctl: replace child with an enumeration
  sysctl: Remove debugging dump_stack
  test_sysclt: Test for registering a mount point
  test_sysctl: Add an option to prevent test skip
  test_sysctl: Add an unregister sysctl test
  test_sysctl: Group node sysctl test under one func
  test_sysctl: Fix test metadata getters
  parport: plug a sysctl register leak
  sysctl: move security keys sysctl registration to its own file
  sysctl: move umh sysctl registration to its own file
  signal: move show_unhandled_signals sysctl to its own file
  sysctl: remove empty dev table
  sysctl: Remove register_sysctl_table
  sysctl: Refactor base paths registrations
  sysctl: stop exporting register_sysctl_table
  parport: Removed sysctl related defines
  parport: Remove register_sysctl_table from parport_default_proc_register
  parport: Remove register_sysctl_table from parport_device_proc_register
  parport: Remove register_sysctl_table from parport_proc_register
  parport: Move magic number "15" to a define
This commit is contained in:
Linus Torvalds 2023-06-28 16:05:21 -07:00
commit 6a8cbd9253
15 changed files with 355 additions and 438 deletions

View File

@ -32,6 +32,13 @@
#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ)
#define PARPORT_MIN_SPINTIME_VALUE 1
#define PARPORT_MAX_SPINTIME_VALUE 1000
/*
* PARPORT_BASE_* is the size of the known parts of the sysctl path
* in dev/partport/%s/devices/%s. "dev/parport/"(12), "/devices/"(9
* and null char(1).
*/
#define PARPORT_BASE_PATH_SIZE 13
#define PARPORT_BASE_DEVICES_PATH_SIZE 22
static int do_active_device(struct ctl_table *table, int write,
void *result, size_t *lenp, loff_t *ppos)
@ -236,13 +243,6 @@ do { \
return 0;
}
#define PARPORT_PORT_DIR(CHILD) { .procname = NULL, .mode = 0555, .child = CHILD }
#define PARPORT_PARPORT_DIR(CHILD) { .procname = "parport", \
.mode = 0555, .child = CHILD }
#define PARPORT_DEV_DIR(CHILD) { .procname = "dev", .mode = 0555, .child = CHILD }
#define PARPORT_DEVICES_ROOT_DIR { .procname = "devices", \
.mode = 0555, .child = NULL }
static const unsigned long parport_min_timeslice_value =
PARPORT_MIN_TIMESLICE_VALUE;
@ -257,17 +257,16 @@ PARPORT_MAX_SPINTIME_VALUE;
struct parport_sysctl_table {
struct ctl_table_header *sysctl_header;
struct ctl_table_header *port_header;
struct ctl_table_header *devices_header;
struct ctl_table vars[12];
struct ctl_table device_dir[2];
struct ctl_table port_dir[2];
struct ctl_table parport_dir[2];
struct ctl_table dev_dir[2];
};
static const struct parport_sysctl_table parport_sysctl_template = {
.sysctl_header = NULL,
{
.port_header = NULL,
.devices_header = NULL,
{
{
.procname = "spintime",
.data = NULL,
@ -305,7 +304,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.mode = 0444,
.proc_handler = do_hardware_modes
},
PARPORT_DEVICES_ROOT_DIR,
#ifdef CONFIG_PARPORT_1284
{
.procname = "autoprobe",
@ -355,18 +353,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
},
{}
},
{
PARPORT_PORT_DIR(NULL),
{}
},
{
PARPORT_PARPORT_DIR(NULL),
{}
},
{
PARPORT_DEV_DIR(NULL),
{}
}
};
struct parport_device_sysctl_table
@ -393,6 +379,7 @@ parport_device_sysctl_template = {
.extra1 = (void*) &parport_min_timeslice_value,
.extra2 = (void*) &parport_max_timeslice_value
},
{}
},
{
{
@ -400,25 +387,8 @@ parport_device_sysctl_template = {
.data = NULL,
.maxlen = 0,
.mode = 0555,
.child = NULL
},
{}
},
{
PARPORT_DEVICES_ROOT_DIR,
{}
},
{
PARPORT_PORT_DIR(NULL),
{}
},
{
PARPORT_PARPORT_DIR(NULL),
{}
},
{
PARPORT_DEV_DIR(NULL),
{}
}
};
@ -454,30 +424,15 @@ parport_default_sysctl_table = {
.extra2 = (void*) &parport_max_spintime_value
},
{}
},
{
{
.procname = "default",
.mode = 0555,
.child = parport_default_sysctl_table.vars
},
{}
},
{
PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
{}
},
{
PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
{}
}
};
int parport_proc_register(struct parport *port)
{
struct parport_sysctl_table *t;
int i;
char *tmp_dir_path;
size_t tmp_path_len, port_name_len;
int bytes_written, i, err = 0;
t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
@ -485,28 +440,64 @@ int parport_proc_register(struct parport *port)
t->device_dir[0].extra1 = port;
for (i = 0; i < 5; i++)
t->vars[i].extra1 = port;
t->vars[0].data = &port->spintime;
t->vars[5].child = t->device_dir;
for (i = 0; i < 5; i++)
t->vars[6 + i].extra2 = &port->probe_info[i];
t->port_dir[0].procname = port->name;
t->port_dir[0].child = t->vars;
t->parport_dir[0].child = t->port_dir;
t->dev_dir[0].child = t->parport_dir;
t->sysctl_header = register_sysctl_table(t->dev_dir);
if (t->sysctl_header == NULL) {
kfree(t);
t = NULL;
for (i = 0; i < 5; i++) {
t->vars[i].extra1 = port;
t->vars[5 + i].extra2 = &port->probe_info[i];
}
port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN);
/*
* Allocate a buffer for two paths: dev/parport/PORT and dev/parport/PORT/devices.
* We calculate for the second as that will give us enough for the first.
*/
tmp_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len;
tmp_dir_path = kzalloc(tmp_path_len, GFP_KERNEL);
if (!tmp_dir_path) {
err = -ENOMEM;
goto exit_free_t;
}
bytes_written = snprintf(tmp_dir_path, tmp_path_len,
"dev/parport/%s/devices", port->name);
if (tmp_path_len <= bytes_written) {
err = -ENOENT;
goto exit_free_tmp_dir_path;
}
t->devices_header = register_sysctl(tmp_dir_path, t->device_dir);
if (t->devices_header == NULL) {
err = -ENOENT;
goto exit_free_tmp_dir_path;
}
tmp_path_len = PARPORT_BASE_PATH_SIZE + port_name_len;
bytes_written = snprintf(tmp_dir_path, tmp_path_len,
"dev/parport/%s", port->name);
if (tmp_path_len <= bytes_written) {
err = -ENOENT;
goto unregister_devices_h;
}
t->port_header = register_sysctl(tmp_dir_path, t->vars);
if (t->port_header == NULL) {
err = -ENOENT;
goto unregister_devices_h;
}
port->sysctl_table = t;
kfree(tmp_dir_path);
return 0;
unregister_devices_h:
unregister_sysctl_table(t->devices_header);
exit_free_tmp_dir_path:
kfree(tmp_dir_path);
exit_free_t:
kfree(t);
return err;
}
int parport_proc_unregister(struct parport *port)
@ -514,7 +505,8 @@ int parport_proc_unregister(struct parport *port)
if (port->sysctl_table) {
struct parport_sysctl_table *t = port->sysctl_table;
port->sysctl_table = NULL;
unregister_sysctl_table(t->sysctl_header);
unregister_sysctl_table(t->devices_header);
unregister_sysctl_table(t->port_header);
kfree(t);
}
return 0;
@ -522,30 +514,53 @@ int parport_proc_unregister(struct parport *port)
int parport_device_proc_register(struct pardevice *device)
{
int bytes_written, err = 0;
struct parport_device_sysctl_table *t;
struct parport * port = device->port;
size_t port_name_len, device_name_len, tmp_dir_path_len;
char *tmp_dir_path;
t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
t->dev_dir[0].child = t->parport_dir;
t->parport_dir[0].child = t->port_dir;
t->port_dir[0].procname = port->name;
t->port_dir[0].child = t->devices_root_dir;
t->devices_root_dir[0].child = t->device_dir;
port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN);
device_name_len = strnlen(device->name, PATH_MAX);
/* Allocate a buffer for two paths: dev/parport/PORT/devices/DEVICE. */
tmp_dir_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len + device_name_len;
tmp_dir_path = kzalloc(tmp_dir_path_len, GFP_KERNEL);
if (!tmp_dir_path) {
err = -ENOMEM;
goto exit_free_t;
}
bytes_written = snprintf(tmp_dir_path, tmp_dir_path_len, "dev/parport/%s/devices/%s",
port->name, device->name);
if (tmp_dir_path_len <= bytes_written) {
err = -ENOENT;
goto exit_free_path;
}
t->device_dir[0].procname = device->name;
t->device_dir[0].child = t->vars;
t->vars[0].data = &device->timeslice;
t->sysctl_header = register_sysctl_table(t->dev_dir);
t->sysctl_header = register_sysctl(tmp_dir_path, t->vars);
if (t->sysctl_header == NULL) {
kfree(t);
t = NULL;
}
device->sysctl_table = t;
kfree(tmp_dir_path);
return 0;
exit_free_path:
kfree(tmp_dir_path);
exit_free_t:
kfree(t);
return err;
}
int parport_device_proc_unregister(struct pardevice *device)
@ -564,7 +579,7 @@ static int __init parport_default_proc_register(void)
int ret;
parport_default_sysctl_table.sysctl_header =
register_sysctl_table(parport_default_sysctl_table.dev_dir);
register_sysctl("dev/parport/default", parport_default_sysctl_table.vars);
if (!parport_default_sysctl_table.sysctl_header)
return -ENOMEM;
ret = parport_bus_init();

View File

@ -467,7 +467,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
atomic_set(&tmp->ref_count, 1);
INIT_LIST_HEAD(&tmp->full_list);
name = kmalloc(15, GFP_KERNEL);
name = kmalloc(PARPORT_NAME_MAX_LEN, GFP_KERNEL);
if (!name) {
kfree(tmp);
return NULL;

View File

@ -29,9 +29,8 @@ static const struct file_operations proc_sys_dir_file_operations;
static const struct inode_operations proc_sys_dir_operations;
/* Support for permanently empty directories */
struct ctl_table sysctl_mount_point[] = {
{ }
{.type = SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY }
};
/**
@ -48,21 +47,14 @@ struct ctl_table_header *register_sysctl_mount_point(const char *path)
}
EXPORT_SYMBOL(register_sysctl_mount_point);
static bool is_empty_dir(struct ctl_table_header *head)
{
return head->ctl_table[0].child == sysctl_mount_point;
}
static void set_empty_dir(struct ctl_dir *dir)
{
dir->header.ctl_table[0].child = sysctl_mount_point;
}
static void clear_empty_dir(struct ctl_dir *dir)
{
dir->header.ctl_table[0].child = NULL;
}
#define sysctl_is_perm_empty_ctl_table(tptr) \
(tptr[0].type == SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY)
#define sysctl_is_perm_empty_ctl_header(hptr) \
(sysctl_is_perm_empty_ctl_table(hptr->ctl_table))
#define sysctl_set_perm_empty_ctl_header(hptr) \
(hptr->ctl_table[0].type = SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY)
#define sysctl_clear_perm_empty_ctl_header(hptr) \
(hptr->ctl_table[0].type = SYSCTL_TABLE_TYPE_DEFAULT)
void proc_sys_poll_notify(struct ctl_table_poll *poll)
{
@ -230,20 +222,22 @@ static void erase_header(struct ctl_table_header *head)
static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
{
struct ctl_table *entry;
struct ctl_table_header *dir_h = &dir->header;
int err;
/* Is this a permanently empty directory? */
if (is_empty_dir(&dir->header))
if (sysctl_is_perm_empty_ctl_header(dir_h))
return -EROFS;
/* Am I creating a permanently empty directory? */
if (header->ctl_table == sysctl_mount_point) {
if (sysctl_is_perm_empty_ctl_table(header->ctl_table)) {
if (!RB_EMPTY_ROOT(&dir->root))
return -EINVAL;
set_empty_dir(dir);
sysctl_set_perm_empty_ctl_header(dir_h);
}
dir->header.nreg++;
dir_h->nreg++;
header->parent = dir;
err = insert_links(header);
if (err)
@ -259,9 +253,9 @@ fail:
put_links(header);
fail_links:
if (header->ctl_table == sysctl_mount_point)
clear_empty_dir(dir);
sysctl_clear_perm_empty_ctl_header(dir_h);
header->parent = NULL;
drop_sysctl_table(&dir->header);
drop_sysctl_table(dir_h);
return err;
}
@ -479,7 +473,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
inode->i_mode |= S_IFDIR;
inode->i_op = &proc_sys_dir_operations;
inode->i_fop = &proc_sys_dir_file_operations;
if (is_empty_dir(head))
if (sysctl_is_perm_empty_ctl_header(head))
make_empty_dir_inode(inode);
}
@ -1136,9 +1130,6 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
struct ctl_table *entry;
int err = 0;
list_for_each_table_entry(entry, table) {
if (entry->child)
err |= sysctl_err(path, entry, "Not a file");
if ((entry->proc_handler == proc_dostring) ||
(entry->proc_handler == proc_dobool) ||
(entry->proc_handler == proc_dointvec) ||
@ -1406,7 +1397,6 @@ fail_put_dir_locked:
spin_unlock(&sysctl_lock);
fail:
kfree(header);
dump_stack();
return NULL;
}
@ -1466,185 +1456,6 @@ void __init __register_sysctl_init(const char *path, struct ctl_table *table,
kmemleak_not_leak(hdr);
}
static char *append_path(const char *path, char *pos, const char *name)
{
int namelen;
namelen = strlen(name);
if (((pos - path) + namelen + 2) >= PATH_MAX)
return NULL;
memcpy(pos, name, namelen);
pos[namelen] = '/';
pos[namelen + 1] = '\0';
pos += namelen + 1;
return pos;
}
static int count_subheaders(struct ctl_table *table)
{
int has_files = 0;
int nr_subheaders = 0;
struct ctl_table *entry;
/* special case: no directory and empty directory */
if (!table || !table->procname)
return 1;
list_for_each_table_entry(entry, table) {
if (entry->child)
nr_subheaders += count_subheaders(entry->child);
else
has_files = 1;
}
return nr_subheaders + has_files;
}
static int register_leaf_sysctl_tables(const char *path, char *pos,
struct ctl_table_header ***subheader, struct ctl_table_set *set,
struct ctl_table *table)
{
struct ctl_table *ctl_table_arg = NULL;
struct ctl_table *entry, *files;
int nr_files = 0;
int nr_dirs = 0;
int err = -ENOMEM;
list_for_each_table_entry(entry, table) {
if (entry->child)
nr_dirs++;
else
nr_files++;
}
files = table;
/* If there are mixed files and directories we need a new table */
if (nr_dirs && nr_files) {
struct ctl_table *new;
files = kcalloc(nr_files + 1, sizeof(struct ctl_table),
GFP_KERNEL);
if (!files)
goto out;
ctl_table_arg = files;
new = files;
list_for_each_table_entry(entry, table) {
if (entry->child)
continue;
*new = *entry;
new++;
}
}
/* Register everything except a directory full of subdirectories */
if (nr_files || !nr_dirs) {
struct ctl_table_header *header;
header = __register_sysctl_table(set, path, files);
if (!header) {
kfree(ctl_table_arg);
goto out;
}
/* Remember if we need to free the file table */
header->ctl_table_arg = ctl_table_arg;
**subheader = header;
(*subheader)++;
}
/* Recurse into the subdirectories. */
list_for_each_table_entry(entry, table) {
char *child_pos;
if (!entry->child)
continue;
err = -ENAMETOOLONG;
child_pos = append_path(path, pos, entry->procname);
if (!child_pos)
goto out;
err = register_leaf_sysctl_tables(path, child_pos, subheader,
set, entry->child);
pos[0] = '\0';
if (err)
goto out;
}
err = 0;
out:
/* On failure our caller will unregister all registered subheaders */
return err;
}
/**
* register_sysctl_table - register a sysctl table hierarchy
* @table: the top-level table structure
*
* Register a sysctl table hierarchy. @table should be a filled in ctl_table
* array. A completely 0 filled entry terminates the table.
* We are slowly deprecating this call so avoid its use.
*/
struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
{
struct ctl_table *ctl_table_arg = table;
int nr_subheaders = count_subheaders(table);
struct ctl_table_header *header = NULL, **subheaders, **subheader;
char *new_path, *pos;
pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL);
if (!new_path)
return NULL;
pos[0] = '\0';
while (table->procname && table->child && !table[1].procname) {
pos = append_path(new_path, pos, table->procname);
if (!pos)
goto out;
table = table->child;
}
if (nr_subheaders == 1) {
header = __register_sysctl_table(&sysctl_table_root.default_set, new_path, table);
if (header)
header->ctl_table_arg = ctl_table_arg;
} else {
header = kzalloc(sizeof(*header) +
sizeof(*subheaders)*nr_subheaders, GFP_KERNEL);
if (!header)
goto out;
subheaders = (struct ctl_table_header **) (header + 1);
subheader = subheaders;
header->ctl_table_arg = ctl_table_arg;
if (register_leaf_sysctl_tables(new_path, pos, &subheader,
&sysctl_table_root.default_set, table))
goto err_register_leaves;
}
out:
kfree(new_path);
return header;
err_register_leaves:
while (subheader > subheaders) {
struct ctl_table_header *subh = *(--subheader);
struct ctl_table *table = subh->ctl_table_arg;
unregister_sysctl_table(subh);
kfree(table);
}
kfree(header);
header = NULL;
goto out;
}
EXPORT_SYMBOL(register_sysctl_table);
int __register_sysctl_base(struct ctl_table *base_table)
{
struct ctl_table_header *hdr;
hdr = register_sysctl_table(base_table);
kmemleak_not_leak(hdr);
return 0;
}
static void put_links(struct ctl_table_header *header)
{
struct ctl_table_set *root_set = &sysctl_table_root.default_set;
@ -1700,35 +1511,18 @@ static void drop_sysctl_table(struct ctl_table_header *header)
/**
* unregister_sysctl_table - unregister a sysctl table hierarchy
* @header: the header returned from register_sysctl_table
* @header: the header returned from register_sysctl or __register_sysctl_table
*
* Unregisters the sysctl table and all children. proc entries may not
* actually be removed until they are no longer used by anyone.
*/
void unregister_sysctl_table(struct ctl_table_header * header)
{
int nr_subheaders;
might_sleep();
if (header == NULL)
return;
nr_subheaders = count_subheaders(header->ctl_table_arg);
if (unlikely(nr_subheaders > 1)) {
struct ctl_table_header **subheaders;
int i;
subheaders = (struct ctl_table_header **)(header + 1);
for (i = nr_subheaders -1; i >= 0; i--) {
struct ctl_table_header *subh = subheaders[i];
struct ctl_table *table = subh->ctl_table_arg;
unregister_sysctl_table(subh);
kfree(table);
}
kfree(header);
return;
}
spin_lock(&sysctl_lock);
drop_sysctl_table(header);
spin_unlock(&sysctl_lock);

View File

@ -29,11 +29,10 @@ static struct ctl_table fs_shared_sysctls[] = {
{ }
};
DECLARE_SYSCTL_BASE(fs, fs_shared_sysctls);
static int __init init_fs_sysctls(void)
{
return register_sysctl_base(fs);
register_sysctl_init("fs", fs_shared_sysctls);
return 0;
}
early_initcall(init_fs_sysctls);

View File

@ -490,9 +490,6 @@ do { \
rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD)); \
} while (0)
#ifdef CONFIG_SYSCTL
extern struct ctl_table key_sysctls[];
#endif
/*
* the userspace interface
*/

View File

@ -180,6 +180,8 @@ struct ieee1284_info {
struct semaphore irq;
};
#define PARPORT_NAME_MAX_LEN 15
/* A parallel port */
struct parport {
unsigned long base; /* base address */

View File

@ -89,7 +89,7 @@ int proc_do_static_key(struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos);
/*
* Register a set of sysctl names by calling register_sysctl_table
* Register a set of sysctl names by calling register_sysctl
* with an initialised array of struct ctl_table's. An entry with
* NULL procname terminates the table. table->de will be
* set up by the registration and need not be initialised in advance.
@ -137,7 +137,17 @@ struct ctl_table {
void *data;
int maxlen;
umode_t mode;
struct ctl_table *child; /* Deprecated */
/**
* enum type - Enumeration to differentiate between ctl target types
* @SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations
* @SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY: Used to identify a permanently
* empty directory target to serve
* as mount point.
*/
enum {
SYSCTL_TABLE_TYPE_DEFAULT,
SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY
} type;
proc_handler *proc_handler; /* Callback for text formatting */
struct ctl_table_poll *poll;
void *extra1;
@ -197,20 +207,6 @@ struct ctl_path {
#ifdef CONFIG_SYSCTL
#define DECLARE_SYSCTL_BASE(_name, _table) \
static struct ctl_table _name##_base_table[] = { \
{ \
.procname = #_name, \
.mode = 0555, \
.child = _table, \
}, \
{ }, \
}
extern int __register_sysctl_base(struct ctl_table *base_table);
#define register_sysctl_base(_name) __register_sysctl_base(_name##_base_table)
void proc_sys_poll_notify(struct ctl_table_poll *poll);
extern void setup_sysctl_set(struct ctl_table_set *p,
@ -222,7 +218,6 @@ 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);
struct ctl_table_header *register_sysctl_table(struct ctl_table * table);
void unregister_sysctl_table(struct ctl_table_header * table);
extern int sysctl_init_bases(void);
@ -244,24 +239,10 @@ extern int unaligned_enabled;
extern int unaligned_dump_stack;
extern int no_unaligned_warning;
extern struct ctl_table sysctl_mount_point[];
#define SYSCTL_PERM_EMPTY_DIR (1 << 0)
#else /* CONFIG_SYSCTL */
#define DECLARE_SYSCTL_BASE(_name, _table)
static inline int __register_sysctl_base(struct ctl_table *base_table)
{
return 0;
}
#define register_sysctl_base(table) __register_sysctl_base(table)
static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
{
return NULL;
}
static inline void register_sysctl_init(const char *path, struct ctl_table *table)
{
}

View File

@ -42,8 +42,6 @@ call_usermodehelper_setup(const char *path, char **argv, char **envp,
extern int
call_usermodehelper_exec(struct subprocess_info *info, int wait);
extern struct ctl_table usermodehelper_table[];
enum umh_disable_depth {
UMH_ENABLED = 0,
UMH_FREEZING,

View File

@ -45,6 +45,7 @@
#include <linux/posix-timers.h>
#include <linux/cgroup.h>
#include <linux/audit.h>
#include <linux/sysctl.h>
#define CREATE_TRACE_POINTS
#include <trace/events/signal.h>
@ -4773,6 +4774,28 @@ static inline void siginfo_buildtime_checks(void)
#endif
}
#if defined(CONFIG_SYSCTL)
static struct ctl_table signal_debug_table[] = {
#ifdef CONFIG_SYSCTL_EXCEPTION_TRACE
{
.procname = "exception-trace",
.data = &show_unhandled_signals,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec
},
#endif
{ }
};
static int __init init_signal_sysctls(void)
{
register_sysctl_init("debug", signal_debug_table);
return 0;
}
early_initcall(init_signal_sysctls);
#endif /* CONFIG_SYSCTL */
void __init signals_init(void)
{
siginfo_buildtime_checks();

View File

@ -1782,11 +1782,6 @@ static struct ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = sysctl_max_threads,
},
{
.procname = "usermodehelper",
.mode = 0555,
.child = usermodehelper_table,
},
{
.procname = "overflowuid",
.data = &overflowuid,
@ -1962,13 +1957,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
#ifdef CONFIG_KEYS
{
.procname = "keys",
.mode = 0555,
.child = key_sysctls,
},
#endif
#ifdef CONFIG_PERF_EVENTS
/*
* User-space scripts rely on the existence of this file
@ -2264,34 +2252,10 @@ static struct ctl_table vm_table[] = {
{ }
};
static struct ctl_table debug_table[] = {
#ifdef CONFIG_SYSCTL_EXCEPTION_TRACE
{
.procname = "exception-trace",
.data = &show_unhandled_signals,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec
},
#endif
{ }
};
static struct ctl_table dev_table[] = {
{ }
};
DECLARE_SYSCTL_BASE(kernel, kern_table);
DECLARE_SYSCTL_BASE(vm, vm_table);
DECLARE_SYSCTL_BASE(debug, debug_table);
DECLARE_SYSCTL_BASE(dev, dev_table);
int __init sysctl_init_bases(void)
{
register_sysctl_base(kernel);
register_sysctl_base(vm);
register_sysctl_base(debug);
register_sysctl_base(dev);
register_sysctl_init("kernel", kern_table);
register_sysctl_init("vm", vm_table);
return 0;
}

View File

@ -544,7 +544,8 @@ static int proc_cap_handler(struct ctl_table *table, int write,
return 0;
}
struct ctl_table usermodehelper_table[] = {
#if defined(CONFIG_SYSCTL)
static struct ctl_table usermodehelper_table[] = {
{
.procname = "bset",
.data = &usermodehelper_bset,
@ -561,3 +562,11 @@ struct ctl_table usermodehelper_table[] = {
},
{ }
};
static int __init init_umh_sysctls(void)
{
register_sysctl_init("kernel/usermodehelper", usermodehelper_table);
return 0;
}
early_initcall(init_umh_sysctls);
#endif /* CONFIG_SYSCTL */

View File

@ -30,6 +30,13 @@ static int i_zero;
static int i_one_hundred = 100;
static int match_int_ok = 1;
static struct {
struct ctl_table_header *test_h_setup_node;
struct ctl_table_header *test_h_mnt;
struct ctl_table_header *test_h_mnterror;
} sysctl_test_headers;
struct test_sysctl_data {
int int_0001;
int int_0002;
@ -126,9 +133,7 @@ static struct ctl_table test_table[] = {
{ }
};
static struct ctl_table_header *test_sysctl_header;
static int __init test_sysctl_init(void)
static void test_sysctl_calc_match_int_ok(void)
{
int i;
@ -153,24 +158,96 @@ static int __init test_sysctl_init(void)
for (i = 0; i < ARRAY_SIZE(match_int); i++)
if (match_int[i].defined != match_int[i].wanted)
match_int_ok = 0;
}
static int test_sysctl_setup_node_tests(void)
{
test_sysctl_calc_match_int_ok();
test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
if (!test_data.bitmap_0001)
return -ENOMEM;
test_sysctl_header = register_sysctl("debug/test_sysctl", test_table);
if (!test_sysctl_header) {
sysctl_test_headers.test_h_setup_node = register_sysctl("debug/test_sysctl", test_table);
if (!sysctl_test_headers.test_h_setup_node) {
kfree(test_data.bitmap_0001);
return -ENOMEM;
}
return 0;
}
/* Used to test that unregister actually removes the directory */
static struct ctl_table test_table_unregister[] = {
{
.procname = "unregister_error",
.data = &test_data.int_0001,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
},
{}
};
static int test_sysctl_run_unregister_nested(void)
{
struct ctl_table_header *unregister;
unregister = register_sysctl("debug/test_sysctl/unregister_error",
test_table_unregister);
if (!unregister)
return -ENOMEM;
unregister_sysctl_table(unregister);
return 0;
}
static int test_sysctl_run_register_mount_point(void)
{
sysctl_test_headers.test_h_mnt
= register_sysctl_mount_point("debug/test_sysctl/mnt");
if (!sysctl_test_headers.test_h_mnt)
return -ENOMEM;
sysctl_test_headers.test_h_mnterror
= register_sysctl("debug/test_sysctl/mnt/mnt_error",
test_table_unregister);
/*
* Don't check the result.:
* If it fails (expected behavior), return 0.
* If successful (missbehavior of register mount point), we want to see
* mnt_error when we run the sysctl test script
*/
return 0;
}
static int __init test_sysctl_init(void)
{
int err;
err = test_sysctl_setup_node_tests();
if (err)
goto out;
err = test_sysctl_run_unregister_nested();
if (err)
goto out;
err = test_sysctl_run_register_mount_point();
out:
return err;
}
module_init(test_sysctl_init);
static void __exit test_sysctl_exit(void)
{
kfree(test_data.bitmap_0001);
if (test_sysctl_header)
unregister_sysctl_table(test_sysctl_header);
if (sysctl_test_headers.test_h_setup_node)
unregister_sysctl_table(sysctl_test_headers.test_h_setup_node);
if (sysctl_test_headers.test_h_mnt)
unregister_sysctl_table(sysctl_test_headers.test_h_mnt);
if (sysctl_test_headers.test_h_mnterror)
unregister_sysctl_table(sysctl_test_headers.test_h_mnterror);
}
module_exit(test_sysctl_exit);

View File

@ -146,16 +146,6 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ {
children[curtable][curentry] = child
}
/register_sysctl_table\(.*\)/ {
match($0, /register_sysctl_table\(([^)]+)\)/, tables)
if (debug) print "Registering table " tables[1]
if (children[tables[1]][table]) {
for (entry in entries[children[tables[1]][table]]) {
printentry(entry)
}
}
}
END {
for (entry in documented) {
if (!seen[entry]) {

View File

@ -68,3 +68,10 @@ struct ctl_table key_sysctls[] = {
#endif
{ }
};
static int __init init_security_keys_sysctls(void)
{
register_sysctl_init("kernel/keys", key_sysctls);
return 0;
}
early_initcall(init_security_keys_sysctls);

View File

@ -14,23 +14,27 @@ TEST_FILE=$(mktemp)
# This represents
#
# TEST_ID:TEST_COUNT:ENABLED:TARGET
# TEST_ID:TEST_COUNT:ENABLED:TARGET:SKIP_NO_TARGET
#
# TEST_ID: is the test id number
# TEST_COUNT: number of times we should run the test
# ENABLED: 1 if enabled, 0 otherwise
# TARGET: test target file required on the test_sysctl module
# SKIP_NO_TARGET: 1 skip if TARGET not there
# 0 run eventhough TARGET not there
#
# Once these are enabled please leave them as-is. Write your own test,
# we have tons of space.
ALL_TESTS="0001:1:1:int_0001"
ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001"
ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002"
ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001"
ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003"
ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001"
ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int"
ALL_TESTS="$ALL_TESTS 0008:1:1:match_int"
ALL_TESTS="0001:1:1:int_0001:1"
ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001:1"
ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002:1"
ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001:1"
ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003:1"
ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001:1"
ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int:1"
ALL_TESTS="$ALL_TESTS 0008:1:1:match_int:1"
ALL_TESTS="$ALL_TESTS 0009:1:1:unregister_error:0"
ALL_TESTS="$ALL_TESTS 0010:1:1:mnt/mnt_error:0"
function allow_user_defaults()
{
@ -613,7 +617,6 @@ target_exists()
TEST_ID="$2"
if [ ! -f ${TARGET} ] ; then
echo "Target for test $TEST_ID: $TARGET not exist, skipping test ..."
return 0
fi
return 1
@ -730,7 +733,7 @@ sysctl_test_0005()
sysctl_test_0006()
{
TARGET="${SYSCTL}/bitmap_0001"
TARGET="${SYSCTL}/$(get_test_target 0006)"
reset_vals
ORIG=""
run_bitmaptest
@ -738,7 +741,7 @@ sysctl_test_0006()
sysctl_test_0007()
{
TARGET="${SYSCTL}/boot_int"
TARGET="${SYSCTL}/$(get_test_target 0007)"
if [ ! -f $TARGET ]; then
echo "Skipping test for $TARGET as it is not present ..."
return $ksft_skip
@ -778,7 +781,7 @@ sysctl_test_0007()
sysctl_test_0008()
{
TARGET="${SYSCTL}/match_int"
TARGET="${SYSCTL}/$(get_test_target 0008)"
if [ ! -f $TARGET ]; then
echo "Skipping test for $TARGET as it is not present ..."
return $ksft_skip
@ -797,6 +800,34 @@ sysctl_test_0008()
return 0
}
sysctl_test_0009()
{
TARGET="${SYSCTL}/$(get_test_target 0009)"
echo -n "Testing if $TARGET unregistered correctly ..."
if [ -d $TARGET ]; then
echo "TEST FAILED"
rc=1
test_rc
fi
echo "ok"
return 0
}
sysctl_test_0010()
{
TARGET="${SYSCTL}/$(get_test_target 0010)"
echo -n "Testing that $TARGET was not created ..."
if [ -d $TARGET ]; then
echo "TEST FAILED"
rc=1
test_rc
fi
echo "ok"
return 0
}
list_tests()
{
echo "Test ID list:"
@ -813,6 +844,8 @@ list_tests()
echo "0006 x $(get_test_count 0006) - tests proc_do_large_bitmap()"
echo "0007 x $(get_test_count 0007) - tests setting sysctl from kernel boot param"
echo "0008 x $(get_test_count 0008) - tests sysctl macro values match"
echo "0009 x $(get_test_count 0009) - tests sysct unregister"
echo "0010 x $(get_test_count 0010) - tests sysct mount point"
}
usage()
@ -857,38 +890,65 @@ function test_num()
usage
fi
}
function remove_leading_zeros()
{
echo $1 | sed 's/^0*//'
}
function get_test_count()
{
test_num $1
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
awk_field=$(remove_leading_zeros $1)
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}')
echo ${TEST_DATA} | awk -F":" '{print $2}'
}
function get_test_enabled()
{
test_num $1
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
awk_field=$(remove_leading_zeros $1)
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}')
echo ${TEST_DATA} | awk -F":" '{print $3}'
}
function get_test_target()
{
test_num $1
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
awk_field=$(remove_leading_zeros $1)
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}')
echo ${TEST_DATA} | awk -F":" '{print $4}'
}
function get_test_skip_no_target()
{
test_num $1
awk_field=$(remove_leading_zeros $1)
TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$awk_field'}')
echo ${TEST_DATA} | awk -F":" '{print $5}'
}
function skip_test()
{
TEST_ID=$1
TEST_TARGET=$2
if target_exists $TEST_TARGET $TEST_ID; then
TEST_SKIP=$(get_test_skip_no_target $TEST_ID)
if [[ $TEST_SKIP -eq "1" ]]; then
echo "Target for test $TEST_ID: $TEST_TARGET not exist, skipping test ..."
return 0
fi
fi
return 1
}
function run_all_tests()
{
for i in $ALL_TESTS ; do
TEST_ID=${i%:*:*:*}
TEST_ID=${i%:*:*:*:*}
ENABLED=$(get_test_enabled $TEST_ID)
TEST_COUNT=$(get_test_count $TEST_ID)
TEST_TARGET=$(get_test_target $TEST_ID)
if target_exists $TEST_TARGET $TEST_ID; then
continue
fi
if [[ $ENABLED -eq "1" ]]; then
test_case $TEST_ID $TEST_COUNT $TEST_TARGET
fi
@ -923,18 +983,19 @@ function watch_case()
function test_case()
{
TEST_ID=$1
NUM_TESTS=$2
TARGET=$3
i=0
if target_exists $3 $1; then
continue
if skip_test $TEST_ID $TARGET; then
return
fi
i=0
while [ $i -lt $NUM_TESTS ]; do
test_num $1
watch_log $i ${TEST_NAME}_test_$1 noclear
RUN_TEST=${TEST_NAME}_test_$1
test_num $TEST_ID
watch_log $i ${TEST_NAME}_test_${TEST_ID} noclear
RUN_TEST=${TEST_NAME}_test_${TEST_ID}
$RUN_TEST
let i=$i+1
done