/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2002 Cluster File Systems, Inc.
+ * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
+ * Author: Hariharan Thantry <thantry@users.sourceforge.net>
*
* This file is part of Lustre, http://www.lustre.org.
*
* You should have received a copy of the GNU General Public License
* along with Lustre; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Author: Hariharan Thantry thantry@users.sourceforge.net
*/
-#define EXPORT_SYMTAB
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/types.h>
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/lustre_lite.h>
-#include <linux/lprocfs_status.h>
-
-#ifdef LPROC_SNMP
-
-#define DEFAULT_MODE 0444
-/*
- * Tokenizer array. Change this array to include special
- * characters for string tokenizing
- */
-const char tok[] = {'/', '\0'};
-/*
- * Externs
- */
-extern struct proc_dir_entry proc_root; /* Defined in proc/root.c */
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/version.h>
+# include <linux/slab.h>
+# include <linux/types.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+# include <asm/statfs.h>
+# endif
+# include <linux/seq_file.h>
+# include <asm/div64.h>
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
-/*
- * Globals
- */
-struct proc_dir_entry *proc_lustre_root;
-struct proc_dir_entry *proc_lustre_dev_root;
-struct proc_dir_entry *proc_lustre_fs_root;
+#include <linux/obd_class.h>
+#include <linux/lprocfs_status.h>
+#include <linux/lustre_fsfilt.h>
-struct proc_dir_entry* lprocfs_mkdir(const char* dname,
- struct proc_dir_entry *parent)
+#if defined(LPROCFS) && defined(__KERNEL__)
+struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
+ const char *name)
{
- struct proc_dir_entry *child_dir_entry;
- child_dir_entry = proc_mkdir(dname, parent);
- if (!child_dir_entry)
- CERROR("lustre: failed to create /proc entry %s\n", dname);
- return child_dir_entry;
-}
+ struct proc_dir_entry *temp;
-struct proc_dir_entry* lprocfs_srch(struct proc_dir_entry* head,
- const char* name)
-{
- struct proc_dir_entry* temp;
- if (!head)
+ if (head == NULL)
return NULL;
+
temp = head->subdir;
while (temp != NULL) {
- if (!strcmp(temp->name, name))
+ if (strcmp(temp->name, name) == 0)
return temp;
+
temp = temp->next;
}
return NULL;
}
-void lprocfs_remove_all(struct proc_dir_entry* root)
+/* lprocfs API calls */
+int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
+ void *data)
+{
+ if (root == NULL || list == NULL)
+ return -EINVAL;
+
+ while (list->name != NULL) {
+ struct proc_dir_entry *cur_root, *proc;
+ char *pathcopy, *cur, *next, pathbuf[64];
+ int pathsize = strlen(list->name) + 1;
+
+ proc = NULL;
+ cur_root = root;
+
+ /* need copy of path for strsep */
+ if (strlen(list->name) > sizeof(pathbuf) - 1) {
+ OBD_ALLOC(pathcopy, pathsize);
+ if (pathcopy == NULL)
+ return -ENOMEM;
+ } else {
+ pathcopy = pathbuf;
+ }
+
+ next = pathcopy;
+ strcpy(pathcopy, list->name);
+
+ while (cur_root != NULL && (cur = strsep(&next, "/"))) {
+ if (*cur =='\0') /* skip double/trailing "/" */
+ continue;
+
+ proc = lprocfs_srch(cur_root, cur);
+ CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
+ cur_root->name, cur, next,
+ (proc ? "exists" : "new"));
+ if (next != NULL) {
+ cur_root = (proc ? proc :
+ proc_mkdir(cur, cur_root));
+ } else if (proc == NULL) {
+ mode_t mode = 0;
+ if (list->read_fptr)
+ mode = 0444;
+ if (list->write_fptr)
+ mode |= 0200;
+ proc = create_proc_entry(cur, mode, cur_root);
+ }
+ }
+
+ if (pathcopy != pathbuf)
+ OBD_FREE(pathcopy, pathsize);
+
+ if (cur_root == NULL || proc == NULL) {
+ CERROR("LprocFS: No memory to create /proc entry %s",
+ list->name);
+ return -ENOMEM;
+ }
+
+ proc->read_proc = list->read_fptr;
+ proc->write_proc = list->write_fptr;
+ proc->data = (list->data ? list->data : data);
+ list++;
+ }
+ return 0;
+}
+
+void lprocfs_remove(struct proc_dir_entry *root)
{
struct proc_dir_entry *temp = root;
struct proc_dir_entry *rm_entry;
- struct proc_dir_entry *parent = root->parent;
+ struct proc_dir_entry *parent;
+ LASSERT(root != NULL);
+ parent = root->parent;
+ LASSERT(parent != NULL);
+
while (1) {
- while (temp->subdir)
+ while (temp->subdir != NULL)
temp = temp->subdir;
rm_entry = temp;
temp = temp->parent;
+
+ /* Memory corruption once caused this to fail, and
+ without this LASSERT we would loop here forever. */
+ LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
+ "0x%p %s/%s len %d\n", rm_entry, temp->name,
+ rm_entry->name, (int)strlen(rm_entry->name));
+
remove_proc_entry(rm_entry->name, rm_entry->parent);
if (temp == parent)
break;
}
}
-#define MAX_STRING_SIZE 100
-struct proc_dir_entry* lprocfs_new_dir(struct proc_dir_entry* root,
- const char* string, const char* tok)
-{
- struct proc_dir_entry* new_root;
- struct proc_dir_entry* temp_entry;
- char temp_string[MAX_STRING_SIZE+1];
- char* my_str;
- char* mover_str;
-
- strncpy(temp_string, string, MAX_STRING_SIZE);
- temp_string[MAX_STRING_SIZE] = '\0';
-
- new_root = root;
- mover_str = temp_string;
- while ((my_str = strsep(&mover_str, tok))) {
- if (!*my_str)
- continue;
- CDEBUG(D_OTHER, "SEARCH= %s\t, ROOT=%s\n", my_str,
- new_root->name);
- temp_entry = lprocfs_srch(new_root, my_str);
- if (temp_entry == NULL) {
- CDEBUG(D_OTHER, "Adding: %s\n", my_str);
- temp_entry = lprocfs_mkdir(my_str, new_root);
- if (temp_entry == NULL) {
- CDEBUG(D_OTHER,
- "! Did not create new dir %s !!\n",
- my_str);
- return temp_entry;
- }
+struct proc_dir_entry *lprocfs_register(const char *name,
+ struct proc_dir_entry *parent,
+ struct lprocfs_vars *list, void *data)
+{
+ struct proc_dir_entry *newchild;
+
+ newchild = lprocfs_srch(parent, name);
+ if (newchild != NULL) {
+ CERROR(" Lproc: Attempting to register %s more than once \n",
+ name);
+ return ERR_PTR(-EALREADY);
+ }
+
+ newchild = proc_mkdir(name, parent);
+ if (newchild != NULL && list != NULL) {
+ int rc = lprocfs_add_vars(newchild, list, data);
+ if (rc) {
+ lprocfs_remove(newchild);
+ return ERR_PTR(rc);
}
- new_root = temp_entry;
}
- return new_root;
+ return newchild;
}
-int lprocfs_new_vars(struct proc_dir_entry* root, struct lprocfs_vars* list,
- const char* tok, void* data)
+/* Generic callbacks */
+
+int lprocfs_rd_u64(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
- struct proc_dir_entry *temp_root;
- struct proc_dir_entry *new_leaf;
- struct proc_dir_entry *new_parent;
- char temp_string[MAX_STRING_SIZE+1];
+ LASSERT(data != NULL);
+ *eof = 1;
+ return snprintf(page, count, LPU64"\n", *(__u64 *)data);
+}
- if (list == NULL)
- return 0;
+int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *dev = (struct obd_device*)data;
- while (list->name) {
- temp_root = lprocfs_new_dir(root, list->name, tok);
- if (temp_root == NULL) {
- CDEBUG(D_OTHER, "!LProcFS: Mods: No root!");
- return -ENOMEM;
- }
+ LASSERT(dev != NULL);
+ *eof = 1;
+ return snprintf(page, count, "%s\n", dev->obd_uuid.uuid);
+}
- /* Convert the last element into a leaf-node */
- strncpy(temp_string, temp_root->name, MAX_STRING_SIZE);
- temp_string[MAX_STRING_SIZE] = '\0';
- new_parent = temp_root->parent;
- remove_proc_entry(temp_root->name, new_parent);
- new_leaf = create_proc_entry(temp_string, DEFAULT_MODE,
- new_parent);
- if (new_leaf == NULL) {
- CERROR("LprocFS: No memory to create /proc entry %s",
- temp_string);
- return -ENOMEM;
- }
- new_leaf->read_proc = list->read_fptr;
- new_leaf->write_proc = list->write_fptr;
- if (data)
- new_leaf->data=data;
- else
- new_leaf->data=list->data;
- list++;
- }
- return 0;
+int lprocfs_rd_name(char *page, char **start, off_t off, int count,
+ int *eof, void* data)
+{
+ struct obd_device *dev = (struct obd_device *)data;
+ LASSERT(dev != NULL);
+ LASSERT(dev->obd_name != NULL);
+ *eof = 1;
+ return snprintf(page, count, "%s\n", dev->obd_name);
}
-#undef MAX_STRING_SIZE
-/*
- * API implementations
- */
-int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *var,
- void *data)
+
+int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+
+ LASSERT(obd != NULL);
+ LASSERT(obd->obd_fsops != NULL);
+ LASSERT(obd->obd_fsops->fs_type != NULL);
+ return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
+}
+
+int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
{
- return lprocfs_new_vars(root, var, tok, data);
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ *eof = 1;
+ rc = snprintf(page, count, "%u\n", osfs.os_bsize);
+ }
+ return rc;
}
-int lprocfs_reg_obd(struct obd_device *device, struct lprocfs_vars *list,
- void *data)
+int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
{
- struct proc_dir_entry* this_dev_root;
- int retval;
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ __u32 blk_size = osfs.os_bsize >> 10;
+ __u64 result = osfs.os_blocks;
- if (lprocfs_srch(device->obd_type->typ_procroot, device->obd_name)) {
- CDEBUG(D_OTHER, "Device with name [%s] exists!",
- device->obd_name);
- return 0;
+ while (blk_size >>= 1)
+ result <<= 1;
+
+ *eof = 1;
+ rc = snprintf(page, count, LPU64"\n", result);
}
+ return rc;
+}
- /* Obtain this device root */
- this_dev_root = lprocfs_mkdir(device->obd_name,
- device->obd_type->typ_procroot);
+int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ __u32 blk_size = osfs.os_bsize >> 10;
+ __u64 result = osfs.os_bfree;
- device->obd_proc_entry = this_dev_root;
- retval = lprocfs_add_vars(this_dev_root, list, data);
+ while (blk_size >>= 1)
+ result <<= 1;
- return retval;
+ *eof = 1;
+ rc = snprintf(page, count, LPU64"\n", result);
+ }
+ return rc;
}
-int lprocfs_dereg_obd(struct obd_device* device)
+int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
{
- CDEBUG(D_OTHER, "LPROCFS removing device = %s\n", device->obd_name);
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ __u32 blk_size = osfs.os_bsize >> 10;
+ __u64 result = osfs.os_bavail;
- if (device == NULL) {
- CDEBUG(D_OTHER, "! LProcfs: Null pointer !\n");
- return 0;
+ while (blk_size >>= 1)
+ result <<= 1;
+
+ *eof = 1;
+ rc = snprintf(page, count, LPU64"\n", result);
}
- if (device->obd_proc_entry == NULL) {
- CDEBUG(D_OTHER, "! Proc entry non-existent !");
- return 0;
+ return rc;
+}
+
+int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ *eof = 1;
+ rc = snprintf(page, count, LPU64"\n", osfs.os_files);
}
- lprocfs_remove_all(device->obd_proc_entry);
- device->obd_proc_entry = NULL;
- if (device->counters)
- OBD_FREE(device->counters, device->cntr_mem_size);
- return 0;
+ return rc;
+}
+
+int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_statfs osfs;
+ int rc = obd_statfs(data, &osfs, jiffies - HZ);
+ if (!rc) {
+ *eof = 1;
+ rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
+ }
+ return rc;
+}
+
+int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device *)data;
+ struct obd_import *imp;
+ char *imp_state_name = NULL;
+
+ LASSERT(obd != NULL);
+ imp = obd->u.cli.cl_import;
+ imp_state_name = ptlrpc_import_state_name(imp->imp_state);
+ *eof = 1;
+ return snprintf(page, count, "%s\t%s\n",
+ imp->imp_target_uuid.uuid, imp_state_name);
+}
+
+int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device*)data;
+ struct ptlrpc_connection *conn;
+
+ LASSERT(obd != NULL);
+ conn = obd->u.cli.cl_import->imp_connection;
+ LASSERT(conn != NULL);
+ *eof = 1;
+ return snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
+}
+
+int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct obd_device *obd = (struct obd_device*)data;
+
+ LASSERT(obd != NULL);
+ *eof = 1;
+ return snprintf(page, count, "%u\n", obd->obd_num_exports);
}
-struct proc_dir_entry* lprocfs_reg_mnt(char* mnt_name)
+int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
{
- if (lprocfs_srch(proc_lustre_fs_root, mnt_name)) {
- CDEBUG(D_OTHER, "Mount with same name exists!");
- return 0;
+ struct obd_type *class = (struct obd_type*) data;
+
+ LASSERT(class != NULL);
+ *eof = 1;
+ return snprintf(page, count, "%d\n", class->typ_refcnt);
+}
+
+int lprocfs_obd_attach(struct obd_device *dev, struct lprocfs_vars *list)
+{
+ int rc = 0;
+
+ LASSERT(dev != NULL);
+ LASSERT(dev->obd_type != NULL);
+ LASSERT(dev->obd_type->typ_procroot != NULL);
+
+ dev->obd_proc_entry = lprocfs_register(dev->obd_name,
+ dev->obd_type->typ_procroot,
+ list, dev);
+ if (IS_ERR(dev->obd_proc_entry)) {
+ rc = PTR_ERR(dev->obd_proc_entry);
+ dev->obd_proc_entry = NULL;
}
- return lprocfs_mkdir(mnt_name, proc_lustre_fs_root);
+ return rc;
}
-int lprocfs_dereg_mnt(struct proc_dir_entry* root)
+int lprocfs_obd_detach(struct obd_device *dev)
{
- if (root == NULL) {
- CDEBUG(D_OTHER, "Non-existent root!");
- return 0;
+ if (dev && dev->obd_proc_entry) {
+ lprocfs_remove(dev->obd_proc_entry);
+ dev->obd_proc_entry = NULL;
}
- lprocfs_remove_all(root);
return 0;
}
-int lprocfs_reg_class(struct obd_type* type, struct lprocfs_vars* list,
- void* data)
+struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
{
- struct proc_dir_entry* root;
- int retval;
- root = lprocfs_mkdir(type->typ_name, proc_lustre_dev_root);
- lprocfs_add_vars(root, list, data);
- type->typ_procroot = root;
- retval = lprocfs_add_vars(root, list, data);
- return retval;
+ struct lprocfs_stats *stats;
+ struct lprocfs_percpu *percpu;
+ unsigned int percpusize;
+ unsigned int i;
+
+ if (num == 0)
+ return NULL;
+
+ OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
+ if (stats == NULL)
+ return NULL;
+
+ percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
+ stats->ls_percpu_size = num_online_cpus() * percpusize;
+ OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
+ if (stats->ls_percpu[0] == NULL) {
+ OBD_FREE(stats, offsetof(typeof(*stats),
+ ls_percpu[num_online_cpus()]));
+ return NULL;
+ }
+
+ stats->ls_num = num;
+ for (i = 1; i < num_online_cpus(); i++)
+ stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
+ percpusize;
+
+ return stats;
}
-int lprocfs_dereg_class(struct obd_type* class)
+void lprocfs_free_stats(struct lprocfs_stats *stats)
{
- if (class == NULL) {
- CDEBUG(D_OTHER, "Non-existent class");
- return 0;
- }
- lprocfs_remove_all(class->typ_procroot);
- class->typ_procroot = NULL;
- CDEBUG(D_OTHER, "LPROCFS removed = %s\n", class->typ_name);
+ if (stats->ls_num == 0)
+ return;
+
+ OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
+ OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
+}
+
+/* Reset counter under lock */
+int lprocfs_counter_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ /* not supported */
return 0;
+}
+
+static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
+{
+ struct lprocfs_stats *stats = p->private;
+ /* return 1st cpu location */
+ return (*pos >= stats->ls_num) ? NULL :
+ &(stats->ls_percpu[0]->lp_cntr[*pos]);
+}
+static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
+{
}
-int lprocfs_reg_main()
+static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
{
- proc_lustre_root = lprocfs_mkdir("lustre", &proc_root);
- if (proc_lustre_root == NULL) {
- CERROR(" !! Cannot create /proc/lustre !! \n");
- return -EINVAL;
+ struct lprocfs_stats *stats = p->private;
+ ++*pos;
+ return (*pos >= stats->ls_num) ? NULL :
+ &(stats->ls_percpu[0]->lp_cntr[*pos]);
+}
+
+/* seq file export of one lprocfs counter */
+static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
+{
+ struct lprocfs_stats *stats = p->private;
+ struct lprocfs_counter *cntr = v;
+ struct lprocfs_counter t, ret = { .lc_min = ~(__u64)0 };
+ int i, idx, rc;
+
+ if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
+ struct timeval now;
+ do_gettimeofday(&now);
+ rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
+ "snapshot_time", now.tv_sec, now.tv_usec);
+ if (rc < 0)
+ return rc;
+ }
+ idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ struct lprocfs_counter *percpu_cntr =
+ &(stats->ls_percpu[i])->lp_cntr[idx];
+ int centry;
+
+ do {
+ centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
+ t.lc_count = percpu_cntr->lc_count;
+ t.lc_sum = percpu_cntr->lc_sum;
+ t.lc_min = percpu_cntr->lc_min;
+ t.lc_max = percpu_cntr->lc_max;
+ t.lc_sumsquare = percpu_cntr->lc_sumsquare;
+ } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
+ centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
+ ret.lc_count += t.lc_count;
+ ret.lc_sum += t.lc_sum;
+ if (t.lc_min < ret.lc_min)
+ ret.lc_min = t.lc_min;
+ if (t.lc_max > ret.lc_max)
+ ret.lc_max = t.lc_max;
+ ret.lc_sumsquare += t.lc_sumsquare;
+ }
+
+ rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
+ ret.lc_count, cntr->lc_units);
+ if (rc < 0)
+ goto out;
+
+ if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
+ rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
+ ret.lc_min, ret.lc_max, ret.lc_sum);
+ if (rc < 0)
+ goto out;
+ if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
+ rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
+ if (rc < 0)
+ goto out;
+ }
+ rc = seq_printf(p, "\n");
+ out:
+ return (rc < 0) ? rc : 0;
+}
+
+struct seq_operations lprocfs_stats_seq_sops = {
+ start: lprocfs_stats_seq_start,
+ stop: lprocfs_stats_seq_stop,
+ next: lprocfs_stats_seq_next,
+ show: lprocfs_stats_seq_show,
+};
+
+static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *dp = PDE(inode);
+ struct seq_file *seq;
+ int rc;
+
+ rc = seq_open(file, &lprocfs_stats_seq_sops);
+ if (rc)
+ return rc;
+ seq = file->private_data;
+ seq->private = dp->data;
+ return 0;
+}
+
+struct file_operations lprocfs_stats_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = lprocfs_stats_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int lprocfs_register_stats(struct proc_dir_entry *root,
+ const char *name,
+ struct lprocfs_stats *stats)
+{
+ struct proc_dir_entry *entry;
+ LASSERT(root != NULL);
+
+ entry = create_proc_entry(name, 0444, root);
+ if (entry == NULL)
+ return -ENOMEM;
+ entry->proc_fops = &lprocfs_stats_seq_fops;
+ entry->data = (void *)stats;
+ entry->write_proc = lprocfs_counter_write;
+ return 0;
+}
+
+void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
+ unsigned conf, const char *name,
+ const char *units)
+{
+ struct lprocfs_counter *c;
+ int i;
+
+ LASSERT(stats != NULL);
+ for (i = 0; i < num_online_cpus(); i++) {
+ c = &(stats->ls_percpu[i]->lp_cntr[index]);
+ c->lc_config = conf;
+ c->lc_min = ~(__u64)0;
+ c->lc_name = name;
+ c->lc_units = units;
}
+}
+EXPORT_SYMBOL(lprocfs_counter_init);
- proc_lustre_dev_root = lprocfs_mkdir("devices", proc_lustre_root);
- if (proc_lustre_dev_root == NULL) {
- CERROR(" !! Cannot create /proc/lustre/devices !! \n");
- return -EINVAL;
+#define LPROCFS_OBD_OP_INIT(base, stats, op) \
+do { \
+ unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
+ LASSERT(coffset < stats->ls_num); \
+ lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
+} while (0)
+
+int lprocfs_alloc_obd_stats(struct obd_device *obd,
+ unsigned num_private_stats)
+{
+ struct lprocfs_stats *stats;
+ unsigned int num_stats;
+ int rc, i;
+
+ LASSERT(obd->obd_stats == NULL);
+ LASSERT(obd->obd_proc_entry != NULL);
+ LASSERT(obd->obd_cntr_base == 0);
+
+ num_stats = 1 + OBD_COUNTER_OFFSET(init_ea_size) +
+ num_private_stats;
+ stats = lprocfs_alloc_stats(num_stats);
+ if (stats == NULL)
+ return -ENOMEM;
+
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect_post);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, revalidate_md);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, do_cow);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, write_extents);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, san_preprw);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_ea_size);
+
+ for (i = num_private_stats; i < num_stats; i++) {
+ /* if this LBUGs, it is likely that an obd operation was added
+ * to struct obd_ops in <linux/obd.h>, and that the
+ * corresponding line item LPROCFS_OBD_OP_INIT(.., .., opname)
+ * is missing from the list above. */
+ if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
+ CERROR("Missing obd_stat initializer obd_op "
+ "operation at offset %d. Aborting.\n",
+ i - num_private_stats);
+ LBUG();
+ }
+ }
+ rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
+ if (rc < 0) {
+ lprocfs_free_stats(stats);
+ } else {
+ obd->obd_stats = stats;
+ obd->obd_cntr_base = num_private_stats;
}
- proc_lustre_fs_root = lprocfs_mkdir("mnt_pnt", proc_lustre_root);
+ return rc;
+}
- if (proc_lustre_fs_root == NULL) {
- CERROR(" !! Cannot create /proc/lustre/mnt_pnt !! \n");
- return -EINVAL;
+void lprocfs_free_obd_stats(struct obd_device *obd)
+{
+ struct lprocfs_stats *stats = obd->obd_stats;
+
+ if (stats != NULL) {
+ obd->obd_stats = NULL;
+ lprocfs_free_stats(stats);
}
+}
+
+#define LPROCFS_MD_OP_INIT(base, stats, op) \
+do { \
+ unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
+ LASSERT(coffset < stats->ls_num); \
+ lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
+} while (0)
+
+int lprocfs_alloc_md_stats(struct obd_device *obd,
+ unsigned num_private_stats)
+{
+ struct lprocfs_stats *stats;
+ unsigned int num_stats;
+ int rc, i;
+
+ LASSERT(obd->md_stats == NULL);
+ LASSERT(obd->obd_proc_entry != NULL);
+ LASSERT(obd->md_cntr_base == 0);
+
+ num_stats = 1 + MD_COUNTER_OFFSET(delete_inode) +
+ num_private_stats;
+ stats = lprocfs_alloc_stats(num_stats);
+ if (stats == NULL)
+ return -ENOMEM;
+
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata_name);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, access_check);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_lock);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, valid_attrs);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, get_real_obd);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, req2lustre_md);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, store_inode_generation);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
+ LPROCFS_MD_OP_INIT(num_private_stats, stats, delete_inode);
+
+ for (i = num_private_stats; i < num_stats; i++) {
+ if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
+ CERROR("Missing md_stat initializer md_op "
+ "operation at offset %d. Aborting.\n",
+ i - num_private_stats);
+ LBUG();
+ }
+ }
+ rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
+ if (rc < 0) {
+ lprocfs_free_stats(stats);
+ } else {
+ obd->md_stats = stats;
+ obd->md_cntr_base = num_private_stats;
+ }
+ return rc;
+}
+
+void lprocfs_free_md_stats(struct obd_device *obd)
+{
+ struct lprocfs_stats *stats = obd->md_stats;
+
+ if (stats != NULL) {
+ obd->md_stats = NULL;
+ lprocfs_free_stats(stats);
+ }
+}
+
+int lprocfs_write_helper(const char *buffer, unsigned long count,
+ int *val)
+{
+ char kernbuf[20], *end;
+
+ if (count > (sizeof(kernbuf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(kernbuf, buffer, count))
+ return -EFAULT;
+
+ kernbuf[count] = '\0';
+
+ *val = simple_strtol(kernbuf, &end, 0);
+ if (kernbuf == end)
+ return -EINVAL;
return 0;
}
-int lprocfs_dereg_main()
+int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
+ __u64 *val)
{
- lprocfs_remove_all(proc_lustre_root);
- proc_lustre_root = NULL;
- proc_lustre_dev_root = NULL;
- proc_lustre_fs_root = NULL;
+ char kernbuf[22], *end;
+
+ if (count > (sizeof(kernbuf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(kernbuf, buffer, count))
+ return -EFAULT;
+
+ kernbuf[count] = '\0';
+
+ if (kernbuf[0] == '-')
+ *val = -simple_strtoull(kernbuf + 1, &end, 0);
+ else
+ *val = simple_strtoull(kernbuf, &end, 0);
+ if (kernbuf == end)
+ return -EINVAL;
+
return 0;
}
+int lprocfs_obd_seq_create(struct obd_device *dev, char *name, mode_t mode,
+ struct file_operations *seq_fops, void *data)
+{
+ struct proc_dir_entry *entry;
+ ENTRY;
+
+ entry = create_proc_entry(name, mode, dev->obd_proc_entry);
+ if (entry == NULL)
+ RETURN(-ENOMEM);
+ entry->proc_fops = seq_fops;
+ entry->data = data;
-/*
- * Needs to go...
- */
-int lprocfs_ll_rd(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+ RETURN(0);
+}
+EXPORT_SYMBOL(lprocfs_obd_seq_create);
+
+void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
+{
+ unsigned long flags;
+
+ if (value >= OBD_HIST_MAX)
+ value = OBD_HIST_MAX - 1;
+
+ spin_lock_irqsave(&oh->oh_lock, flags);
+ oh->oh_buckets[value]++;
+ spin_unlock_irqrestore(&oh->oh_lock, flags);
+}
+EXPORT_SYMBOL(lprocfs_oh_tally);
+
+void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
+{
+ unsigned int val;
+
+ for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
+ ;
+
+ lprocfs_oh_tally(oh, val);
+}
+EXPORT_SYMBOL(lprocfs_oh_tally_log2);
+
+unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
+{
+ unsigned long ret = 0;
+ int i;
+
+ for (i = 0; i < OBD_HIST_MAX; i++)
+ ret += oh->oh_buckets[i];
+ return ret;
+}
+EXPORT_SYMBOL(lprocfs_oh_sum);
+
+void lprocfs_oh_clear(struct obd_histogram *oh)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&oh->oh_lock, flags);
+ memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
+ spin_unlock_irqrestore(&oh->oh_lock, flags);
+}
+EXPORT_SYMBOL(lprocfs_oh_clear);
+
+/* XXX copied from ldlm/ldlm_lockd.c, copied from ptlrpc/service.c */
+static long timeval_sub(struct timeval *large, struct timeval *small)
+{
+ return ((large->tv_sec - small->tv_sec) * 1000000) +
+ (large->tv_usec - small->tv_usec);
+}
+
+void lprocfs_stime_record(struct obd_service_time *stime, struct timeval *large,
+ struct timeval *small)
{
- __u64 *temp = (__u64 *)data;
- int len;
- len = snprintf(page, count, LPU64"\n", *temp);
- return len;
+ long diff = timeval_sub(large, small);
+
+ if (diff < 0)
+ return;
+
+ stime->st_num++;
+ stime->st_total_us += diff;
}
+EXPORT_SYMBOL(lprocfs_stime_record);
-#endif /* LPROC_SNMP */
+unsigned long lprocfs_stime_avg_ms(struct obd_service_time *stime)
+{
+ struct obd_service_time copy;
-EXPORT_SYMBOL(lprocfs_reg_obd);
-EXPORT_SYMBOL(lprocfs_dereg_obd);
-EXPORT_SYMBOL(lprocfs_reg_main);
-EXPORT_SYMBOL(lprocfs_dereg_main);
-EXPORT_SYMBOL(lprocfs_reg_mnt);
-EXPORT_SYMBOL(lprocfs_dereg_mnt);
+ memcpy(©, stime, sizeof(copy));
+ if (copy.st_num > 0) {
+ do_div(copy.st_total_us, copy.st_num * 1000);
+ return (unsigned long)copy.st_total_us;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(lprocfs_stime_avg_ms);
+
+unsigned long lprocfs_stime_avg_us(struct obd_service_time *stime)
+{
+ struct obd_service_time copy;
+ __u32 remainder;
+
+ memcpy(©, stime, sizeof(copy));
+ if (copy.st_num > 0) {
+ do_div(copy.st_total_us, copy.st_num);
+ remainder = do_div(copy.st_total_us, 1000);
+ return (unsigned long)remainder;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(lprocfs_stime_avg_us);
+
+int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct obd_device *obd = data;
+ int len = 0, n,
+ connected = obd->obd_connected_clients,
+ max_recoverable = obd->obd_max_recoverable_clients,
+ recoverable = obd->obd_recoverable_clients,
+ completed = max_recoverable - recoverable,
+ queue_len = obd->obd_requests_queued_for_recovery,
+ replayed = obd->obd_replayed_requests;
+ __u64 next_transno = obd->obd_next_recovery_transno;
+
+ LASSERT(obd != NULL);
+ *eof = 1;
+
+ n = snprintf(page, count, "status: ");
+ page += n; len += n; count -= n;
+ if (obd->obd_max_recoverable_clients == 0) {
+ n = snprintf(page, count, "INACTIVE\n");
+ return len + n;
+ }
+
+ /* sampled unlocked, but really... */
+ if (obd->obd_recovering == 0) {
+ n = snprintf(page, count, "COMPLETE\n");
+ page += n; len += n; count -= n;
+
+ n = snprintf(page, count, "recovery_start: %lu\n",
+ obd->obd_recovery_start);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "recovery_end: %lu\n",
+ obd->obd_recovery_end);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "recovered_clients: %d\n",
+ completed);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "unrecovered_clients: %d\n",
+ obd->obd_recoverable_clients);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "last_transno: "LPD64"\n",
+ next_transno - 1);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "replayed_requests: %d\n", replayed);
+ return len + n;
+ }
+
+ n = snprintf(page, count, "RECOVERING\n");
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "recovery_start: %lu\n",
+ obd->obd_recovery_start);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "connected_clients: %d/%d\n",
+ connected, max_recoverable);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "completed_clients: %d/%d\n",
+ completed, max_recoverable);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "replayed_requests: %d/??\n", replayed);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "queued_requests: %d\n", queue_len);
+ page += n; len += n; count -= n;
+ n = snprintf(page, count, "next_transno: "LPD64"\n", next_transno);
+ return len + n;
+}
+EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
+#endif /* LPROCFS*/
+
+EXPORT_SYMBOL(lprocfs_register);
+EXPORT_SYMBOL(lprocfs_srch);
+EXPORT_SYMBOL(lprocfs_remove);
EXPORT_SYMBOL(lprocfs_add_vars);
-EXPORT_SYMBOL(lprocfs_reg_class);
-EXPORT_SYMBOL(lprocfs_dereg_class);
-EXPORT_SYMBOL(lprocfs_ll_rd);
+EXPORT_SYMBOL(lprocfs_obd_attach);
+EXPORT_SYMBOL(lprocfs_obd_detach);
+EXPORT_SYMBOL(lprocfs_alloc_stats);
+EXPORT_SYMBOL(lprocfs_free_stats);
+EXPORT_SYMBOL(lprocfs_register_stats);
+EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
+EXPORT_SYMBOL(lprocfs_free_obd_stats);
+EXPORT_SYMBOL(lprocfs_alloc_md_stats);
+EXPORT_SYMBOL(lprocfs_free_md_stats);
+
+EXPORT_SYMBOL(lprocfs_rd_u64);
+EXPORT_SYMBOL(lprocfs_rd_uuid);
+EXPORT_SYMBOL(lprocfs_rd_name);
+EXPORT_SYMBOL(lprocfs_rd_fstype);
+EXPORT_SYMBOL(lprocfs_rd_server_uuid);
+EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
+EXPORT_SYMBOL(lprocfs_rd_num_exports);
+EXPORT_SYMBOL(lprocfs_rd_numrefs);
+EXPORT_SYMBOL(lprocfs_rd_blksize);
+EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
+EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
+EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
+EXPORT_SYMBOL(lprocfs_rd_filestotal);
+EXPORT_SYMBOL(lprocfs_rd_filesfree);
+EXPORT_SYMBOL(lprocfs_write_helper);
+EXPORT_SYMBOL(lprocfs_write_u64_helper);