dgrp procfs fixes, part 4: get rid of sysctl-like machinery

racy and very overblown...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2013-03-30 00:36:23 -04:00
Родитель 772317b53b
Коммит 08f3d07ddd
2 изменённых файлов: 42 добавлений и 270 удалений

Просмотреть файл

@ -76,61 +76,6 @@ extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c);
extern void dgrp_remove_tty_sysfs(struct device *c); extern void dgrp_remove_tty_sysfs(struct device *c);
/* from dgrp_specproc.c */ /* from dgrp_specproc.c */
/*
* The list of DGRP entries with r/w capabilities. These
* magic numbers are used for identification purposes.
*/
enum {
DGRP_CONFIG = 1, /* Configure portservers */
DGRP_NETDIR = 2, /* Directory for "net" devices */
DGRP_MONDIR = 3, /* Directory for "mon" devices */
DGRP_PORTSDIR = 4, /* Directory for "ports" devices */
DGRP_INFO = 5, /* Get info. about the running module */
DGRP_NODEINFO = 6, /* Get info. about the configured nodes */
DGRP_DPADIR = 7, /* Directory for the "dpa" devices */
};
/*
* Directions for proc handlers
*/
enum {
INBOUND = 1, /* Data being written to kernel */
OUTBOUND = 2, /* Data being read from the kernel */
};
/**
* dgrp_proc_entry: structure for dgrp proc dirs
* @id: ID number associated with this particular entry. Should be
* unique across all of DGRP.
* @name: text name associated with the /proc entry
* @mode: file access permisssions for the /proc entry
* @child: pointer to table describing a subdirectory for this entry
* @de: pointer to directory entry for this object once registered. Used
* to grab the handle of the object for unregistration
* @excl_sem: semaphore to provide exclusive to struct
* @excl_cnt: counter of current accesses
*
* Each entry in a DGRP proc directory is described with a
* dgrp_proc_entry structure. A collection of these
* entries (in an array) represents the members associated
* with a particular /proc directory, and is referred to
* as a table. All tables are terminated by an entry with
* zeros for every member.
*/
struct dgrp_proc_entry {
int id; /* Integer identifier */
const char *name; /* ASCII identifier */
umode_t mode; /* File access permissions */
struct dgrp_proc_entry *child; /* Child pointer */
/* file ops to use, pass NULL to use default */
struct file_operations *proc_file_ops;
struct proc_dir_entry *de; /* proc entry pointer */
struct semaphore excl_sem; /* Protects exclusive access var */
int excl_cnt; /* Counts number of curr accesses */
};
extern void dgrp_unregister_proc(void); extern void dgrp_unregister_proc(void);
extern void dgrp_register_proc(void); extern void dgrp_register_proc(void);

Просмотреть файл

