* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2013, Intel Corporation.
+ * Copyright (c) 2011, 2014, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <lustre/lustre_idl.h>
#include <libcfs/params_tree.h>
+#ifndef HAVE_ONLY_PROCFS_SEQ
struct lprocfs_vars {
const char *name;
+ read_proc_t *read_fptr;
+ write_proc_t *write_fptr;
+ void *data;
+ const struct file_operations *fops;
+ /**
+ * /proc file mode.
+ */
+ mode_t proc_mode;
+};
+
+struct lprocfs_static_vars {
+ struct lprocfs_vars *module_vars;
+ struct lprocfs_vars *obd_vars;
+};
+
+#endif
+
+struct lprocfs_seq_vars {
+ const char *name;
const struct file_operations *fops;
void *data;
/**
#define lc_sum_irq lc_array_sum[1]
struct lprocfs_percpu {
- struct lprocfs_counter lp_cntr[0];
+ struct lprocfs_counter lp_cntr[0];
};
-#define LPROCFS_GET_NUM_CPU 0x0001
-#define LPROCFS_GET_SMP_ID 0x0002
+enum lprocfs_stats_lock_ops {
+ LPROCFS_GET_NUM_CPU = 0x0001, /* number allocated per-CPU stats */
+ LPROCFS_GET_SMP_ID = 0x0002, /* current stat to be updated */
+};
enum lprocfs_stats_flags {
LPROCFS_STATS_FLAG_NONE = 0x0000, /* per cpu counter */
};
enum lprocfs_fields_flags {
- LPROCFS_FIELDS_FLAGS_CONFIG = 0x0001,
- LPROCFS_FIELDS_FLAGS_SUM = 0x0002,
- LPROCFS_FIELDS_FLAGS_MIN = 0x0003,
- LPROCFS_FIELDS_FLAGS_MAX = 0x0004,
- LPROCFS_FIELDS_FLAGS_AVG = 0x0005,
- LPROCFS_FIELDS_FLAGS_SUMSQUARE = 0x0006,
- LPROCFS_FIELDS_FLAGS_COUNT = 0x0007,
+ LPROCFS_FIELDS_FLAGS_CONFIG = 0x0001,
+ LPROCFS_FIELDS_FLAGS_SUM = 0x0002,
+ LPROCFS_FIELDS_FLAGS_MIN = 0x0003,
+ LPROCFS_FIELDS_FLAGS_MAX = 0x0004,
+ LPROCFS_FIELDS_FLAGS_AVG = 0x0005,
+ LPROCFS_FIELDS_FLAGS_SUMSQUARE = 0x0006,
+ LPROCFS_FIELDS_FLAGS_COUNT = 0x0007,
};
struct lprocfs_stats {
#ifdef LPROCFS
extern int lprocfs_stats_alloc_one(struct lprocfs_stats *stats,
- unsigned int cpuid);
-/*
- * \return value
- * < 0 : on error (only possible for opc as LPROCFS_GET_SMP_ID)
+ unsigned int cpuid);
+
+/**
+ * Lock statistics structure for access, possibly only on this CPU.
+ *
+ * The statistics struct may be allocated with per-CPU structures for
+ * efficient concurrent update (usually only on server-wide stats), or
+ * as a single global struct (e.g. for per-client or per-job statistics),
+ * so the required locking depends on the type of structure allocated.
+ *
+ * For per-CPU statistics, pin the thread to the current cpuid so that
+ * will only access the statistics for that CPU. If the stats structure
+ * for the current CPU has not been allocated (or previously freed),
+ * allocate it now. The per-CPU statistics do not need locking since
+ * the thread is pinned to the CPU during update.
+ *
+ * For global statistics, lock the stats structure to prevent concurrent update.
+ *
+ * \param[in] stats statistics structure to lock
+ * \param[in] opc type of operation:
+ * LPROCFS_GET_SMP_ID: "lock" and return current CPU index
+ * for incrementing statistics for that CPU
+ * LPROCFS_GET_NUM_CPU: "lock" and return number of used
+ * CPU indices to iterate over all indices
+ * \param[out] flags CPU interrupt saved state for IRQ-safe locking
+ *
+ * \retval cpuid of current thread or number of allocated structs
+ * \retval negative on error (only for opc LPROCFS_GET_SMP_ID + per-CPU stats)
*/
-static inline int lprocfs_stats_lock(struct lprocfs_stats *stats, int opc,
+static inline int lprocfs_stats_lock(struct lprocfs_stats *stats,
+ enum lprocfs_stats_lock_ops opc,
unsigned long *flags)
{
- int rc = 0;
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+ spin_lock_irqsave(&stats->ls_lock, *flags);
+ else
+ spin_lock(&stats->ls_lock);
+ return opc == LPROCFS_GET_NUM_CPU ? 1 : 0;
+ }
switch (opc) {
- default:
- LBUG();
-
- case LPROCFS_GET_SMP_ID:
- if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
- if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
- spin_lock_irqsave(&stats->ls_lock, *flags);
- else
- spin_lock(&stats->ls_lock);
- return 0;
- } else {
- unsigned int cpuid = get_cpu();
-
- if (unlikely(stats->ls_percpu[cpuid] == NULL)) {
- rc = lprocfs_stats_alloc_one(stats, cpuid);
- if (rc < 0) {
- put_cpu();
- return rc;
- }
+ case LPROCFS_GET_SMP_ID: {
+ unsigned int cpuid = get_cpu();
+
+ if (unlikely(stats->ls_percpu[cpuid] == NULL)) {
+ int rc = lprocfs_stats_alloc_one(stats, cpuid);
+ if (rc < 0) {
+ put_cpu();
+ return rc;
}
- return cpuid;
}
-
+ return cpuid;
+ }
case LPROCFS_GET_NUM_CPU:
- if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
- if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
- spin_lock_irqsave(&stats->ls_lock, *flags);
- else
- spin_lock(&stats->ls_lock);
- return 1;
- } else {
- return stats->ls_biggest_alloc_num;
- }
+ return stats->ls_biggest_alloc_num;
+ default:
+ LBUG();
}
}
-static inline void lprocfs_stats_unlock(struct lprocfs_stats *stats, int opc,
+/**
+ * Unlock statistics structure after access.
+ *
+ * Unlock the lock acquired via lprocfs_stats_lock() for global statistics,
+ * or unpin this thread from the current cpuid for per-CPU statistics.
+ *
+ * This function must be called using the same arguments as used when calling
+ * lprocfs_stats_lock() so that the correct operation can be performed.
+ *
+ * \param[in] stats statistics structure to unlock
+ * \param[in] opc type of operation (current cpuid or number of structs)
+ * \param[in] flags CPU interrupt saved state for IRQ-safe locking
+ */
+static inline void lprocfs_stats_unlock(struct lprocfs_stats *stats,
+ enum lprocfs_stats_lock_ops opc,
unsigned long *flags)
{
- switch (opc) {
- default:
- LBUG();
-
- case LPROCFS_GET_SMP_ID:
- if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
- if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) {
- spin_unlock_irqrestore(&stats->ls_lock,
- *flags);
- } else {
- spin_unlock(&stats->ls_lock);
- }
- } else {
- put_cpu();
- }
- return;
-
- case LPROCFS_GET_NUM_CPU:
- if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
- if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) {
- spin_unlock_irqrestore(&stats->ls_lock,
- *flags);
- } else {
- spin_unlock(&stats->ls_lock);
- }
- }
- return;
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+ if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+ spin_unlock_irqrestore(&stats->ls_lock, *flags);
+ else
+ spin_unlock(&stats->ls_lock);
+ } else if (opc == LPROCFS_GET_SMP_ID) {
+ put_cpu();
}
}
extern int lprocfs_add_clear_entry(struct obd_device * obd,
struct proc_dir_entry *entry);
#ifdef HAVE_SERVER_SUPPORT
-extern int lprocfs_exp_setup(struct obd_export *exp,
- lnet_nid_t *peer_nid, int *newnid);
+extern int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *peer_nid);
extern int lprocfs_exp_cleanup(struct obd_export *exp);
#else
static inline int lprocfs_exp_cleanup(struct obd_export *exp)
struct lprocfs_stats *stats);
/* lprocfs_status.c */
+#ifndef HAVE_ONLY_PROCFS_SEQ
extern int lprocfs_add_vars(struct proc_dir_entry *root,
- struct lprocfs_vars *var, void *data);
+ struct lprocfs_vars *var,
+ void *data);
+
+extern struct proc_dir_entry *lprocfs_register(const char *name,
+ struct proc_dir_entry *parent,
+ struct lprocfs_vars *list,
+ void *data);
+#endif
+extern int lprocfs_seq_add_vars(struct proc_dir_entry *root,
+ struct lprocfs_seq_vars *var,
+ void *data);
+
extern struct proc_dir_entry *
-lprocfs_register(const char *name, struct proc_dir_entry *parent,
- struct lprocfs_vars *list, void *data);
+lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
+ struct lprocfs_seq_vars *list, void *data);
extern void lprocfs_remove(struct proc_dir_entry **root);
extern void lprocfs_remove_proc_entry(const char *name,
struct proc_dir_entry *parent);
#ifndef HAVE_ONLY_PROCFS_SEQ
-extern void remove_proc_subtree(const char *name,
- struct proc_dir_entry *parent);
+extern void lprocfs_try_remove_proc_entry(const char *name,
+ struct proc_dir_entry *parent);
+
+extern struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *root,
+ const char *name);
#endif
extern int lprocfs_obd_setup(struct obd_device *dev);
extern int lprocfs_obd_cleanup(struct obd_device *obd);
extern int lprocfs_num_exports_seq_show(struct seq_file *m, void *data);
#endif
struct adaptive_timeout;
-extern int lprocfs_at_hist_helper(struct seq_file *m,
+extern int lprocfs_seq_at_hist_helper(struct seq_file *m,
struct adaptive_timeout *at);
extern int lprocfs_timeouts_seq_show(struct seq_file *m, void *data);
extern ssize_t
lprocfs_timeouts_seq_write(struct file *file, const char *buffer,
size_t count, loff_t *off);
#ifdef HAVE_SERVER_SUPPORT
+#ifndef HAVE_ONLY_PROCFS_SEQ
+extern ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
+ size_t size, loff_t *ppos);
+extern ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *ppos);
+#endif
extern ssize_t
lprocfs_evict_client_seq_write(struct file *file, const char *buffer,
size_t count, loff_t *off);
#define __LPROC_SEQ_FOPS(name, custom_seq_write) \
static int name##_single_open(struct inode *inode, struct file *file) \
{ \
- LPROCFS_ENTRY_CHECK(PDE(inode)); \
+ int rc; \
+ \
+ rc = LPROCFS_ENTRY_CHECK(inode); \
+ if (rc < 0) \
+ return rc; \
+ \
return single_open(file, name##_seq_show, PDE_DATA(inode)); \
} \
-struct file_operations name##_fops = { \
+static const struct file_operations name##_fops = { \
.owner = THIS_MODULE, \
.open = name##_single_open, \
.read = seq_read, \
{ \
return single_open(file, NULL, PDE_DATA(inode)); \
} \
- struct file_operations name##_##type##_fops = { \
+ static const struct file_operations name##_##type##_fops = { \
.open = name##_##type##_open, \
.write = name##_##type##_write, \
.release = lprocfs_single_release, \
static inline
int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
{return 0;}
-static inline int lprocfs_exp_setup(struct obd_export *exp,lnet_nid_t *peer_nid,
- int *newnid)
+static inline int lprocfs_exp_setup(struct obd_export *exp,lnet_nid_t *peer_nid)
{ return 0; }
#endif
static inline int lprocfs_exp_cleanup(struct obd_export *exp)
lprocfs_add_symlink(const char *name, struct proc_dir_entry *parent,
const char *format, ...)
{return NULL; }
-static inline int lprocfs_add_vars(struct proc_dir_entry *root,
- struct lprocfs_vars *var,
- void *data)
-{ return 0; }
+#ifndef HAVE_ONLY_PROCFS_SEQ
static inline struct proc_dir_entry *
lprocfs_register(const char *name, struct proc_dir_entry *parent,
struct lprocfs_vars *list, void *data)
{ return NULL; }
+static inline int lprocfs_add_vars(struct proc_dir_entry *root,
+ struct lprocfs_vars *var,
+ void *data)
+{ return 0; }
+#endif
+static inline int lprocfs_seq_add_vars(struct proc_dir_entry *root,
+ struct lprocfs_seq_vars *var,
+ void *data)
+{ return 0; }
+static inline struct proc_dir_entry *
+lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
+ struct lprocfs_seq_vars *list, void *data)
+{ return NULL; }
static inline void lprocfs_remove(struct proc_dir_entry **root)
{ return; }
static inline void lprocfs_remove_proc_entry(const char *name,
struct proc_dir_entry *parent)
{ return; }
#ifndef HAVE_ONLY_PROCFS_SEQ
-static inline void remove_proc_subtree(const char *name,
- struct proc_dir_entry *parent)
+static inline void lprocfs_try_remove_proc_entry(const char *name,
+ struct proc_dir_entry *parent)
{ return; }
+static inline struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
+ const char *name)
+{ return 0; }
#endif
static inline int lprocfs_obd_setup(struct obd_device *dev)
{ return 0; }
{ return 0; }
#endif
struct adaptive_timeout;
-static inline int lprocfs_at_hist_helper(struct seq_file *m,
- struct adaptive_timeout *at)
+static inline int lprocfs_seq_at_hist_helper(struct seq_file *m,
+ struct adaptive_timeout *at)
{ return 0; }
static inline int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
{ return 0; }