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: Alexey Dobriyan <adobriyan@gmail.com>
This commit is contained in:
@@ -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,
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user