* 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/
#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 {
#define PTLRPC_FIRST_CNTR PTLRPC_REQWAIT_CNTR
-enum {
+enum lprocfs_extra_opc {
LDLM_GLIMPSE_ENQUEUE = 0,
LDLM_PLAIN_ENQUEUE,
LDLM_EXTENT_ENQUEUE,
#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)
/* Generic callbacks */
extern int lprocfs_u64_seq_show(struct seq_file *m, void *data);
extern int lprocfs_atomic_seq_show(struct seq_file *m, void *data);
-extern ssize_t lprocfs_atomic_seq_write(struct file *file, const char *buffer,
+extern ssize_t lprocfs_atomic_seq_write(struct file *file,
+ const char __user *buffer,
size_t count, loff_t *off);
extern int lprocfs_uint_seq_show(struct seq_file *m, void *data);
-extern ssize_t lprocfs_uint_seq_write(struct file *file, const char *buffer,
+extern ssize_t lprocfs_uint_seq_write(struct file *file,
+ const char __user *buffer,
size_t count, loff_t *off);
-extern int lprocfs_wr_uint(struct file *file, const char *buffer,
+extern int lprocfs_wr_uint(struct file *file, const char __user *buffer,
unsigned long count, void *data);
extern int lprocfs_uuid_seq_show(struct seq_file *m, void *data);
extern int lprocfs_name_seq_show(struct seq_file *m, void *data);
lprocfs_ping_seq_write(struct file *file, const char *buffer,
size_t count, loff_t *off);
extern ssize_t
-lprocfs_import_seq_write(struct file *file, const char *buffer,
+lprocfs_import_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
extern int lprocfs_pinger_recov_seq_show(struct seq_file *m, void *data);
extern ssize_t
extern int lprocfs_filestotal_seq_show(struct seq_file *m, void *data);
extern int lprocfs_filesfree_seq_show(struct seq_file *m, void *data);
-extern int lprocfs_write_helper(const char *buffer, unsigned long count,
+extern int lprocfs_write_helper(const char __user *buffer, unsigned long count,
int *val);
-extern int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
- int *val, int mult);
+extern int lprocfs_write_frac_helper(const char __user *buffer,
+ unsigned long count,
+ int *val, int mult);
extern int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult);
extern int lprocfs_read_frac_helper(char *buffer, unsigned long count,
long val, int mult);
-extern int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
- __u64 *val);
-extern int lprocfs_write_frac_u64_helper(const char *buffer,
+extern int lprocfs_write_u64_helper(const char __user *buffer,
+ unsigned long count, __u64 *val);
+extern int lprocfs_write_frac_u64_helper(const char __user *buffer,
unsigned long count,
__u64 *val, int mult);
char *lprocfs_find_named_value(const char *buffer, const char *name,
#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 lprocfs_##type##_seq_show(m, m->private); \
} \
static ssize_t name##_##type##_seq_write(struct file *file, \
- const char *buffer, size_t count, loff_t *off) \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
{ \
struct seq_file *seq = file->private_data; \
return lprocfs_##type##_seq_write(file, buffer, \
#define LPROC_SEQ_FOPS_WO_TYPE(name, type) \
static ssize_t name##_##type##_write(struct file *file, \
- const char *buffer, size_t count, loff_t *off) \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
{ \
return lprocfs_##type##_seq_write(file, buffer, count, off);\
} \
{ \
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, \
size_t count, loff_t *off);
struct root_squash_info;
-int lprocfs_wr_root_squash(const char *buffer, unsigned long count,
+int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count,
struct root_squash_info *squash, char *name);
-int lprocfs_wr_nosquash_nids(const char *buffer, unsigned long count,
+int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
struct root_squash_info *squash, char *name);
/* all quota proc functions */
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)
{ return 0; }
#endif
static inline ssize_t
-lprocfs_ping_seq_write(struct file *file, const char *buffer,
+lprocfs_ping_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{ return 0; }
static inline ssize_t
-lprocfs_import_seq_write(struct file *file, const char *buffer,
+lprocfs_import_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{ return 0; }
static inline int
lprocfs_pinger_recov_seq_show(struct seq_file *m, void *data)
{ return 0; }
static inline ssize_t
-lprocfs_pinger_recov_seq_write(struct file *file, const char *buffer,
+lprocfs_pinger_recov_seq_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{ return 0; }