take care to handle NULL ->proc_lseek()
[linux-2.6-microblaze.git] / fs / proc / inode.c
index 73aeb4e..f495fdb 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/mount.h>
 #include <linux/bug.h>
 
-#include <linux/uaccess.h>
-
 #include "internal.h"
 
 static void proc_evict_inode(struct inode *inode)
@@ -214,7 +212,15 @@ static void unuse_pde(struct proc_dir_entry *pde)
                complete(pde->pde_unload_completion);
 }
 
-/* pde is locked on entry, unlocked on exit */
+/*
+ * At most 2 contexts can enter this function: the one doing the last
+ * close on the descriptor and whoever is deleting PDE itself.
+ *
+ * First to enter calls ->proc_release hook and signals its completion
+ * to the second one which waits and then does nothing.
+ *
+ * PDE is locked on entry, unlocked on exit.
+ */
 static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
        __releases(&pde->pde_unload_lock)
 {
@@ -224,9 +230,6 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
         *
         * rmmod (remove_proc_entry() et al) can't delete an entry and proceed:
         * "struct file" needs to be available at the right moment.
-        *
-        * Therefore, first process to enter this function does ->release() and
-        * signals its completion to the other process which does nothing.
         */
        if (pdeo->closing) {
                /* somebody else is doing that, just wait */
@@ -240,10 +243,12 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
 
                pdeo->closing = true;
                spin_unlock(&pde->pde_unload_lock);
+
                file = pdeo->file;
                pde->proc_ops->proc_release(file_inode(file), file);
+
                spin_lock(&pde->pde_unload_lock);
-               /* After ->release. */
+               /* Strictly after ->proc_release, see above. */
                list_del(&pdeo->lh);
                c = pdeo->c;
                spin_unlock(&pde->pde_unload_lock);
@@ -489,6 +494,9 @@ static int proc_reg_open(struct inode *inode, struct file *file)
        typeof_member(struct proc_ops, proc_release) release;
        struct pde_opener *pdeo;
 
+       if (!pde->proc_ops->proc_lseek)
+               file->f_mode &= ~FMODE_LSEEK;
+
        if (pde_is_permanent(pde)) {
                open = pde->proc_ops->proc_open;
                if (open)