proc 1/2: do PDE usecounting even for ->read_proc, ->write_proc
[safe/jmp/linux-2.6] / fs / proc / generic.c
index bca0f81..fa678ab 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/stat.h>
 #include <linux/module.h>
 #include <linux/mount.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/idr.h>
 #include <linux/namei.h>
@@ -38,7 +37,7 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
 #define PROC_BLOCK_SIZE        (PAGE_SIZE - 1024)
 
 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)
 {
        struct inode * inode = file->f_path.dentry->d_inode;
@@ -184,19 +183,47 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
 }
 
 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
 proc_file_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *ppos)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct proc_dir_entry * dp;
-       
-       dp = PDE(inode);
-
-       if (!dp->write_proc)
-               return -EIO;
+       struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+       ssize_t rv = -EIO;
+
+       if (pde->write_proc) {
+               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);
 
-       /* FIXME: does this routine need ppos?  probably... */
-       return dp->write_proc(file, buffer, count, dp->data);
+               /* FIXME: does this routine need ppos?  probably... */
+               rv = pde->write_proc(file, buffer, count, pde->data);
+               pde_users_dec(pde);
+       }
+       return rv;
 }
 
 
@@ -308,6 +335,21 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
 /*
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
+ *
+ * Current inode allocations in the proc-fs (hex-numbers):
+ *
+ * 00000000            reserved
+ * 00000001-00000fff   static entries  (goners)
+ *      001            root-ino
+ *
+ * 00001000-00001fff   unused
+ * 0001xxxx-7fffxxxx   pid-dir entries for pid 1-7fff
+ * 80000000-efffffff   unused
+ * f0000000-ffffffff   dynamic entries
+ *
+ * Goal:
+ *     Once we split the thing into several virtual filesystems,
+ *     we will get rid of magical ranges (and this comment, BTW).
  */
 static unsigned int get_inode_number(void)
 {
@@ -364,7 +406,7 @@ static int proc_delete_dentry(struct dentry * dentry)
        return 1;
 }
 
-static struct dentry_operations proc_dentry_operations =
+static const struct dentry_operations proc_dentry_operations =
 {
        .d_delete       = proc_delete_dentry,
 };
@@ -379,7 +421,6 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
        struct inode *inode = NULL;
        int error = -ENOENT;
 
-       lock_kernel();
        spin_lock(&proc_subdir_lock);
        for (de = de->subdir; de ; de = de->next) {
                if (de->namelen != dentry->d_name.len)
@@ -397,7 +438,6 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
        }
        spin_unlock(&proc_subdir_lock);
 out_unlock:
-       unlock_kernel();
 
        if (inode) {
                dentry->d_op = &proc_dentry_operations;
@@ -432,8 +472,6 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
        struct inode *inode = filp->f_path.dentry->d_inode;
        int ret = 0;
 
-       lock_kernel();
-
        ino = inode->i_ino;
        i = filp->f_pos;
        switch (i) {
@@ -487,7 +525,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
                        spin_unlock(&proc_subdir_lock);
        }
        ret = 1;
-out:   unlock_kernel();
+out:
        return ret;     
 }
 
@@ -504,6 +542,7 @@ int proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
  * the /proc directory.
  */
 static const struct file_operations proc_dir_operations = {
+       .llseek                 = generic_file_llseek,
        .read                   = generic_read_dir,
        .readdir                = proc_readdir,
 };
@@ -547,9 +586,8 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
 
        for (tmp = dir->subdir; tmp; tmp = tmp->next)
                if (strcmp(tmp->name, dp->name) == 0) {
-                       printk(KERN_WARNING "proc_dir_entry '%s' already "
-                                       "registered\n", dp->name);
-                       dump_stack();
+                       WARN(1, KERN_WARNING "proc_dir_entry '%s/%s' already registered\n",
+                               dir->name, dp->name);
                        break;
                }