]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/proc/generic.c
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / fs / proc / generic.c
index 6a2fe5187b6265db0c896aa9e68ec6fb7507a3a4..68971e66cd41ca438f7dff0e6047322fca2b5d5f 100644 (file)
 
 #include "internal.h"
 
-static ssize_t proc_file_read(struct file *file, char __user *buf,
-                             size_t nbytes, loff_t *ppos);
-static ssize_t proc_file_write(struct file *file, const char __user *buffer,
-                              size_t count, loff_t *ppos);
-static loff_t proc_file_lseek(struct file *, loff_t, int);
-
 DEFINE_SPINLOCK(proc_subdir_lock);
 
 static int proc_match(int len, const char *name, struct proc_dir_entry *de)
@@ -40,12 +34,6 @@ static int proc_match(int len, const char *name, struct proc_dir_entry *de)
        return !memcmp(name, de->name, len);
 }
 
-static const struct file_operations proc_file_operations = {
-       .llseek         = proc_file_lseek,
-       .read           = proc_file_read,
-       .write          = proc_file_write,
-};
-
 /* buffer size is one page but our output routines use some slack for overruns */
 #define PROC_BLOCK_SIZE        (PAGE_SIZE - 1024)
 
@@ -233,6 +221,12 @@ proc_file_lseek(struct file *file, loff_t offset, int orig)
        return retval;
 }
 
+static const struct file_operations proc_file_operations = {
+       .llseek         = proc_file_lseek,
+       .read           = proc_file_read,
+       .write          = proc_file_write,
+};
+
 static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
 {
        struct inode *inode = dentry->d_inode;
@@ -406,12 +400,12 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
                                spin_unlock(&proc_subdir_lock);
                                error = -EINVAL;
                                inode = proc_get_inode(dir->i_sb, ino, de);
-                               spin_lock(&proc_subdir_lock);
-                               break;
+                               goto out_unlock;
                        }
                }
        }
        spin_unlock(&proc_subdir_lock);
+out_unlock:
        unlock_kernel();
 
        if (inode) {
@@ -527,6 +521,7 @@ static const struct inode_operations proc_dir_inode_operations = {
 static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
 {
        unsigned int i;
+       struct proc_dir_entry *tmp;
        
        i = get_inode_number();
        if (i == 0)
@@ -550,6 +545,15 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
        }
 
        spin_lock(&proc_subdir_lock);
+
+       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();
+                       break;
+               }
+
        dp->next = dir->subdir;
        dp->parent = dir;
        dir->subdir = dp;
@@ -558,7 +562,7 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
        return 0;
 }
 
-static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
+static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
                                          const char *name,
                                          mode_t mode,
                                          nlink_t nlink)
@@ -601,7 +605,7 @@ struct proc_dir_entry *proc_symlink(const char *name,
 {
        struct proc_dir_entry *ent;
 
-       ent = proc_create(&parent,name,
+       ent = __proc_create(&parent, name,
                          (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1);
 
        if (ent) {
@@ -626,7 +630,7 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
 {
        struct proc_dir_entry *ent;
 
-       ent = proc_create(&parent, name, S_IFDIR | mode, 2);
+       ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
        if (ent) {
                if (proc_register(parent, ent) < 0) {
                        kfree(ent);
@@ -660,7 +664,7 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
                nlink = 1;
        }
 
-       ent = proc_create(&parent,name,mode,nlink);
+       ent = __proc_create(&parent, name, mode, nlink);
        if (ent) {
                if (proc_register(parent, ent) < 0) {
                        kfree(ent);
@@ -670,6 +674,38 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
        return ent;
 }
 
+struct proc_dir_entry *proc_create(const char *name, mode_t mode,
+                                  struct proc_dir_entry *parent,
+                                  const struct file_operations *proc_fops)
+{
+       struct proc_dir_entry *pde;
+       nlink_t nlink;
+
+       if (S_ISDIR(mode)) {
+               if ((mode & S_IALLUGO) == 0)
+                       mode |= S_IRUGO | S_IXUGO;
+               nlink = 2;
+       } else {
+               if ((mode & S_IFMT) == 0)
+                       mode |= S_IFREG;
+               if ((mode & S_IALLUGO) == 0)
+                       mode |= S_IRUGO;
+               nlink = 1;
+       }
+
+       pde = __proc_create(&parent, name, mode, nlink);
+       if (!pde)
+               goto out;
+       pde->proc_fops = proc_fops;
+       if (proc_register(parent, pde) < 0)
+               goto out_free;
+       return pde;
+out_free:
+       kfree(pde);
+out:
+       return NULL;
+}
+
 void free_proc_entry(struct proc_dir_entry *de)
 {
        unsigned int ino = de->low_ino;
@@ -679,7 +715,7 @@ void free_proc_entry(struct proc_dir_entry *de)
 
        release_inode_number(ino);
 
-       if (S_ISLNK(de->mode) && de->data)
+       if (S_ISLNK(de->mode))
                kfree(de->data);
        kfree(de);
 }