@ -44,7 +44,6 @@
#include "dgrp_common.h" #include "dgrp_common.h"
static struct dgrp_proc_entry dgrp_table[];
static struct proc_dir_entry *dgrp_proc_dir_entry; static struct proc_dir_entry *dgrp_proc_dir_entry;
static int dgrp_add_id(long id); static int dgrp_add_id(long id);
@ -63,16 +62,6 @@ static struct inode_operations proc_inode_ops = {
}; };
static void register_proc_table(struct dgrp_proc_entry *,
struct proc_dir_entry *);
static void unregister_proc_table(struct dgrp_proc_entry *,
struct proc_dir_entry *);
static struct dgrp_proc_entry dgrp_net_table[];
static struct dgrp_proc_entry dgrp_mon_table[];
static struct dgrp_proc_entry dgrp_ports_table[];
static struct dgrp_proc_entry dgrp_dpa_table[];
static ssize_t dgrp_config_proc_write(struct file *file, static ssize_t dgrp_config_proc_write(struct file *file,
const char __user *buffer, const char __user *buffer,
size_t count, loff_t *pos); size_t count, loff_t *pos);
@ -106,72 +95,11 @@ static struct file_operations nodeinfo_proc_file_ops = {
.release = seq_release, .release = seq_release,
}; };
static struct dgrp_proc_entry dgrp_table[] = {
{
.id = DGRP_CONFIG,
.name = "config",
.mode = 0644,
.proc_file_ops = &config_proc_file_ops,
},
{
.id = DGRP_INFO,
.name = "info",
.mode = 0644,
.proc_file_ops = &info_proc_file_ops,
},
{
.id = DGRP_NODEINFO,
.name = "nodeinfo",
.mode = 0644,
.proc_file_ops = &nodeinfo_proc_file_ops,
},
{
.id = DGRP_NETDIR,
.name = "net",
.mode = 0500,
.child = dgrp_net_table
},
{
.id = DGRP_MONDIR,
.name = "mon",
.mode = 0500,
.child = dgrp_mon_table
},
{
.id = DGRP_PORTSDIR,
.name = "ports",
.mode = 0500,
.child = dgrp_ports_table
},
{
.id = DGRP_DPADIR,
.name = "dpa",
.mode = 0500,
.child = dgrp_dpa_table
}
};
static struct proc_dir_entry *net_entry_pointer; static struct proc_dir_entry *net_entry_pointer;
static struct proc_dir_entry *mon_entry_pointer; static struct proc_dir_entry *mon_entry_pointer;
static struct proc_dir_entry *dpa_entry_pointer; static struct proc_dir_entry *dpa_entry_pointer;
static struct proc_dir_entry *ports_entry_pointer; static struct proc_dir_entry *ports_entry_pointer;
static struct dgrp_proc_entry dgrp_net_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_mon_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_ports_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_dpa_table[] = {
{0}
};
void dgrp_unregister_proc(void) void dgrp_unregister_proc(void)
{ {
net_entry_pointer = NULL; net_entry_pointer = NULL;
@ -180,163 +108,62 @@ void dgrp_unregister_proc(void)
ports_entry_pointer = NULL; ports_entry_pointer = NULL;
if (dgrp_proc_dir_entry) { if (dgrp_proc_dir_entry) {
unregister_proc_table(dgrp_table, dgrp_proc_dir_entry); struct nd_struct *nd;
remove_proc_entry(dgrp_proc_dir_entry->name, list_for_each_entry(nd, &nd_struct_list, list) {
dgrp_proc_dir_entry->parent); if (nd->nd_net_de) {
unregister_dgrp_device(nd->nd_net_de);
dgrp_remove_node_class_sysfs_files(nd);
}
if (nd->nd_mon_de)
unregister_dgrp_device(nd->nd_mon_de);
if (nd->nd_dpa_de)
unregister_dgrp_device(nd->nd_dpa_de);
if (nd->nd_ports_de)
unregister_dgrp_device(nd->nd_ports_de);
}
remove_proc_entry("dgrp/config", NULL);
remove_proc_entry("dgrp/info", NULL);
remove_proc_entry("dgrp/nodeinfo", NULL);
remove_proc_entry("dgrp/net", NULL);
remove_proc_entry("dgrp/mon", NULL);
remove_proc_entry("dgrp/dpa", NULL);
remove_proc_entry("dgrp/ports", NULL);
remove_proc_entry("dgrp", NULL);
dgrp_proc_dir_entry = NULL; dgrp_proc_dir_entry = NULL;
} }
} }
void dgrp_register_proc(void) void dgrp_register_proc(void)
{ {
struct proc_dir_entry *de;
/* /*
* Register /proc/dgrp * Register /proc/dgrp
*/ */
dgrp_proc_dir_entry = proc_mkdir("dgrp", NULL); dgrp_proc_dir_entry = proc_mkdir("dgrp", NULL);
register_proc_table(dgrp_table, dgrp_proc_dir_entry); if (!dgrp_proc_dir_entry)
}
/*
* /proc/sys support
*/
static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
{
if (!de || !de->low_ino)
return 0;
if (de->namelen != len)
return 0;
return !memcmp(name, de->name, len);
}
/*
* Scan the entries in table and add them all to /proc at the position
* referred to by "root"
*/
static void register_proc_table(struct dgrp_proc_entry *table,
struct proc_dir_entry *root)
{
struct proc_dir_entry *de;
int len;
umode_t mode;
if (table == NULL)
return; return;
if (root == NULL) de = create_proc_entry("dgrp/config", 0644, NULL);
return; if (de) {
de->proc_fops = &config_proc_file_ops;
for (; table->id; table++) { de->proc_iops = &proc_inode_ops;
/* Can't do anything without a proc name. */
if (!table->name)
continue;
/* Maybe we can't do anything with it... */
if (!table->proc_file_ops &&
!table->child) {
pr_warn("dgrp: Can't register %s\n",
table->name);
continue;
}
len = strlen(table->name);
mode = table->mode;
de = NULL;
if (!table->child)
mode |= S_IFREG;
else {
mode |= S_IFDIR;
for (de = root->subdir; de; de = de->next) {
if (dgrp_proc_match(len, table->name, de))
break;
}
/* If the subdir exists already, de is non-NULL */
}
if (!de) {
de = create_proc_entry(table->name, mode, root);
if (!de)
continue;
de->data = (void *) table;
if (!table->child) {
de->proc_iops = &proc_inode_ops;
de->proc_fops = table->proc_file_ops;
}
}
table->de = de;
if (de->mode & S_IFDIR)
register_proc_table(table->child, de);
if (table->id == DGRP_NETDIR)
net_entry_pointer = de;
if (table->id == DGRP_MONDIR)
mon_entry_pointer = de;
if (table->id == DGRP_DPADIR)
dpa_entry_pointer = de;
if (table->id == DGRP_PORTSDIR)
ports_entry_pointer = de;
} }
} de = create_proc_entry("dgrp/info", 0644, NULL);
if (de) {
/* de->proc_fops = &info_proc_file_ops;
* Unregister a /proc sysctl table and any subdirectories. de->proc_iops = &proc_inode_ops;
*/
static void unregister_proc_table(struct dgrp_proc_entry *table,
struct proc_dir_entry *root)
{
struct proc_dir_entry *de;
struct nd_struct *tmp;
if (table == NULL)
return;
list_for_each_entry(tmp, &nd_struct_list, list) {
if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
unregister_dgrp_device(tmp->nd_net_de);
dgrp_remove_node_class_sysfs_files(tmp);
}
if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
unregister_dgrp_device(tmp->nd_mon_de);
if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
unregister_dgrp_device(tmp->nd_dpa_de);
if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
unregister_dgrp_device(tmp->nd_ports_de);
} }
de = create_proc_entry("dgrp/nodeinfo", 0644, NULL);
for (; table->id; table++) { if (de) {
de = table->de; de->proc_fops = &nodeinfo_proc_file_ops;
de->proc_iops = &proc_inode_ops;
if (!de)
continue;
if (de->mode & S_IFDIR) {
if (!table->child) {
pr_alert("dgrp: malformed sysctl tree on free\n");
continue;
}
unregister_proc_table(table->child, de);
/* Don't unregister directories which still have entries */
if (de->subdir)
continue;
}
/* Don't unregister proc entries that are still being used.. */
if ((atomic_read(&de->count)) != 1) {
pr_alert("proc entry %s in use, not removing\n",
de->name);
continue;
}
remove_proc_entry(de->name, de->parent);
table->de = NULL;
} }
net_entry_pointer = proc_mkdir_mode("dgrp/net", 0500, NULL);
mon_entry_pointer = proc_mkdir_mode("dgrp/mon", 0500, NULL);
dpa_entry_pointer = proc_mkdir_mode("dgrp/dpa", 0500, NULL);
ports_entry_pointer = proc_mkdir_mode("dgrp/ports", 0500, NULL);
} }
static void *dgrp_config_proc_start(struct seq_file *m, loff_t *pos) static void *dgrp_config_proc_start(struct seq_file *m, loff_t *pos)