Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+39 -10
+37 -9
fs/proc/generic.c
··· 37 37 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) 38 38 39 39 static ssize_t 40 - proc_file_read(struct file *file, char __user *buf, size_t nbytes, 40 + __proc_file_read(struct file *file, char __user *buf, size_t nbytes, 41 41 loff_t *ppos) 42 42 { 43 43 struct inode * inode = file->f_path.dentry->d_inode; ··· 183 183 } 184 184 185 185 static ssize_t 186 + proc_file_read(struct file *file, char __user *buf, size_t nbytes, 187 + loff_t *ppos) 188 + { 189 + struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); 190 + ssize_t rv = -EIO; 191 + 192 + spin_lock(&pde->pde_unload_lock); 193 + if (!pde->proc_fops) { 194 + spin_unlock(&pde->pde_unload_lock); 195 + return rv; 196 + } 197 + pde->pde_users++; 198 + spin_unlock(&pde->pde_unload_lock); 199 + 200 + rv = __proc_file_read(file, buf, nbytes, ppos); 201 + 202 + pde_users_dec(pde); 203 + return rv; 204 + } 205 + 206 + static ssize_t 186 207 proc_file_write(struct file *file, const char __user *buffer, 187 208 size_t count, loff_t *ppos) 188 209 { 189 - struct inode *inode = file->f_path.dentry->d_inode; 190 - struct proc_dir_entry * dp; 191 - 192 - dp = PDE(inode); 210 + struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); 211 + ssize_t rv = -EIO; 193 212 194 - if (!dp->write_proc) 195 - return -EIO; 213 + if (pde->write_proc) { 214 + spin_lock(&pde->pde_unload_lock); 215 + if (!pde->proc_fops) { 216 + spin_unlock(&pde->pde_unload_lock); 217 + return rv; 218 + } 219 + pde->pde_users++; 220 + spin_unlock(&pde->pde_unload_lock); 196 221 197 - /* FIXME: does this routine need ppos? probably... */ 198 - return dp->write_proc(file, buffer, count, dp->data); 222 + /* FIXME: does this routine need ppos? probably... */ 223 + rv = pde->write_proc(file, buffer, count, pde->data); 224 + pde_users_dec(pde); 225 + } 226 + return rv; 199 227 } 200 228 201 229
+1 -1
fs/proc/inode.c
··· 127 127 complete(pde->pde_unload_completion); 128 128 } 129 129 130 - static void pde_users_dec(struct proc_dir_entry *pde) 130 + void pde_users_dec(struct proc_dir_entry *pde) 131 131 { 132 132 spin_lock(&pde->pde_unload_lock); 133 133 __pde_users_dec(pde);
+1
fs/proc/internal.h
··· 91 91 int (*release)(struct inode *, struct file *); 92 92 struct list_head lh; 93 93 }; 94 + void pde_users_dec(struct proc_dir_entry *pde);