/* in lprocfs_stat.c, to protect the private data for proc entries */
extern struct rw_semaphore _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 { \
+ down_read(&_lprocfs_lock); \
+} while(0)
+
+#define LPROCFS_EXIT() \
+do { \
+ up_read(&_lprocfs_lock); \
+} while(0)
+
+#else
+#define LPROCFS_ENTRY() do{ }while(0)
+#define LPROCFS_EXIT() do{ }while(0)
+#endif
+
+#ifdef HAVE_PROCFS_DELETED
+
+static inline
+int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
+{
+ LPROCFS_ENTRY();
+ if ((dp)->deleted) {
+ LPROCFS_EXIT();
+ return -ENODEV;
+ }
+ return 0;
+}
+#elif defined(HAVE_PROCFS_USERS) /* !HAVE_PROCFS_DELETED*/
static inline
-int LPROCFS_ENTRY_CHECK(struct proc_dir_entry *dp)
+int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
{
int deleted = 0;
return -ENODEV;
return 0;
}
+#else /* !HAVE_PROCFS_DELETED*/
+static inline
+int LPROCFS_ENTRY_AND_CHECK(struct proc_dir_entry *dp)
+{
+ LPROCFS_ENTRY();
+ return 0;
+}
+#endif /* HAVE_PROCFS_DELETED */
#define LPROCFS_SRCH_ENTRY() \
do { \
down_read(&_lprocfs_lock); \
rc = 0; \
} while(0)
+#define LPROCFS_ENTRY() do {} while(0)
+#define LPROCFS_EXIT() do {} while(0)
static inline
-int LPROCFS_ENTRY_CHECK(cfs_param_dentry_t *dp)
+int LPROCFS_ENTRY_AND_CHECK(cfs_param_dentry_t *dp)
{
+ LPROCFS_ENTRY();
return 0;
}
#define LPROCFS_WRITE_ENTRY() do {} while(0)
])
])
+# 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])
+],[
+ LB_LINUX_TRY_COMPILE([
+ #include "$LINUX/fs/proc/internal.h"
+ ],[
+ struct proc_dir_entry_aux pde_aux;
+
+ pde_aux.pde_users = 0;
+ ],[
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_PROCFS_USERS, 1,
+ [kernel has pde_users member in proc_dir_entry_aux])
+ ],[
+ AC_MSG_RESULT([no])
+ ])
+])
+])
+
# 2.6.24
# 2.6.24 has bio_endio with 2 args
])
])
+# 2.6.24 removes long aged procfs entry -> deleted member
+AC_DEFUN([LC_PROCFS_DELETED],
+[AC_MSG_CHECKING([if kernel has deleted member in procfs entry struct])
+LB_LINUX_TRY_COMPILE([
+ #include <linux/proc_fs.h>
+],[
+ struct proc_dir_entry pde;
+
+ pde.deleted = sizeof(pde);
+], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_PROCFS_DELETED, 1,
+ [kernel has deleted member in procfs entry struct])
+],[
+ AC_MSG_RESULT([no])
+])
+])
+
# 2.6.26
# 2.6.26 isn't export set_fs_pwd and change paramter in fs struct
# 2.6.23
LC_UNREGISTER_BLKDEV_RETURN_INT
+ LC_PROCFS_USERS
# 2.6.24
LC_BIO_ENDIO_2ARG
+ LC_PROCFS_DELETED
# 2.6.26
LC_FS_STRUCT_USE_PATH
int env_init = 0;
int rc;
- LPROCFS_ENTRY_CHECK(dp);
+ LPROCFS_ENTRY_AND_CHECK(dp);
rc = seq_open(file, &fldb_sops);
if (rc)
GOTO(out, rc);
lu_env_fini(¶m->fsp_env);
if (param != NULL)
OBD_FREE_PTR(param);
+ LPROCFS_EXIT();
}
return rc;
}
#define __LPROC_SEQ_FOPS(name, custom_seq_write) \
static int name##_single_open(cfs_inode_t *inode, struct file *file) { \
struct proc_dir_entry *dp = PDE(inode); \
- LPROCFS_ENTRY_CHECK(dp); \
- return single_open(file, name##_seq_show, dp->data); \
+ int rc; \
+ LPROCFS_ENTRY_AND_CHECK(dp); \
+ rc = single_open(file, name##_seq_show, dp->data); \
+ if (rc) { \
+ LPROCFS_EXIT(); \
+ return rc; \
+ } \
+ return 0; \
} \
struct file_operations name##_fops = { \
.owner = THIS_MODULE, \
struct seq_file *seq;
int rc;
- LPROCFS_ENTRY_CHECK(dp);
+ LPROCFS_ENTRY_AND_CHECK(dp);
rc = seq_open(file, &lod_osts_sops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
return rc;
+ }
seq = file->private_data;
seq->private = dp->data;
struct seq_file *seq;
int rc;
- LPROCFS_ENTRY_CHECK(dp);
+ LPROCFS_ENTRY_AND_CHECK(dp);
rc = seq_open(file, &lov_tgt_sops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
return rc;
+ }
seq = file->private_data;
seq->private = dp->data;
struct mdt_device *mdt;
ENTRY;
- if (LPROCFS_ENTRY_CHECK(PDE(inode)))
+ if (LPROCFS_ENTRY_AND_CHECK(PDE(inode)))
RETURN(-ENOENT);
rc = seq_open(file, &mdt_agent_actions_proc_ops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
RETURN(rc);
+ }
OBD_ALLOC_PTR(aai);
if (aai == NULL)
struct seq_file *seq;
int rc;
- if (LPROCFS_ENTRY_CHECK(dp))
+ if (LPROCFS_ENTRY_AND_CHECK(dp))
return -ENOENT;
rc = seq_open(file, &lprocfs_jobstats_seq_sops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
return rc;
+ }
seq = file->private_data;
seq->private = dp->data;
return 0;
int lprocfs_single_release(struct inode *inode, struct file *file)
{
+ LPROCFS_EXIT();
return single_release(inode, file);
}
EXPORT_SYMBOL(lprocfs_single_release);
int lprocfs_seq_release(struct inode *inode, struct file *file)
{
+ LPROCFS_EXIT();
return seq_release(inode, file);
}
EXPORT_SYMBOL(lprocfs_seq_release);
if (page == NULL)
return -ENOMEM;
- if (LPROCFS_ENTRY_CHECK(dp)) {
+ if (LPROCFS_ENTRY_AND_CHECK(dp)) {
rc = -ENOENT;
goto out;
}
if (dp->read_proc)
rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
&eof, dp->data);
+ LPROCFS_EXIT();
if (rc <= 0)
goto out;
struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
int rc = -EIO;
- if (LPROCFS_ENTRY_CHECK(dp))
+ if (LPROCFS_ENTRY_AND_CHECK(dp))
return -ENOENT;
if (dp->write_proc)
rc = dp->write_proc(f, buf, size, dp->data);
+ LPROCFS_EXIT();
return rc;
}
struct seq_file *seq;
int rc;
- if (LPROCFS_ENTRY_CHECK(dp))
+ if (LPROCFS_ENTRY_AND_CHECK(dp))
return -ENOENT;
rc = seq_open(file, &lprocfs_stats_seq_sops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
return rc;
+ }
seq = file->private_data;
seq->private = dp->data;
return 0;
struct seq_file *seqf;
int rc;
- LPROCFS_ENTRY_CHECK(dp);
+ LPROCFS_ENTRY_AND_CHECK(dp);
rc = seq_open(file, &sops);
- if (rc)
+ if (rc) {
+ LPROCFS_EXIT();
return rc;
+ }
seqf = file->private_data;
seqf->private = dp->data;
goto out;
}
tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
+ /* Kludge code(deadlock situation): the lprocfs lock has been held
+ * since the client is evicted by writting client's
+ * uuid/nid to procfs "evict_client" entry. However,
+ * obd_export_evict_by_uuid() will call lprocfs_remove() to destroy
+ * the proc entries under the being destroyed export{}, so I have
+ * to drop the lock at first here.
+ * - jay, jxiong@clusterfs.com */
+ LPROCFS_EXIT();
class_incref(obd, __FUNCTION__, cfs_current());
if (strncmp(tmpbuf, "nid:", 4) == 0)
obd_export_evict_by_uuid(obd, tmpbuf);
class_decref(obd, __FUNCTION__, cfs_current());
+ LPROCFS_ENTRY();
out:
OBD_FREE(kbuf, BUFLEN);
goto out_lqp;
}
- if (LPROCFS_ENTRY_CHECK(dp)) {
+ if (LPROCFS_ENTRY_AND_CHECK(dp)) {
rc = -ENOENT;
goto out_env;
}
rc = seq_open(file, &lprocfs_quota_seq_sops);
if (rc)
- goto out_env;
+ goto out_lprocfs;
seq = file->private_data;
seq->private = lqp;
return 0;
+out_lprocfs:
+ LPROCFS_EXIT();
out_env:
lu_env_fini(&lqp->lqp_env);
out_lqp:
struct seq_file *seq = file->private_data;
struct lquota_procfs *lqp = seq->private;
+ LPROCFS_EXIT();
+
LASSERT(lqp);
lu_env_fini(&lqp->lqp_env);
OBD_FREE_PTR(lqp);