procfs: add proc_remove_subtree()
just what it sounds like; do that only to procfs subtrees you've created - doing that to something shared with another driver is not only antisocial, but might cause interesting races with proc_create() and its ilk. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
52f21999c7
commit
8ce584c741
2 changed files with 91 additions and 30 deletions
|
@ -755,37 +755,8 @@ void pde_put(struct proc_dir_entry *pde)
|
||||||
free_proc_entry(pde);
|
free_proc_entry(pde);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void entry_rundown(struct proc_dir_entry *de)
|
||||||
* Remove a /proc entry and free it if it's not currently in use.
|
|
||||||
*/
|
|
||||||
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
|
|
||||||
{
|
{
|
||||||
struct proc_dir_entry **p;
|
|
||||||
struct proc_dir_entry *de = NULL;
|
|
||||||
const char *fn = name;
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
spin_lock(&proc_subdir_lock);
|
|
||||||
if (__xlate_proc_name(name, &parent, &fn) != 0) {
|
|
||||||
spin_unlock(&proc_subdir_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
len = strlen(fn);
|
|
||||||
|
|
||||||
for (p = &parent->subdir; *p; p=&(*p)->next ) {
|
|
||||||
if (proc_match(len, fn, *p)) {
|
|
||||||
de = *p;
|
|
||||||
*p = de->next;
|
|
||||||
de->next = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock(&proc_subdir_lock);
|
|
||||||
if (!de) {
|
|
||||||
WARN(1, "name '%s'\n", name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&de->pde_unload_lock);
|
spin_lock(&de->pde_unload_lock);
|
||||||
/*
|
/*
|
||||||
* Stop accepting new callers into module. If you're
|
* Stop accepting new callers into module. If you're
|
||||||
|
@ -817,6 +788,40 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
|
||||||
spin_lock(&de->pde_unload_lock);
|
spin_lock(&de->pde_unload_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&de->pde_unload_lock);
|
spin_unlock(&de->pde_unload_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a /proc entry and free it if it's not currently in use.
|
||||||
|
*/
|
||||||
|
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry **p;
|
||||||
|
struct proc_dir_entry *de = NULL;
|
||||||
|
const char *fn = name;
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
spin_lock(&proc_subdir_lock);
|
||||||
|
if (__xlate_proc_name(name, &parent, &fn) != 0) {
|
||||||
|
spin_unlock(&proc_subdir_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
len = strlen(fn);
|
||||||
|
|
||||||
|
for (p = &parent->subdir; *p; p=&(*p)->next ) {
|
||||||
|
if (proc_match(len, fn, *p)) {
|
||||||
|
de = *p;
|
||||||
|
*p = de->next;
|
||||||
|
de->next = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&proc_subdir_lock);
|
||||||
|
if (!de) {
|
||||||
|
WARN(1, "name '%s'\n", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_rundown(de);
|
||||||
|
|
||||||
if (S_ISDIR(de->mode))
|
if (S_ISDIR(de->mode))
|
||||||
parent->nlink--;
|
parent->nlink--;
|
||||||
|
@ -827,3 +832,57 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
|
||||||
pde_put(de);
|
pde_put(de);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(remove_proc_entry);
|
EXPORT_SYMBOL(remove_proc_entry);
|
||||||
|
|
||||||
|
int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry **p;
|
||||||
|
struct proc_dir_entry *root = NULL, *de, *next;
|
||||||
|
const char *fn = name;
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
spin_lock(&proc_subdir_lock);
|
||||||
|
if (__xlate_proc_name(name, &parent, &fn) != 0) {
|
||||||
|
spin_unlock(&proc_subdir_lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
len = strlen(fn);
|
||||||
|
|
||||||
|
for (p = &parent->subdir; *p; p=&(*p)->next ) {
|
||||||
|
if (proc_match(len, fn, *p)) {
|
||||||
|
root = *p;
|
||||||
|
*p = root->next;
|
||||||
|
root->next = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!root) {
|
||||||
|
spin_unlock(&proc_subdir_lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
de = root;
|
||||||
|
while (1) {
|
||||||
|
next = de->subdir;
|
||||||
|
if (next) {
|
||||||
|
de->subdir = next->next;
|
||||||
|
next->next = NULL;
|
||||||
|
de = next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
spin_unlock(&proc_subdir_lock);
|
||||||
|
|
||||||
|
entry_rundown(de);
|
||||||
|
next = de->parent;
|
||||||
|
if (S_ISDIR(de->mode))
|
||||||
|
next->nlink--;
|
||||||
|
de->nlink = 0;
|
||||||
|
if (de == root)
|
||||||
|
break;
|
||||||
|
pde_put(de);
|
||||||
|
|
||||||
|
spin_lock(&proc_subdir_lock);
|
||||||
|
de = next;
|
||||||
|
}
|
||||||
|
pde_put(root);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(remove_proc_subtree);
|
||||||
|
|
|
@ -117,6 +117,7 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
|
||||||
const struct file_operations *proc_fops,
|
const struct file_operations *proc_fops,
|
||||||
void *data);
|
void *data);
|
||||||
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
|
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
|
||||||
|
extern int remove_proc_subtree(const char *name, struct proc_dir_entry *parent);
|
||||||
|
|
||||||
struct pid_namespace;
|
struct pid_namespace;
|
||||||
|
|
||||||
|
@ -202,6 +203,7 @@ static inline struct proc_dir_entry *proc_create_data(const char *name,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#define remove_proc_entry(name, parent) do {} while (0)
|
#define remove_proc_entry(name, parent) do {} while (0)
|
||||||
|
#define remove_proc_subtree(name, parent) do {} while (0)
|
||||||
|
|
||||||
static inline struct proc_dir_entry *proc_symlink(const char *name,
|
static inline struct proc_dir_entry *proc_symlink(const char *name,
|
||||||
struct proc_dir_entry *parent,const char *dest) {return NULL;}
|
struct proc_dir_entry *parent,const char *dest) {return NULL;}
|
||||||
|
|
Loading…
Add table
Reference in a new issue