Whamcloud - gitweb
b=19706 porting patch for master.
authoryangsheng <sheng.yang@oracle.com>
Fri, 3 Dec 2010 14:24:17 +0000 (22:24 +0800)
committerVitaly Fertman <vitaly.fertman@oracle.com>
Fri, 3 Dec 2010 19:05:28 +0000 (22:05 +0300)
Since 2.6.32, kernel add pde_user in proc_dir_entry to protect
directory entry from deleted. So we don't need extra lock in
lprocfs_remove().

i=hongchao.zhang
i=johann

libcfs/include/libcfs/params_tree.h
lustre/autoconf/lustre-core.m4
lustre/obdclass/lprocfs_status.c

index d6bf464..635d6bc 100644 (file)
@@ -81,16 +81,38 @@ typedef struct poll_table_struct                cfs_poll_table_t;
 
 /* in lprocfs_stat.c, to protect the private data for proc entries */
 extern cfs_rw_semaphore_t       _lprocfs_lock;
+
+/* to begin from 2.6.23, Linux defines self file_operations (proc_reg_file_ops)
+ * in procfs, the proc file_operation defined by Lustre (lprocfs_generic_fops)
+ * will be wrapped into the new defined proc_reg_file_ops, which instroduces
+ * user count in proc_dir_entrey(pde_users) to protect the proc entry from
+ * being deleted. then the protection lock (_lprocfs_lock) defined by Lustre
+ * isn't necessary anymore for lprocfs_generic_fops(e.g. lprocfs_fops_read).
+ * see bug19706 for detailed information.
+ */
+#ifndef HAVE_PROCFS_USERS
+
 #define LPROCFS_ENTRY()                 \
 do {                                    \
         cfs_down_read(&_lprocfs_lock);  \
 } while(0)
+
 #define LPROCFS_EXIT()                  \
 do {                                    \
         cfs_up_read(&_lprocfs_lock);    \
 } while(0)
 
+#else
+#define LPROCFS_ENTRY() do{ }while(0)
+#define LPROCFS_EXIT()  do{ }while(0)
+#endif
+
 #ifdef HAVE_PROCFS_DELETED
+
+#ifdef HAVE_PROCFS_USERS
+#error proc_dir_entry->deleted is conflicted with proc_dir_entry->pde_users
+#endif
+
 static inline
 int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
 {
@@ -101,6 +123,19 @@ int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
         }
         return 0;
 }
+#elif defined(HAVE_PROCFS_USERS) /* !HAVE_PROCFS_DELETED*/
+static inline
+int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
+{
+        int deleted = 0;
+        spin_lock(&(dp)->pde_unload_lock);
+        if (dp->proc_fops == NULL)
+                deleted = 1;
+        spin_unlock(&(dp)->pde_unload_lock);
+        if (deleted)
+                return -ENODEV;
+        return 0;
+}
 #else /* !HAVE_PROCFS_DELETED*/
 static inline
 int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
@@ -109,16 +144,25 @@ int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
         return 0;
 }
 #endif /* HAVE_PROCFS_DELETED */
+#define LPROCFS_SRCH_ENTRY()            \
+do {                                    \
+        down_read(&_lprocfs_lock);      \
+} while(0)
+
+#define LPROCFS_SRCH_EXIT()             \
+do {                                    \
+        up_read(&_lprocfs_lock);        \
+} while(0)
 
 #define LPROCFS_WRITE_ENTRY()           \
 do {                                    \
         cfs_down_write(&_lprocfs_lock); \
 } while(0)
+
 #define LPROCFS_WRITE_EXIT()            \
 do {                                    \
         cfs_up_write(&_lprocfs_lock);   \
 } while(0)
-
 #else /* !LPROCFS */
 
 typedef struct cfs_params_file {
index eae0087..d8f72c4 100644 (file)
@@ -1183,6 +1183,24 @@ LB_LINUX_TRY_COMPILE([
 ])
 ])
 
+# 2.6.23 add code to wait other users to complete before removing procfs entry
+AC_DEFUN([LC_PROCFS_USERS],
+[AC_MSG_CHECKING([if kernel has pde_users member in procfs entry struct])
+LB_LINUX_TRY_COMPILE([
+        #include <linux/proc_fs.h>
+],[
+        struct proc_dir_entry pde;
+
+        pde.pde_users   = 0;
+],[
+        AC_MSG_RESULT([yes])
+        AC_DEFINE(HAVE_PROCFS_USERS, 1,
+                [kernel has pde_users member in procfs entry struct])
+],[
+        AC_MSG_RESULT([no])
+])
+])
+
 # 2.6.24 has bio_endio with 2 args
 AC_DEFUN([LC_BIO_ENDIO_2ARG],
 [AC_MSG_CHECKING([if kernel has bio_endio with 2 args])
@@ -2046,6 +2064,7 @@ AC_DEFUN([LC_PROG_LINUX],
          LC_HAVE_EXPORTFS_H
          LC_VM_OP_FAULT
          LC_REGISTER_SHRINKER
+         LC_PROCFS_USERS
   
         # 2.6.24
         LC_HAVE_MMTYPES_H
index 2a5d742..a6981db 100644 (file)
@@ -92,9 +92,9 @@ struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
 {
         struct proc_dir_entry *temp;
 
-        LPROCFS_ENTRY();
+        LPROCFS_SRCH_ENTRY();
         temp = __lprocfs_srch(head, name);
-        LPROCFS_EXIT();
+        LPROCFS_SRCH_EXIT();
         return temp;
 }
 
@@ -401,9 +401,23 @@ void lprocfs_remove(struct proc_dir_entry **rooth)
                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
                          rm_entry->name, (int)strlen(rm_entry->name));
 
+#ifdef HAVE_PROCFS_USERS
+                /* if procfs uses user count to synchronize deletion of
+                 * proc entry, there is no protection for rm_entry->data,
+                 * then lprocfs_fops_read and lprocfs_fops_write maybe
+                 * call proc_dir_entry->read_proc (or write_proc) with
+                 * proc_dir_entry->data == NULL, then cause kernel Oops.
+                 * see bug19706 for detailed information */
+
+                /* procfs won't free rm_entry->data if it isn't a LINK,
+                 * and Lustre won't use rm_entry->data if it is a LINK */
+                if (S_ISLNK(rm_entry->mode))
+                        rm_entry->data = NULL;
+#else
                 /* Now, the rm_entry->deleted flags is protected
                  * by _lprocfs_lock. */
                 rm_entry->data = NULL;
+#endif
                 remove_proc_entry(rm_entry->name, temp);
                 if (temp == parent)
                         break;