From: yangsheng Date: Fri, 3 Dec 2010 14:24:17 +0000 (+0800) Subject: b=19706 porting patch for master. X-Git-Tag: 2.1.57.0~10 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=595ce7a56e34d59ae1644373bbc0bafa4cd77c4d;p=fs%2Flustre-release.git b=19706 porting patch for master. 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 --- diff --git a/libcfs/include/libcfs/params_tree.h b/libcfs/include/libcfs/params_tree.h index d6bf464..635d6bc 100644 --- a/libcfs/include/libcfs/params_tree.h +++ b/libcfs/include/libcfs/params_tree.h @@ -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 { diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index eae0087..d8f72c4 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -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 +],[ + 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 diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 2a5d742..a6981db 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -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;