proc: introduce proc_create_data to setup de->data
Denis V. Lunev [Tue, 29 Apr 2008 08:02:00 +0000 (01:02 -0700)]
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 <>


index 0f3d97d..9d53b39 100644 (file)
@@ -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;
index c741b45..9511753 100644 (file)
@@ -230,5 +230,5 @@ void pid_ns_release_proc(struct pid_namespace *ns)
index 29abcb8..9883bc9 100644 (file)
@@ -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,