From 59b7435149eab2dd06dd678742faff6049cb655f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 29 Apr 2008 01:02:00 -0700 Subject: [PATCH] proc: introduce proc_create_data to setup de->data This set of patches fixes an proc ->open'less usage due to ->proc_fops flip in the most part of the kernel code. The original OOPS is described in the commit 2d3a4e3666325a9709cc8ea2e88151394e8f20fc: Typical PDE creation code looks like: pde = create_proc_entry("foo", 0, NULL); if (pde) pde->proc_fops = &foo_proc_fops; Notice that PDE is first created, only then ->proc_fops is set up to final value. This is a problem because right after creation a) PDE is fully visible in /proc , and b) ->proc_fops are proc_file_operations which do not have ->open callback. So, it's possible to ->read without ->open (see one class of oopses below). The fix is new API called proc_create() which makes sure ->proc_fops are set up before gluing PDE to main tree. Typical new code looks like: pde = proc_create("foo", 0, NULL, &foo_proc_fops); if (!pde) return -ENOMEM; Fix most networking users for a start. In the long run, create_proc_entry() for regular files will go. In addition to this, proc_create_data is introduced to fix reading from proc without PDE->data. The race is basically the same as above. create_proc_entries is replaced in the entire kernel code as new method is also simply better. This patch: The problem is the same as for de->proc_fops. Right now PDE becomes visible without data set. So, the entry could be looked up without data. This, in most cases, will simply OOPS. proc_create_data call is created to address this issue. proc_create now becomes a wrapper around it. Signed-off-by: Denis V. Lunev Cc: "Eric W. Biederman" Cc: "J. Bruce Fields" Cc: Alessandro Zummo Cc: Alexey Dobriyan Cc: Bartlomiej Zolnierkiewicz Cc: Benjamin Herrenschmidt Cc: Bjorn Helgaas Cc: Chris Mason Acked-by: David Howells Cc: Dmitry Torokhov Cc: Geert Uytterhoeven Cc: Grant Grundler Cc: Greg Kroah-Hartman Cc: Haavard Skinnemoen Cc: Heiko Carstens Cc: Ingo Molnar Cc: James Bottomley Cc: Jaroslav Kysela Cc: Jeff Garzik Cc: Jeff Mahoney Cc: Jesper Nilsson Cc: Karsten Keil Cc: Kyle McMartin Cc: Len Brown Cc: Martin Schwidefsky Cc: Mathieu Desnoyers Cc: Matthew Wilcox Cc: Mauro Carvalho Chehab Cc: Mikael Starvik Cc: Nadia Derbey Cc: Neil Brown Cc: Paul Mackerras Cc: Peter Osterlund Cc: Pierre Peiffer Cc: Russell King Cc: Takashi Iwai Cc: Tony Luck Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/generic.c | 8 +++++--- fs/proc/root.c | 2 +- include/linux/proc_fs.h | 17 +++++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 0f3d97d41b..9d53b39a9c 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -675,9 +675,10 @@ 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 *proc_create_data(const char *name, mode_t mode, + struct proc_dir_entry *parent, + const struct file_operations *proc_fops, + void *data) { struct proc_dir_entry *pde; nlink_t nlink; @@ -698,6 +699,7 @@ struct proc_dir_entry *proc_create(const char *name, mode_t mode, if (!pde) goto out; pde->proc_fops = proc_fops; + pde->data = data; if (proc_register(parent, pde) < 0) goto out_free; return pde; diff --git a/fs/proc/root.c b/fs/proc/root.c index c741b45a55..95117538a4 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -230,5 +230,5 @@ void pid_ns_release_proc(struct pid_namespace *ns) EXPORT_SYMBOL(proc_symlink); EXPORT_SYMBOL(proc_mkdir); EXPORT_SYMBOL(create_proc_entry); -EXPORT_SYMBOL(proc_create); +EXPORT_SYMBOL(proc_create_data); EXPORT_SYMBOL(remove_proc_entry); diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 29abcb8057..9883bc9422 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -116,9 +116,10 @@ void de_put(struct proc_dir_entry *de); extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent); -struct proc_dir_entry *proc_create(const char *name, mode_t mode, +struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, struct proc_dir_entry *parent, - const struct file_operations *proc_fops); + const struct file_operations *proc_fops, + void *data); extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); extern struct vfsmount *proc_mnt; @@ -173,6 +174,12 @@ extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *); extern struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dir_entry *parent); +static inline struct proc_dir_entry *proc_create(const char *name, mode_t mode, + struct proc_dir_entry *parent, const struct file_operations *proc_fops) +{ + return proc_create_data(name, mode, parent, proc_fops, NULL); +} + static inline struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void * data) @@ -214,6 +221,12 @@ static inline struct proc_dir_entry *proc_create(const char *name, { return NULL; } +static inline struct proc_dir_entry *proc_create_data(const char *name, + mode_t mode, struct proc_dir_entry *parent, + const struct file_operations *proc_fops, void *data) +{ + return NULL; +} #define remove_proc_entry(name, parent) do {} while (0) static inline struct proc_dir_entry *proc_symlink(const char *name, -- 2.39.5