Commit 2f2665c1 authored by Joel Granados's avatar Joel Granados Committed by Luis Chamberlain

sysctl: replace child with an enumeration

This is part of the effort to remove the empty element at the end of
ctl_table structs. "child" was a deprecated elem in this struct and was
being used to differentiate between two types of ctl_tables: "normal"
and "permanently emtpy".

What changed?:
* Replace "child" with an enumeration that will have two values: the
  default (0) and the permanently empty (1). The latter is left at zero
  so when struct ctl_table is created with kzalloc or in a local
  context, it will have the zero value by default. We document the
  new enum with kdoc.
* Remove the "empty child" check from sysctl_check_table
* Remove count_subheaders function as there is no longer a need to
  calculate how many headers there are for every child
* Remove the recursive call to unregister_sysctl_table as there is no
  need to traverse down the child tree any longer
* Add a new SYSCTL_PERM_EMPTY_DIR binary flag
* Remove the last remanence of child from partport/procfs.c
Signed-off-by: default avatarJoel Granados <j.granados@samsung.com>
Signed-off-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
parent 94a64905
...@@ -387,7 +387,6 @@ parport_device_sysctl_template = { ...@@ -387,7 +387,6 @@ parport_device_sysctl_template = {
.data = NULL, .data = NULL,
.maxlen = 0, .maxlen = 0,
.mode = 0555, .mode = 0555,
.child = NULL
}, },
{} {}
} }
......
...@@ -29,9 +29,8 @@ static const struct file_operations proc_sys_dir_file_operations; ...@@ -29,9 +29,8 @@ static const struct file_operations proc_sys_dir_file_operations;
static const struct inode_operations proc_sys_dir_operations; static const struct inode_operations proc_sys_dir_operations;
/* Support for permanently empty directories */ /* Support for permanently empty directories */
struct ctl_table sysctl_mount_point[] = { 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) ...@@ -48,21 +47,14 @@ struct ctl_table_header *register_sysctl_mount_point(const char *path)
} }
EXPORT_SYMBOL(register_sysctl_mount_point); EXPORT_SYMBOL(register_sysctl_mount_point);
static bool is_empty_dir(struct ctl_table_header *head) #define sysctl_is_perm_empty_ctl_table(tptr) \
{ (tptr[0].type == SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY)
return head->ctl_table[0].child == sysctl_mount_point; #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) \
static void set_empty_dir(struct ctl_dir *dir) (hptr->ctl_table[0].type = SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY)
{ #define sysctl_clear_perm_empty_ctl_header(hptr) \
dir->header.ctl_table[0].child = sysctl_mount_point; (hptr->ctl_table[0].type = SYSCTL_TABLE_TYPE_DEFAULT)
}
static void clear_empty_dir(struct ctl_dir *dir)
{
dir->header.ctl_table[0].child = NULL;
}
void proc_sys_poll_notify(struct ctl_table_poll *poll) void proc_sys_poll_notify(struct ctl_table_poll *poll)
{ {
...@@ -230,20 +222,22 @@ static void erase_header(struct ctl_table_header *head) ...@@ -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) static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
{ {
struct ctl_table *entry; struct ctl_table *entry;
struct ctl_table_header *dir_h = &dir->header;
int err; int err;
/* Is this a permanently empty directory? */ /* Is this a permanently empty directory? */
if (is_empty_dir(&dir->header)) if (sysctl_is_perm_empty_ctl_header(dir_h))
return -EROFS; return -EROFS;
/* Am I creating a permanently empty directory? */ /* 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)) if (!RB_EMPTY_ROOT(&dir->root))
return -EINVAL; return -EINVAL;
set_empty_dir(dir); sysctl_set_perm_empty_ctl_header(dir_h);
} }
dir->header.nreg++; dir_h->nreg++;
header->parent = dir; header->parent = dir;
err = insert_links(header); err = insert_links(header);
if (err) if (err)
...@@ -259,9 +253,9 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) ...@@ -259,9 +253,9 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
put_links(header); put_links(header);
fail_links: fail_links:
if (header->ctl_table == sysctl_mount_point) if (header->ctl_table == sysctl_mount_point)
clear_empty_dir(dir); sysctl_clear_perm_empty_ctl_header(dir_h);
header->parent = NULL; header->parent = NULL;
drop_sysctl_table(&dir->header); drop_sysctl_table(dir_h);
return err; return err;
} }
...@@ -479,7 +473,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, ...@@ -479,7 +473,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
inode->i_op = &proc_sys_dir_operations; inode->i_op = &proc_sys_dir_operations;
inode->i_fop = &proc_sys_dir_file_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); make_empty_dir_inode(inode);
} }
...@@ -1136,9 +1130,6 @@ static int sysctl_check_table(const char *path, struct ctl_table *table) ...@@ -1136,9 +1130,6 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
struct ctl_table *entry; struct ctl_table *entry;
int err = 0; int err = 0;
list_for_each_table_entry(entry, table) { list_for_each_table_entry(entry, table) {
if (entry->child)
err |= sysctl_err(path, entry, "Not a file");
if ((entry->proc_handler == proc_dostring) || if ((entry->proc_handler == proc_dostring) ||
(entry->proc_handler == proc_dobool) || (entry->proc_handler == proc_dobool) ||
(entry->proc_handler == proc_dointvec) || (entry->proc_handler == proc_dointvec) ||
...@@ -1465,25 +1456,6 @@ void __init __register_sysctl_init(const char *path, struct ctl_table *table, ...@@ -1465,25 +1456,6 @@ void __init __register_sysctl_init(const char *path, struct ctl_table *table,
kmemleak_not_leak(hdr); kmemleak_not_leak(hdr);
} }
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 void put_links(struct ctl_table_header *header) static void put_links(struct ctl_table_header *header)
{ {
struct ctl_table_set *root_set = &sysctl_table_root.default_set; struct ctl_table_set *root_set = &sysctl_table_root.default_set;
...@@ -1546,28 +1518,11 @@ static void drop_sysctl_table(struct ctl_table_header *header) ...@@ -1546,28 +1518,11 @@ static void drop_sysctl_table(struct ctl_table_header *header)
*/ */
void unregister_sysctl_table(struct ctl_table_header * header) void unregister_sysctl_table(struct ctl_table_header * header)
{ {
int nr_subheaders;
might_sleep(); might_sleep();
if (header == NULL) if (header == NULL)
return; 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); spin_lock(&sysctl_lock);
drop_sysctl_table(header); drop_sysctl_table(header);
spin_unlock(&sysctl_lock); spin_unlock(&sysctl_lock);
......
...@@ -137,7 +137,17 @@ struct ctl_table { ...@@ -137,7 +137,17 @@ struct ctl_table {
void *data; void *data;
int maxlen; int maxlen;
umode_t mode; 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 */ proc_handler *proc_handler; /* Callback for text formatting */
struct ctl_table_poll *poll; struct ctl_table_poll *poll;
void *extra1; void *extra1;
...@@ -229,7 +239,7 @@ extern int unaligned_enabled; ...@@ -229,7 +239,7 @@ extern int unaligned_enabled;
extern int unaligned_dump_stack; extern int unaligned_dump_stack;
extern int no_unaligned_warning; extern int no_unaligned_warning;
extern struct ctl_table sysctl_mount_point[]; #define SYSCTL_PERM_EMPTY_DIR (1 << 0)
#else /* CONFIG_SYSCTL */ #else /* CONFIG_SYSCTL */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment