diff options
Diffstat (limited to 'fs/proc/generic.c')
-rw-r--r-- | fs/proc/generic.c | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 6a2fe5187b62..68971e66cd41 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -25,12 +25,6 @@ #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); } |