forked from mirrors/linux
		
	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: Joel Granados <j.granados@samsung.com> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
This commit is contained in:
		
							parent
							
								
									94a6490518
								
							
						
					
					
						commit
						2f2665c13a
					
				
					 3 changed files with 30 additions and 66 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
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)
 | 
				
			||||||
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)
 | 
				
			||||||
	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,
 | 
				
			||||||
		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)
 | 
				
			||||||
	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,
 | 
				
			||||||
	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)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
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 {
 | 
				
			||||||
	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;
 | 
				
			||||||
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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue