Commit 3dec7f59 authored by Alexey Dobriyan's avatar Alexey Dobriyan

proc 1/2: do PDE usecounting even for ->read_proc, ->write_proc

struct proc_dir_entry::owner is going to be removed. Now it's only necessary
to protect PDEs which are using ->read_proc, ->write_proc hooks.

However, ->owner assignments are racy and make it very easy for someone to switch
->owner on live PDE (as some subsystems do) without fixing refcounts and so on.

http://bugzilla.kernel.org/show_bug.cgi?id=12454

So, ->owner is on death row.

Proxy file operations exist already (proc_file_operations), just bump usecount
when necessary.
Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
parent 09729a99
...@@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de) ...@@ -37,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
static ssize_t static ssize_t
proc_file_read(struct file *file, char __user *buf, size_t nbytes, __proc_file_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos) loff_t *ppos)
{ {
struct inode * inode = file->f_path.dentry->d_inode; struct inode * inode = file->f_path.dentry->d_inode;
...@@ -182,20 +182,48 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes, ...@@ -182,20 +182,48 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
return retval; return retval;
} }
static ssize_t
proc_file_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
ssize_t rv = -EIO;
spin_lock(&pde->pde_unload_lock);
if (!pde->proc_fops) {
spin_unlock(&pde->pde_unload_lock);
return rv;
}
pde->pde_users++;
spin_unlock(&pde->pde_unload_lock);
rv = __proc_file_read(file, buf, nbytes, ppos);
pde_users_dec(pde);
return rv;
}
static ssize_t static ssize_t
proc_file_write(struct file *file, const char __user *buffer, proc_file_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct proc_dir_entry * dp; ssize_t rv = -EIO;
dp = PDE(inode); if (pde->write_proc) {
spin_lock(&pde->pde_unload_lock);
if (!dp->write_proc) if (!pde->proc_fops) {
return -EIO; spin_unlock(&pde->pde_unload_lock);
return rv;
}
pde->pde_users++;
spin_unlock(&pde->pde_unload_lock);
/* FIXME: does this routine need ppos? probably... */ /* FIXME: does this routine need ppos? probably... */
return dp->write_proc(file, buffer, count, dp->data); rv = pde->write_proc(file, buffer, count, pde->data);
pde_users_dec(pde);
}
return rv;
} }
......
...@@ -127,7 +127,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde) ...@@ -127,7 +127,7 @@ static void __pde_users_dec(struct proc_dir_entry *pde)
complete(pde->pde_unload_completion); complete(pde->pde_unload_completion);
} }
static void pde_users_dec(struct proc_dir_entry *pde) void pde_users_dec(struct proc_dir_entry *pde)
{ {
spin_lock(&pde->pde_unload_lock); spin_lock(&pde->pde_unload_lock);
__pde_users_dec(pde); __pde_users_dec(pde);
......
...@@ -91,3 +91,4 @@ struct pde_opener { ...@@ -91,3 +91,4 @@ struct pde_opener {
int (*release)(struct inode *, struct file *); int (*release)(struct inode *, struct file *);
struct list_head lh; struct list_head lh;
}; };
void pde_users_dec(struct proc_dir_entry *pde);
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