Whamcloud - gitweb
LU-3319 lprocfs: client side cleanups
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index ad145c8..973fd0b 100644 (file)
@@ -1,6 +1,4 @@
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
  * GPL HEADER START
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -28,6 +26,8 @@
 /*
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2013, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
  */
 
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_CLASS
 
 #ifndef __KERNEL__
-# include <liblustre.h>
+#include <liblustre.h>
 #endif
 
 #include <obd_class.h>
 #include <lprocfs_status.h>
-#include <lustre_fsfilt.h>
-#include <lustre_log.h>
 #include <lustre/lustre_idl.h>
 
 #if defined(LPROCFS)
 
+static int lprocfs_no_percpu_stats = 0;
+CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
+                "Do not alloc percpu data for lprocfs stats");
+
 #define MAX_STRING_SIZE 128
 
-/* for bug 10866, global variable */
-CFS_DECLARE_RWSEM(_lprocfs_lock);
-EXPORT_SYMBOL(_lprocfs_lock);
+int lprocfs_single_release(struct inode *inode, struct file *file)
+{
+        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);
 
-struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
-                                    const char *name)
+#ifndef HAVE_ONLY_PROCFS_SEQ
+/* for b=10866, global variable */
+DECLARE_RWSEM(_lprocfs_lock);
+EXPORT_SYMBOL(_lprocfs_lock);
+
+static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
+                                             const char *name)
 {
         struct proc_dir_entry *temp;
 
         if (head == NULL)
                 return NULL;
-        LPROCFS_ENTRY();
 
         temp = head->subdir;
         while (temp != NULL) {
                 if (strcmp(temp->name, name) == 0) {
-                        LPROCFS_EXIT();
                         return temp;
                 }
 
                 temp = temp->next;
         }
-        LPROCFS_EXIT();
         return NULL;
 }
 
+struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
+                                    const char *name)
+{
+        struct proc_dir_entry *temp;
+
+        LPROCFS_SRCH_ENTRY();
+        temp = __lprocfs_srch(head, name);
+        LPROCFS_SRCH_EXIT();
+        return temp;
+}
+EXPORT_SYMBOL(lprocfs_srch);
+
 /* lprocfs API calls */
 
 /* Function that emulates snprintf but also has the side effect of advancing
    the page pointer for the next write into the buffer, incrementing the total
    length written to the buffer, and decrementing the size left in the
    buffer. */
+#ifdef HAVE_SERVER_SUPPORT
 static int lprocfs_obd_snprintf(char **page, int end, int *len,
                                 const char *format, ...)
 {
@@ -112,11 +127,15 @@ static int lprocfs_obd_snprintf(char **page, int end, int *len,
         *page += n; *len += n;
         return n;
 }
+#endif /* HAVE_SERVER_SUPPORT */
+#endif /* HAVE_ONLY_PROCFS_SEQ */
 
 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
                                          char *name,
-                                         read_proc_t *read_proc,
-                                         write_proc_t *write_proc,
+#ifndef HAVE_ONLY_PROCFS_SEQ
+                                        read_proc_t *read_proc,
+                                        write_proc_t *write_proc,
+#endif
                                          void *data,
                                          struct file_operations *fops)
 {
@@ -125,24 +144,43 @@ cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
 
         if (root == NULL || name == NULL)
                 return ERR_PTR(-EINVAL);
-        if (read_proc)
-                mode = 0444;
-        if (write_proc)
-                mode |= 0200;
-        if (fops)
-                mode = 0644;
-        proc = create_proc_entry(name, mode, root);
-        if (!proc) {
-                CERROR("LprocFS: No memory to create /proc entry %s", name);
-                return ERR_PTR(-ENOMEM);
-        }
-        proc->read_proc = read_proc;
-        proc->write_proc = write_proc;
-        proc->data = data;
-        if (fops)
-                proc->proc_fops = fops;
+
+       if (!fops) {
+#ifndef HAVE_ONLY_PROCFS_SEQ
+               if (read_proc)
+                       mode = 0444;
+               if (write_proc)
+                       mode |= 0200;
+
+               LPROCFS_WRITE_ENTRY();
+               proc = create_proc_entry(name, mode, root);
+               if (!proc) {
+                       CERROR("LprocFS: No memory to create /proc entry %s", name);
+                       LPROCFS_WRITE_EXIT();
+                       return ERR_PTR(-ENOMEM);
+               }
+               proc->read_proc = read_proc;
+               proc->write_proc = write_proc;
+               proc->data = data;
+               LPROCFS_WRITE_EXIT();
+#else
+               return ERR_PTR(-EINVAL);
+#endif
+       } else {
+               if (fops->read)
+                       mode = 0444;
+               if (fops->write)
+                       mode |= 0200;
+               proc = proc_create_data(name, mode, root, fops, data);
+               if (!proc) {
+                       CERROR("LprocFS: No memory to create /proc entry %s",
+                              name);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
         return proc;
 }
+EXPORT_SYMBOL(lprocfs_add_simple);
 
 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
                         struct proc_dir_entry *parent, const char *format, ...)
@@ -170,7 +208,9 @@ struct proc_dir_entry *lprocfs_add_symlink(const char *name,
         OBD_FREE(dest, MAX_STRING_SIZE + 1);
         return entry;
 }
+EXPORT_SYMBOL(lprocfs_add_symlink);
 
+#ifndef HAVE_ONLY_PROCFS_SEQ
 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
                                  size_t size, loff_t *ppos)
 {
@@ -178,23 +218,22 @@ static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
         char *page, *start = NULL;
         int rc = 0, eof = 1, count;
 
-        if (*ppos >= CFS_PAGE_SIZE)
+       if (*ppos >= PAGE_CACHE_SIZE)
                 return 0;
 
         page = (char *)__get_free_page(GFP_KERNEL);
         if (page == NULL)
                 return -ENOMEM;
 
-        if (LPROCFS_ENTRY_AND_CHECK(dp)) {
+       if (LPROCFS_ENTRY_CHECK(dp)) {
                 rc = -ENOENT;
                 goto out;
         }
 
         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
         if (dp->read_proc)
-                rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
+               rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
                                    &eof, dp->data);
-        LPROCFS_EXIT();
         if (rc <= 0)
                 goto out;
 
@@ -213,7 +252,7 @@ static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
         }
 
         count = (rc < size) ? rc : size;
-        if (cfs_copy_to_user(buf, start, count)) {
+       if (copy_to_user(buf, start, count)) {
                 rc = -EFAULT;
                 goto out;
         }
@@ -230,11 +269,10 @@ static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
         int rc = -EIO;
 
-        if (LPROCFS_ENTRY_AND_CHECK(dp))
+       if (LPROCFS_ENTRY_CHECK(dp))
                 return -ENOENT;
         if (dp->write_proc)
                 rc = dp->write_proc(f, buf, size, dp->data);
-        LPROCFS_EXIT();
         return rc;
 }
 
@@ -243,28 +281,112 @@ static struct file_operations lprocfs_generic_fops = {
         .read = lprocfs_fops_read,
         .write = lprocfs_fops_write,
 };
+#else
+static struct file_operations lprocfs_generic_fops = { };
+#endif
 
+#ifdef HAVE_SERVER_SUPPORT
 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
 {
-        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
-        struct obd_device *obd = dp->data;
+       struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
 
-        cfs_atomic_inc(&obd->obd_evict_inprogress);
-
-        return 0;
+       atomic_inc(&obd->obd_evict_inprogress);
+       return 0;
 }
 
 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
 {
-        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
-        struct obd_device *obd = dp->data;
+       struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
 
-        cfs_atomic_dec(&obd->obd_evict_inprogress);
-        cfs_waitq_signal(&obd->obd_evict_inprogress_waitq);
+       atomic_dec(&obd->obd_evict_inprogress);
+       wake_up(&obd->obd_evict_inprogress_waitq);
 
-        return 0;
+       return 0;
 }
 
+#define BUFLEN (UUID_MAX + 5)
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
+int lprocfs_wr_evict_client(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+       struct obd_device *obd = data;
+       char              *kbuf;
+       char              *tmpbuf;
+
+       OBD_ALLOC(kbuf, BUFLEN);
+       if (kbuf == NULL)
+               return -ENOMEM;
+
+       /*
+        * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
+        * bytes into kbuf, to ensure that the string is NUL-terminated.
+        * UUID_MAX should include a trailing NUL already.
+        */
+       if (copy_from_user(kbuf, buffer,
+                          min_t(unsigned long, BUFLEN - 1, count))) {
+               count = -EFAULT;
+               goto out;
+       }
+       tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
+       class_incref(obd, __FUNCTION__, current);
+
+       if (strncmp(tmpbuf, "nid:", 4) == 0)
+               obd_export_evict_by_nid(obd, tmpbuf + 4);
+       else if (strncmp(tmpbuf, "uuid:", 5) == 0)
+               obd_export_evict_by_uuid(obd, tmpbuf + 5);
+       else
+               obd_export_evict_by_uuid(obd, tmpbuf);
+
+       class_decref(obd, __FUNCTION__, current);
+out:
+       OBD_FREE(kbuf, BUFLEN);
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_wr_evict_client);
+#endif
+
+ssize_t
+lprocfs_evict_client_seq_write(struct file *file, const char *buffer,
+                              size_t count, loff_t *off)
+{
+       struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
+       char *tmpbuf, *kbuf;
+
+       OBD_ALLOC(kbuf, BUFLEN);
+       if (kbuf == NULL)
+               return -ENOMEM;
+
+       /*
+        * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
+        * bytes into kbuf, to ensure that the string is NUL-terminated.
+        * UUID_MAX should include a trailing NUL already.
+        */
+       if (copy_from_user(kbuf, buffer,
+                          min_t(unsigned long, BUFLEN - 1, count))) {
+               count = -EFAULT;
+               goto out;
+       }
+       tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
+       class_incref(obd, __FUNCTION__, current);
+
+       if (strncmp(tmpbuf, "nid:", 4) == 0)
+               obd_export_evict_by_nid(obd, tmpbuf + 4);
+       else if (strncmp(tmpbuf, "uuid:", 5) == 0)
+               obd_export_evict_by_uuid(obd, tmpbuf + 5);
+       else
+               obd_export_evict_by_uuid(obd, tmpbuf);
+
+       class_decref(obd, __FUNCTION__, current);
+
+out:
+       OBD_FREE(kbuf, BUFLEN);
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_evict_client_seq_write);
+
+#undef BUFLEN
+
 struct file_operations lprocfs_evict_client_fops = {
         .owner = THIS_MODULE,
         .read = lprocfs_fops_read,
@@ -273,21 +395,15 @@ struct file_operations lprocfs_evict_client_fops = {
         .release = lprocfs_evict_client_release,
 };
 EXPORT_SYMBOL(lprocfs_evict_client_fops);
+#endif
 
-/**
- * Add /proc entries.
- *
- * \param root [in]  The parent proc entry on which new entry will be added.
- * \param list [in]  Array of proc entries to be added.
- * \param data [in]  The argument to be passed when entries read/write routines
- *                   are called through /proc file.
- *
- * \retval 0   on success
- *         < 0 on error
- */
-int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
-                     void *data)
+#ifndef HAVE_ONLY_PROCFS_SEQ
+static int __lprocfs_add_vars(struct proc_dir_entry *root,
+                             struct lprocfs_vars *list,
+                             void *data)
 {
+        int rc = 0;
+
         if (root == NULL || list == NULL)
                 return -EINVAL;
 
@@ -303,7 +419,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
                         OBD_ALLOC(pathcopy, pathsize);
                         if (pathcopy == NULL)
-                                return -ENOMEM;
+                                GOTO(out, rc = -ENOMEM);
                 } else {
                         pathcopy = pathbuf;
                 }
@@ -315,7 +431,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                         if (*cur =='\0') /* skip double/trailing "/" */
                                 continue;
 
-                        proc = lprocfs_srch(cur_root, cur);
+                        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"));
@@ -342,7 +458,7 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 if (cur_root == NULL || proc == NULL) {
                         CERROR("LprocFS: No memory to create /proc entry %s",
                                list->name);
-                        return -ENOMEM;
+                        GOTO(out, rc = -ENOMEM);
                 }
 
                 if (list->fops)
@@ -354,23 +470,80 @@ int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
                 proc->data = (list->data ? list->data : data);
                 list++;
         }
-        return 0;
+out:
+        return rc;
 }
 
-void lprocfs_remove(struct proc_dir_entry **rooth)
+int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
+                    void *data)
 {
-        struct proc_dir_entry *root = *rooth;
-        struct proc_dir_entry *temp = root;
-        struct proc_dir_entry *rm_entry;
-        struct proc_dir_entry *parent;
+       int rc = 0;
 
-        if (!root)
-                return;
-        *rooth = NULL;
+       LPROCFS_WRITE_ENTRY();
+       rc = __lprocfs_add_vars(root, list, data);
+       LPROCFS_WRITE_EXIT();
+
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_add_vars);
+
+#endif
+
+/**
+ * Add /proc entries.
+ *
+ * \param root [in]  The parent proc entry on which new entry will be added.
+ * \param list [in]  Array of proc entries to be added.
+ * \param data [in]  The argument to be passed when entries read/write routines
+ *                   are called through /proc file.
+ *
+ * \retval 0   on success
+ *         < 0 on error
+ */
+int
+lprocfs_seq_add_vars(struct proc_dir_entry *root, struct lprocfs_seq_vars *list,
+                    void *data)
+{
+       if (root == NULL || list == NULL)
+               return -EINVAL;
+
+       while (list->name != NULL) {
+               struct proc_dir_entry *proc;
+               mode_t mode = 0;
+
+               if (list->proc_mode != 0000) {
+                       mode = list->proc_mode;
+               } else if (list->fops) {
+                       if (list->fops->read)
+                               mode = 0444;
+                       if (list->fops->write)
+                               mode |= 0200;
+               }
+               proc = proc_create_data(list->name, mode, root,
+                                       list->fops ?: &lprocfs_generic_fops,
+                                       list->data ?: data);
+               if (proc == NULL)
+                       return -ENOMEM;
+               list++;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_seq_add_vars);
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
+void lprocfs_remove_nolock(struct proc_dir_entry **proot)
+{
+       struct proc_dir_entry *root = *proot;
+       struct proc_dir_entry *temp = root;
+       struct proc_dir_entry *rm_entry;
+       struct proc_dir_entry *parent;
+
+       *proot = NULL;
+       if (root == NULL || IS_ERR(root))
+               return;
 
         parent = root->parent;
         LASSERT(parent != NULL);
-        LPROCFS_WRITE_ENTRY(); /* search vs remove race */
 
         while (1) {
                 while (temp->subdir != NULL)
@@ -385,53 +558,136 @@ 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));
 
-                /* Now, the rm_entry->deleted flags is protected
-                 * by _lprocfs_lock. */
-                rm_entry->data = NULL;
                 remove_proc_entry(rm_entry->name, temp);
                 if (temp == parent)
                         break;
         }
-        LPROCFS_WRITE_EXIT();
 }
+#endif
+
+void lprocfs_remove(struct proc_dir_entry **rooth)
+{
+#ifndef HAVE_ONLY_PROCFS_SEQ
+       LPROCFS_WRITE_ENTRY(); /* search vs remove race */
+       lprocfs_remove_nolock(rooth);
+       LPROCFS_WRITE_EXIT();
+#else
+       proc_remove(*rooth);
+       *rooth = NULL;
+#endif
+}
+EXPORT_SYMBOL(lprocfs_remove);
 
 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 {
         LASSERT(parent != NULL);
         remove_proc_entry(name, parent);
 }
+EXPORT_SYMBOL(lprocfs_remove_proc_entry);
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
+void lprocfs_try_remove_proc_entry(const char *name,
+                                  struct proc_dir_entry *parent)
+{
+       struct proc_dir_entry    *t = NULL;
+       struct proc_dir_entry   **p;
+       int                       len, busy = 0;
+
+       LASSERT(parent != NULL);
+       len = strlen(name);
+
+       LPROCFS_WRITE_ENTRY();
+
+       /* lookup target name */
+       for (p = &parent->subdir; *p; p = &(*p)->next) {
+               if ((*p)->namelen != len)
+                       continue;
+               if (memcmp(name, (*p)->name, len))
+                       continue;
+               t = *p;
+               break;
+       }
+
+       if (t) {
+               /* verify it's empty: do not count "num_refs" */
+               for (p = &t->subdir; *p; p = &(*p)->next) {
+                       if ((*p)->namelen != strlen("num_refs")) {
+                               busy = 1;
+                               break;
+                       }
+                       if (memcmp("num_refs", (*p)->name,
+                                  strlen("num_refs"))) {
+                               busy = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (busy == 0)
+               lprocfs_remove_nolock(&t);
+
+       LPROCFS_WRITE_EXIT();
+
+       return;
+}
+EXPORT_SYMBOL(lprocfs_try_remove_proc_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;
+                                       struct proc_dir_entry *parent,
+                                       struct lprocfs_vars *list, void *data)
+{
+       struct proc_dir_entry *entry;
+       int rc;
+
+       LPROCFS_WRITE_ENTRY();
+       entry = __lprocfs_srch(parent, name);
+       if (entry != NULL) {
+               CERROR("entry '%s' already registered\n", name);
+               GOTO(out, entry = ERR_PTR(-EALREADY));
+       }
+
+       entry = proc_mkdir(name, parent);
+       if (entry == NULL)
+               GOTO(out, entry = ERR_PTR(-ENOMEM));
+
+       if (list != NULL) {
+               rc = __lprocfs_add_vars(entry, list, data);
+               if (rc != 0) {
+                       lprocfs_remove_nolock(&entry);
+                       GOTO(out, entry = ERR_PTR(rc));
+               }
+       }
+out:
+       LPROCFS_WRITE_EXIT();
+       return entry;
+}
+EXPORT_SYMBOL(lprocfs_register);
+#endif
 
-        newchild = lprocfs_srch(parent, name);
-        if (newchild != NULL) {
-                CERROR(" Lproc: Attempting to register %s more than once \n",
-                       name);
-                return ERR_PTR(-EALREADY);
-        }
+struct proc_dir_entry *
+lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
+                    struct lprocfs_seq_vars *list, void *data)
+{
+       struct proc_dir_entry *newchild;
 
-        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);
-                }
-        }
-        return newchild;
+       newchild = proc_mkdir(name, parent);
+       if (newchild != NULL && list != NULL) {
+               int rc = lprocfs_seq_add_vars(newchild, list, data);
+               if (rc) {
+                       lprocfs_remove(&newchild);
+                       return ERR_PTR(rc);
+               }
+       }
+       return newchild;
 }
+EXPORT_SYMBOL(lprocfs_seq_register);
 
 /* Generic callbacks */
-int lprocfs_rd_uint(char *page, char **start, off_t off,
-                    int count, int *eof, void *data)
+int lprocfs_uint_seq_show(struct seq_file *m, void *data)
 {
-        unsigned int *temp = data;
-        return snprintf(page, count, "%u\n", *temp);
+       return seq_printf(m, "%u\n", *(unsigned int *)data);
 }
+EXPORT_SYMBOL(lprocfs_uint_seq_show);
 
 int lprocfs_wr_uint(struct file *file, const char *buffer,
                     unsigned long count, void *data)
@@ -441,7 +697,7 @@ int lprocfs_wr_uint(struct file *file, const char *buffer,
         unsigned long tmp;
 
         dummy[MAX_STRING_SIZE] = '\0';
-        if (cfs_copy_from_user(dummy, buffer, MAX_STRING_SIZE))
+       if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
                 return -EFAULT;
 
         tmp = simple_strtoul(dummy, &end, 0);
@@ -451,6 +707,678 @@ int lprocfs_wr_uint(struct file *file, const char *buffer,
         *p = (unsigned int)tmp;
         return count;
 }
+EXPORT_SYMBOL(lprocfs_wr_uint);
+
+ssize_t lprocfs_uint_seq_write(struct file *file, const char *buffer,
+                              size_t count, loff_t *off)
+{
+       int *data = ((struct seq_file *)file->private_data)->private;
+       int val = 0, rc;
+
+       rc = lprocfs_write_helper(buffer, count, &val);
+       if (rc < 0)
+               return rc;
+
+       return lprocfs_wr_uint(file, buffer, count, data);
+}
+EXPORT_SYMBOL(lprocfs_uint_seq_write);
+
+int lprocfs_u64_seq_show(struct seq_file *m, void *data)
+{
+       LASSERT(data != NULL);
+       return seq_printf(m, LPU64"\n", *(__u64 *)data);
+}
+EXPORT_SYMBOL(lprocfs_u64_seq_show);
+
+int lprocfs_atomic_seq_show(struct seq_file *m, void *data)
+{
+       atomic_t *atom = data;
+       LASSERT(atom != NULL);
+       return seq_printf(m, "%d\n", atomic_read(atom));
+}
+EXPORT_SYMBOL(lprocfs_atomic_seq_show);
+
+ssize_t
+lprocfs_atomic_seq_write(struct file *file, const char *buffer,
+                       size_t count, loff_t *off)
+{
+       atomic_t *atm = ((struct seq_file *)file->private_data)->private;
+       int val = 0;
+       int rc;
+
+       rc = lprocfs_write_helper(buffer, count, &val);
+       if (rc < 0)
+               return rc;
+
+       if (val <= 0)
+               return -ERANGE;
+
+       atomic_set(atm, val);
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_atomic_seq_write);
+
+int lprocfs_uuid_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+
+       LASSERT(obd != NULL);
+       return seq_printf(m, "%s\n", obd->obd_uuid.uuid);
+}
+EXPORT_SYMBOL(lprocfs_uuid_seq_show);
+
+int lprocfs_name_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *dev = data;
+
+       LASSERT(dev != NULL);
+       return seq_printf(m, "%s\n", dev->obd_name);
+}
+EXPORT_SYMBOL(lprocfs_name_seq_show);
+
+int lprocfs_blksize_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc)
+               rc = seq_printf(m, "%u\n", osfs.os_bsize);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_blksize_seq_show);
+
+int lprocfs_kbytestotal_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_blocks;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               rc = seq_printf(m, LPU64"\n", result);
+       }
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_kbytestotal_seq_show);
+
+int lprocfs_kbytesfree_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_bfree;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               rc = seq_printf(m, LPU64"\n", result);
+       }
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_kbytesfree_seq_show);
+
+int lprocfs_kbytesavail_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_bavail;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               rc = seq_printf(m, LPU64"\n", result);
+       }
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_kbytesavail_seq_show);
+
+int lprocfs_filestotal_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc)
+               rc = seq_printf(m, LPU64"\n", osfs.os_files);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_filestotal_seq_show);
+
+int lprocfs_filesfree_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_statfs  osfs;
+       int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
+                           cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
+                           OBD_STATFS_NODELAY);
+       if (!rc)
+               rc = seq_printf(m, LPU64"\n", osfs.os_ffree);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_filesfree_seq_show);
+
+int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct obd_import *imp;
+       char *imp_state_name = NULL;
+       int rc = 0;
+
+       LASSERT(obd != NULL);
+       LPROCFS_CLIMP_CHECK(obd);
+       imp = obd->u.cli.cl_import;
+       imp_state_name = ptlrpc_import_state_name(imp->imp_state);
+       rc = seq_printf(m, "%s\t%s%s\n", obd2cli_tgt(obd), imp_state_name,
+                       imp->imp_deactive ? "\tDEACTIVATED" : "");
+
+       LPROCFS_CLIMP_EXIT(obd);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_server_uuid_seq_show);
+
+int lprocfs_conn_uuid_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       struct ptlrpc_connection *conn;
+       int rc = 0;
+
+       LASSERT(obd != NULL);
+
+       LPROCFS_CLIMP_CHECK(obd);
+       conn = obd->u.cli.cl_import->imp_connection;
+       if (conn && obd->u.cli.cl_import)
+               rc = seq_printf(m, "%s\n", conn->c_remote_uuid.uuid);
+       else
+               rc = seq_printf(m, "%s\n", "<none>");
+
+       LPROCFS_CLIMP_EXIT(obd);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_conn_uuid_seq_show);
+
+/** add up per-cpu counters */
+void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
+                          struct lprocfs_counter *cnt)
+{
+       unsigned int                    num_entry;
+       struct lprocfs_counter          *percpu_cntr;
+       int                             i;
+       unsigned long                   flags = 0;
+
+       memset(cnt, 0, sizeof(*cnt));
+
+       if (stats == NULL) {
+               /* set count to 1 to avoid divide-by-zero errs in callers */
+               cnt->lc_count = 1;
+               return;
+       }
+
+       cnt->lc_min = LC_MIN_INIT;
+
+       num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+
+       for (i = 0; i < num_entry; i++) {
+               if (stats->ls_percpu[i] == NULL)
+                       continue;
+               percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
+
+               cnt->lc_count += percpu_cntr->lc_count;
+               cnt->lc_sum += percpu_cntr->lc_sum;
+               if (percpu_cntr->lc_min < cnt->lc_min)
+                       cnt->lc_min = percpu_cntr->lc_min;
+               if (percpu_cntr->lc_max > cnt->lc_max)
+                       cnt->lc_max = percpu_cntr->lc_max;
+               cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
+       }
+
+       lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
+}
+EXPORT_SYMBOL(lprocfs_stats_collect);
+
+/**
+ * Append a space separated list of current set flags to str.
+ */
+#define flag2seqstr(flag)                                              \
+       do {                                                            \
+               if (imp->imp_##flag)                                    \
+                       seq_printf(m, "%s" #flag, first ? "" : ", ");   \
+       } while (0)
+static int obd_import_flags2seqstr(struct obd_import *imp, struct seq_file *m)
+{
+       bool first = true;
+
+       if (imp->imp_obd->obd_no_recov) {
+               seq_printf(m, "no_recov");
+               first = false;
+       }
+
+       flag2seqstr(invalid);
+       flag2seqstr(deactive);
+       flag2seqstr(replayable);
+       flag2seqstr(pingable);
+       return 0;
+}
+#undef flags2seqstr
+
+static const char *obd_connect_names[] = {
+       "read_only",
+       "lov_index",
+       "connect_from_mds",
+       "write_grant",
+       "server_lock",
+       "version",
+       "request_portal",
+       "acl",
+       "xattr",
+       "create_on_write",
+       "truncate_lock",
+       "initial_transno",
+       "inode_bit_locks",
+       "join_file(obsolete)",
+       "getattr_by_fid",
+       "no_oh_for_devices",
+       "remote_client",
+       "remote_client_by_force",
+       "max_byte_per_rpc",
+       "64bit_qdata",
+       "mds_capability",
+       "oss_capability",
+       "early_lock_cancel",
+       "som",
+       "adaptive_timeouts",
+       "lru_resize",
+       "mds_mds_connection",
+       "real_conn",
+       "change_qunit_size",
+       "alt_checksum_algorithm",
+       "fid_is_enabled",
+       "version_recovery",
+       "pools",
+       "grant_shrink",
+       "skip_orphan",
+       "large_ea",
+       "full20",
+       "layout_lock",
+       "64bithash",
+       "object_max_bytes",
+       "imp_recov",
+       "jobstats",
+       "umask",
+       "einprogress",
+       "grant_param",
+       "flock_owner",
+       "lvb_type",
+       "nanoseconds_times",
+       "lightweight_conn",
+       "short_io",
+       "pingless",
+       "flock_deadlock",
+       "disp_stripe",
+       "unknown",
+       NULL
+};
+
+static void obd_connect_seq_flags2str(struct seq_file *m, __u64 flags, char *sep)
+{
+       bool first = true;
+       __u64 mask = 1;
+       int i;
+
+       for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
+               if (flags & mask) {
+                       seq_printf(m, "%s%s",
+                                  first ? "" : sep, obd_connect_names[i]);
+                       first = false;
+               }
+       }
+       if (flags & ~(mask - 1))
+               seq_printf(m, "%sunknown flags "LPX64,
+                          first ? "" : sep, flags & ~(mask - 1));
+}
+
+int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
+{
+       __u64 mask = 1;
+       int i, ret = 0;
+
+       for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
+               if (flags & mask)
+                       ret += snprintf(page + ret, count - ret, "%s%s",
+                                       ret ? sep : "", obd_connect_names[i]);
+       }
+       if (flags & ~(mask - 1))
+               ret += snprintf(page + ret, count - ret,
+                               "%sunknown flags "LPX64,
+                               ret ? sep : "", flags & ~(mask - 1));
+       return ret;
+}
+EXPORT_SYMBOL(obd_connect_flags2str);
+
+static void obd_connect_data_seqprint(struct seq_file *m,
+                                     struct obd_connect_data *ocd)
+{
+       int flags;
+
+       LASSERT(ocd != NULL);
+       flags = ocd->ocd_connect_flags;
+
+       seq_printf(m, "    connect_data:\n"
+                     "       flags: "LPX64"\n"
+                     "       instance: %u\n",
+                     ocd->ocd_connect_flags,
+                     ocd->ocd_instance);
+       if (flags & OBD_CONNECT_VERSION)
+               seq_printf(m, "       target_version: %u.%u.%u.%u\n",
+                             OBD_OCD_VERSION_MAJOR(ocd->ocd_version),
+                             OBD_OCD_VERSION_MINOR(ocd->ocd_version),
+                             OBD_OCD_VERSION_PATCH(ocd->ocd_version),
+                             OBD_OCD_VERSION_FIX(ocd->ocd_version));
+       if (flags & OBD_CONNECT_MDS)
+               seq_printf(m, "       mdt_index: %d\n", ocd->ocd_group);
+       if (flags & OBD_CONNECT_GRANT)
+               seq_printf(m, "       initial_grant: %d\n", ocd->ocd_grant);
+       if (flags & OBD_CONNECT_INDEX)
+               seq_printf(m, "       target_index: %u\n", ocd->ocd_index);
+       if (flags & OBD_CONNECT_BRW_SIZE)
+               seq_printf(m, "       max_brw_size: %d\n", ocd->ocd_brw_size);
+       if (flags & OBD_CONNECT_IBITS)
+               seq_printf(m, "       ibits_known: "LPX64"\n",
+                               ocd->ocd_ibits_known);
+       if (flags & OBD_CONNECT_GRANT_PARAM)
+               seq_printf(m, "       grant_block_size: %d\n"
+                             "       grant_inode_size: %d\n"
+                             "       grant_extent_overhead: %d\n",
+                             ocd->ocd_blocksize,
+                             ocd->ocd_inodespace,
+                             ocd->ocd_grant_extent);
+       if (flags & OBD_CONNECT_TRANSNO)
+               seq_printf(m, "       first_transno: "LPX64"\n",
+                               ocd->ocd_transno);
+       if (flags & OBD_CONNECT_CKSUM)
+               seq_printf(m, "       cksum_types: %#x\n",
+                             ocd->ocd_cksum_types);
+       if (flags & OBD_CONNECT_MAX_EASIZE)
+               seq_printf(m, "       max_easize: %d\n", ocd->ocd_max_easize);
+       if (flags & OBD_CONNECT_MAXBYTES)
+               seq_printf(m, "       max_object_bytes: "LPU64"\n",
+                             ocd->ocd_maxbytes);
+}
+
+int lprocfs_import_seq_show(struct seq_file *m, void *data)
+{
+       struct lprocfs_counter          ret;
+       struct lprocfs_counter_header   *header;
+       struct obd_device               *obd    = (struct obd_device *)data;
+       struct obd_import               *imp;
+       struct obd_import_conn          *conn;
+       struct obd_connect_data         *ocd;
+       int                             j;
+       int                             k;
+       int                             rw      = 0;
+
+       LASSERT(obd != NULL);
+       LPROCFS_CLIMP_CHECK(obd);
+       imp = obd->u.cli.cl_import;
+       ocd = &imp->imp_connect_data;
+
+       seq_printf(m, "import:\n"
+                     "    name: %s\n"
+                     "    target: %s\n"
+                     "    state: %s\n"
+                     "    connect_flags: [",
+                     obd->obd_name,
+                     obd2cli_tgt(obd),
+                     ptlrpc_import_state_name(imp->imp_state));
+       obd_connect_seq_flags2str(m, imp->imp_connect_data.ocd_connect_flags,
+                                       ", ");
+       seq_printf(m, "]\n");
+       obd_connect_data_seqprint(m, ocd);
+       seq_printf(m, "    import_flags: [");
+       obd_import_flags2seqstr(imp, m);
+
+       seq_printf(m, "]\n"
+                     "    connection:\n"
+                     "       failover_nids: [");
+       spin_lock(&imp->imp_lock);
+       j = 0;
+       list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
+               seq_printf(m, "%s%s", j ? ", " : "",
+                          libcfs_nid2str(conn->oic_conn->c_peer.nid));
+               j++;
+       }
+       seq_printf(m, "]\n"
+                     "       current_connection: %s\n"
+                     "       connection_attempts: %u\n"
+                     "       generation: %u\n"
+                     "       in-progress_invalidations: %u\n",
+                     imp->imp_connection == NULL ? "<none>" :
+                             libcfs_nid2str(imp->imp_connection->c_peer.nid),
+                     imp->imp_conn_cnt,
+                     imp->imp_generation,
+                     atomic_read(&imp->imp_inval_count));
+       spin_unlock(&imp->imp_lock);
+
+       if (obd->obd_svc_stats == NULL)
+               goto out_climp;
+
+       header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
+       lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
+       if (ret.lc_count != 0) {
+               /* first argument to do_div MUST be __u64 */
+               __u64 sum = ret.lc_sum;
+               do_div(sum, ret.lc_count);
+               ret.lc_sum = sum;
+       } else
+               ret.lc_sum = 0;
+       seq_printf(m, "    rpcs:\n"
+                     "       inflight: %u\n"
+                     "       unregistering: %u\n"
+                     "       timeouts: %u\n"
+                     "       avg_waittime: "LPU64" %s\n",
+                     atomic_read(&imp->imp_inflight),
+                     atomic_read(&imp->imp_unregistering),
+                     atomic_read(&imp->imp_timeouts),
+                     ret.lc_sum, header->lc_units);
+
+       k = 0;
+       for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
+               if (imp->imp_at.iat_portal[j] == 0)
+                       break;
+               k = max_t(unsigned int, k,
+                         at_get(&imp->imp_at.iat_service_estimate[j]));
+       }
+       seq_printf(m, "    service_estimates:\n"
+                     "       services: %u sec\n"
+                     "       network: %u sec\n",
+                     k,
+                     at_get(&imp->imp_at.iat_net_latency));
+
+       seq_printf(m, "    transactions:\n"
+                     "       last_replay: "LPU64"\n"
+                     "       peer_committed: "LPU64"\n"
+                     "       last_checked: "LPU64"\n",
+                     imp->imp_last_replay_transno,
+                     imp->imp_peer_committed_transno,
+                     imp->imp_last_transno_checked);
+
+       /* avg data rates */
+       for (rw = 0; rw <= 1; rw++) {
+               lprocfs_stats_collect(obd->obd_svc_stats,
+                                     PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
+                                     &ret);
+               if (ret.lc_sum > 0 && ret.lc_count > 0) {
+                       /* first argument to do_div MUST be __u64 */
+                       __u64 sum = ret.lc_sum;
+                       do_div(sum, ret.lc_count);
+                       ret.lc_sum = sum;
+                       seq_printf(m, "    %s_data_averages:\n"
+                                     "       bytes_per_rpc: "LPU64"\n",
+                                     rw ? "write" : "read",
+                                     ret.lc_sum);
+               }
+               k = (int)ret.lc_sum;
+               j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
+               header = &obd->obd_svc_stats->ls_cnt_header[j];
+               lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
+               if (ret.lc_sum > 0 && ret.lc_count != 0) {
+                       /* first argument to do_div MUST be __u64 */
+                       __u64 sum = ret.lc_sum;
+                       do_div(sum, ret.lc_count);
+                       ret.lc_sum = sum;
+                       seq_printf(m, "       %s_per_rpc: "LPU64"\n",
+                                       header->lc_units, ret.lc_sum);
+                       j = (int)ret.lc_sum;
+                       if (j > 0)
+                               seq_printf(m, "       MB_per_sec: %u.%.02u\n",
+                                               k / j, (100 * k / j) % 100);
+               }
+       }
+
+out_climp:
+       LPROCFS_CLIMP_EXIT(obd);
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_import_seq_show);
+
+int lprocfs_state_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = (struct obd_device *)data;
+       struct obd_import *imp;
+       int j, k;
+
+       LASSERT(obd != NULL);
+       LPROCFS_CLIMP_CHECK(obd);
+       imp = obd->u.cli.cl_import;
+
+       seq_printf(m, "current_state: %s\n",
+                  ptlrpc_import_state_name(imp->imp_state));
+       seq_printf(m, "state_history:\n");
+       k = imp->imp_state_hist_idx;
+       for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
+               struct import_state_hist *ish =
+                       &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
+               if (ish->ish_state == 0)
+                       continue;
+               seq_printf(m, " - ["CFS_TIME_T", %s]\n",
+                          ish->ish_time,
+               ptlrpc_import_state_name(ish->ish_state));
+       }
+
+       LPROCFS_CLIMP_EXIT(obd);
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_state_seq_show);
+
+int lprocfs_seq_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
+{
+       int i;
+       for (i = 0; i < AT_BINS; i++)
+               seq_printf(m, "%3u ", at->at_hist[i]);
+       seq_printf(m, "\n");
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_seq_at_hist_helper);
+
+/* See also ptlrpc_lprocfs_timeouts_show_seq */
+int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = (struct obd_device *)data;
+       struct obd_import *imp;
+       unsigned int cur, worst;
+       time_t now, worstt;
+       struct dhms ts;
+       int i;
+
+       LASSERT(obd != NULL);
+       LPROCFS_CLIMP_CHECK(obd);
+       imp = obd->u.cli.cl_import;
+
+       now = cfs_time_current_sec();
+
+       /* Some network health info for kicks */
+       s2dhms(&ts, now - imp->imp_last_reply_time);
+       seq_printf(m, "%-10s : %ld, "DHMS_FMT" ago\n",
+                  "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
+
+       cur = at_get(&imp->imp_at.iat_net_latency);
+       worst = imp->imp_at.iat_net_latency.at_worst_ever;
+       worstt = imp->imp_at.iat_net_latency.at_worst_time;
+       s2dhms(&ts, now - worstt);
+       seq_printf(m, "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
+                  "network", cur, worst, worstt, DHMS_VARS(&ts));
+       lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_net_latency);
+
+       for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
+               if (imp->imp_at.iat_portal[i] == 0)
+                       break;
+               cur = at_get(&imp->imp_at.iat_service_estimate[i]);
+               worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
+               worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
+               s2dhms(&ts, now - worstt);
+               seq_printf(m, "portal %-2d  : cur %3u  worst %3u (at %ld, "
+                          DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
+                          cur, worst, worstt, DHMS_VARS(&ts));
+               lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
+       }
+
+       LPROCFS_CLIMP_EXIT(obd);
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_timeouts_seq_show);
+
+int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+       __u64 flags;
+
+       LPROCFS_CLIMP_CHECK(obd);
+       flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
+       seq_printf(m, "flags="LPX64"\n", flags);
+       obd_connect_seq_flags2str(m, flags, "\n");
+       seq_printf(m, "\n");
+       LPROCFS_CLIMP_EXIT(obd);
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_connect_flags_seq_show);
+
+#ifdef HAVE_SERVER_SUPPORT
+int lprocfs_num_exports_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = data;
+
+       LASSERT(obd != NULL);
+       return seq_printf(m, "%u\n", obd->obd_num_exports);
+}
+EXPORT_SYMBOL(lprocfs_num_exports_seq_show);
+#endif
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
+
+int lprocfs_rd_uint(char *page, char **start, off_t off,
+                   int count, int *eof, void *data)
+{
+       unsigned int *temp = data;
+       return snprintf(page, count, "%u\n", *temp);
+}
+EXPORT_SYMBOL(lprocfs_rd_uint);
 
 int lprocfs_rd_u64(char *page, char **start, off_t off,
                    int count, int *eof, void *data)
@@ -459,20 +1387,22 @@ int lprocfs_rd_u64(char *page, char **start, off_t off,
         *eof = 1;
         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
 }
+EXPORT_SYMBOL(lprocfs_rd_u64);
 
 int lprocfs_rd_atomic(char *page, char **start, off_t off,
                    int count, int *eof, void *data)
 {
-        cfs_atomic_t *atom = data;
+       atomic_t *atom = data;
         LASSERT(atom != NULL);
         *eof = 1;
-        return snprintf(page, count, "%d\n", cfs_atomic_read(atom));
+       return snprintf(page, count, "%d\n", atomic_read(atom));
 }
+EXPORT_SYMBOL(lprocfs_rd_atomic);
 
 int lprocfs_wr_atomic(struct file *file, const char *buffer,
                       unsigned long count, void *data)
 {
-        cfs_atomic_t *atm = data;
+       atomic_t *atm = data;
         int val = 0;
         int rc;
 
@@ -483,9 +1413,10 @@ int lprocfs_wr_atomic(struct file *file, const char *buffer,
         if (val <= 0)
                 return -ERANGE;
 
-        cfs_atomic_set(atm, val);
+       atomic_set(atm, val);
         return count;
 }
+EXPORT_SYMBOL(lprocfs_wr_atomic);
 
 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
                     int *eof, void *data)
@@ -496,6 +1427,7 @@ int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
         *eof = 1;
         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
 }
+EXPORT_SYMBOL(lprocfs_rd_uuid);
 
 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
                     int *eof, void *data)
@@ -503,27 +1435,17 @@ int lprocfs_rd_name(char *page, char **start, off_t off, int count,
         struct obd_device *dev = data;
 
         LASSERT(dev != NULL);
-        LASSERT(dev->obd_name != NULL);
         *eof = 1;
         return snprintf(page, count, "%s\n", dev->obd_name);
 }
-
-int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
-                      void *data)
-{
-        struct obd_device *obd = 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);
-}
+EXPORT_SYMBOL(lprocfs_rd_name);
 
 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
                        int *eof, void *data)
 {
-        struct obd_statfs osfs;
-        int rc = obd_statfs(data, &osfs,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -532,12 +1454,14 @@ int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_blksize);
 
 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
                            int *eof, void *data)
 {
-        struct obd_statfs osfs;
-        int rc = obd_statfs(data, &osfs,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -552,12 +1476,14 @@ int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
 
 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,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -572,12 +1498,14 @@ int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
 
 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
                            int *eof, void *data)
 {
-        struct obd_statfs osfs;
-        int rc = obd_statfs(data, &osfs,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -592,12 +1520,14 @@ int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
 
 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,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -607,12 +1537,14 @@ int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
 
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_filestotal);
 
 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,
+        struct obd_device *obd = data;
+        struct obd_statfs  osfs;
+        int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                             OBD_STATFS_NODELAY);
         if (!rc) {
@@ -621,6 +1553,7 @@ int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_filesfree);
 
 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
                            int *eof, void *data)
@@ -642,6 +1575,7 @@ int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
         LPROCFS_CLIMP_EXIT(obd);
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_server_uuid);
 
 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
                          int *eof,  void *data)
@@ -665,57 +1599,7 @@ int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
         LPROCFS_CLIMP_EXIT(obd);
         return rc;
 }
-
-/** add up per-cpu counters */
-void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
-                           struct lprocfs_counter *cnt)
-{
-        unsigned int num_cpu;
-        struct lprocfs_counter t;
-        struct lprocfs_counter *percpu_cntr;
-        int centry, i;
-
-        memset(cnt, 0, sizeof(*cnt));
-
-        if (stats == NULL) {
-                /* set count to 1 to avoid divide-by-zero errs in callers */
-                cnt->lc_count = 1;
-                return;
-        }
-
-        cnt->lc_min = LC_MIN_INIT;
-
-        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
-
-        for (i = 0; i < num_cpu; i++) {
-                percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
-
-                do {
-                        centry = cfs_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 != cfs_atomic_read(&percpu_cntr->lc_cntl. \
-                                                   la_entry) &&
-                         centry != cfs_atomic_read(&percpu_cntr->lc_cntl. \
-                                                   la_exit));
-                cnt->lc_count += t.lc_count;
-                cnt->lc_sum += t.lc_sum;
-                if (t.lc_min < cnt->lc_min)
-                        cnt->lc_min = t.lc_min;
-                if (t.lc_max > cnt->lc_max)
-                        cnt->lc_max = t.lc_max;
-                cnt->lc_sumsquare += t.lc_sumsquare;
-        }
-
-        cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
-}
+EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
 
 /**
  * Append a space separated list of current set flags to str.
@@ -738,73 +1622,18 @@ static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
 }
 #undef flags2str
 
-static const char *obd_connect_names[] = {
-        "read_only",
-        "lov_index",
-        "unused",
-        "write_grant",
-        "server_lock",
-        "version",
-        "request_portal",
-        "acl",
-        "xattr",
-        "create_on_write",
-        "truncate_lock",
-        "initial_transno",
-        "inode_bit_locks",
-        "join_file(obsolete)",
-        "getattr_by_fid",
-        "no_oh_for_devices",
-        "remote_client",
-        "remote_client_by_force",
-        "max_byte_per_rpc",
-        "64bit_qdata",
-        "mds_capability",
-        "oss_capability",
-        "early_lock_cancel",
-        "som",
-        "adaptive_timeouts",
-        "lru_resize",
-        "mds_mds_connection",
-        "real_conn",
-        "change_qunit_size",
-        "alt_checksum_algorithm",
-        "fid_is_enabled",
-        "version_recovery",
-        "pools",
-        "grant_shrink",
-        "skip_orphan",
-        "large_ea",
-        "full20",
-        "layout_lock",
-        NULL
-};
-
-static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
-{
-        __u64 mask = 1;
-        int i, ret = 0;
-
-        for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
-                if (flags & mask)
-                        ret += snprintf(page + ret, count - ret, "%s%s",
-                                        ret ? sep : "", obd_connect_names[i]);
-        }
-        if (flags & ~(mask - 1))
-                ret += snprintf(page + ret, count - ret,
-                                "%sunknown flags "LPX64,
-                                ret ? sep : "", flags & ~(mask - 1));
-        return ret;
-}
-
 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                       int *eof, void *data)
 {
-        struct lprocfs_counter ret;
-        struct obd_device *obd = (struct obd_device *)data;
-        struct obd_import *imp;
-        struct obd_import_conn *conn;
-        int i, j, k, rw = 0;
+       struct lprocfs_counter          ret;
+       struct lprocfs_counter_header   *header;
+       struct obd_device               *obd    = (struct obd_device *)data;
+       struct obd_import               *imp;
+       struct obd_import_conn          *conn;
+       int                             i;
+       int                             j;
+       int                             k;
+       int                             rw      = 0;
 
         LASSERT(obd != NULL);
         LPROCFS_CLIMP_CHECK(obd);
@@ -816,10 +1645,12 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                      "    name: %s\n"
                      "    target: %s\n"
                      "    state: %s\n"
+                     "    instance: %u\n"
                      "    connect_flags: [",
                      obd->obd_name,
                      obd2cli_tgt(obd),
-                     ptlrpc_import_state_name(imp->imp_state));
+                     ptlrpc_import_state_name(imp->imp_state),
+                     imp->imp_connect_data.ocd_instance);
         i += obd_connect_flags2str(page + i, count - i,
                                    imp->imp_connect_data.ocd_connect_flags,
                                    ", ");
@@ -832,29 +1663,37 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                       "]\n"
                       "    connection:\n"
                       "       failover_nids: [");
-        cfs_spin_lock(&imp->imp_lock);
+       spin_lock(&imp->imp_lock);
         j = 0;
         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
                 j++;
         }
-        cfs_spin_unlock(&imp->imp_lock);
-        i += snprintf(page + i, count - i,
-                      "]\n"
-                      "       current_connection: %s\n"
-                      "       connection_attempts: %u\n"
-                      "       generation: %u\n"
-                      "       in-progress_invalidations: %u\n",
-                      libcfs_nid2str(imp->imp_connection->c_peer.nid),
-                      imp->imp_conn_cnt,
-                      imp->imp_generation,
-                      cfs_atomic_read(&imp->imp_inval_count));
-
+       i += snprintf(page + i, count - i,
+                     "]\n"
+                     "       current_connection: %s\n"
+                     "       connection_attempts: %u\n"
+                     "       generation: %u\n"
+                     "       in-progress_invalidations: %u\n",
+                     imp->imp_connection == NULL ? "<none>" :
+                             libcfs_nid2str(imp->imp_connection->c_peer.nid),
+                     imp->imp_conn_cnt,
+                     imp->imp_generation,
+                     atomic_read(&imp->imp_inval_count));
+       spin_unlock(&imp->imp_lock);
+
+       if (obd->obd_svc_stats == NULL)
+               goto out_climp;
+
+       header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
-        if (ret.lc_count != 0)
-                do_div(ret.lc_sum, ret.lc_count);
-        else
+        if (ret.lc_count != 0) {
+                /* first argument to do_div MUST be __u64 */
+                __u64 sum = ret.lc_sum;
+                do_div(sum, ret.lc_count);
+                ret.lc_sum = sum;
+        } else
                 ret.lc_sum = 0;
         i += snprintf(page + i, count - i,
                       "    rpcs:\n"
@@ -862,10 +1701,10 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                       "       unregistering: %u\n"
                       "       timeouts: %u\n"
                       "       avg_waittime: "LPU64" %s\n",
-                      cfs_atomic_read(&imp->imp_inflight),
-                      cfs_atomic_read(&imp->imp_unregistering),
-                      cfs_atomic_read(&imp->imp_timeouts),
-                      ret.lc_sum, ret.lc_units);
+                     atomic_read(&imp->imp_inflight),
+                     atomic_read(&imp->imp_unregistering),
+                     atomic_read(&imp->imp_timeouts),
+                     ret.lc_sum, header->lc_units);
 
         k = 0;
         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
@@ -896,7 +1735,10 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
                                       &ret);
                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
-                        do_div(ret.lc_sum, ret.lc_count);
+                        /* first argument to do_div MUST be __u64 */
+                        __u64 sum = ret.lc_sum;
+                        do_div(sum, ret.lc_count);
+                        ret.lc_sum = sum;
                         i += snprintf(page + i, count - i,
                                       "    %s_data_averages:\n"
                                       "       bytes_per_rpc: "LPU64"\n",
@@ -905,12 +1747,16 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                 }
                 k = (int)ret.lc_sum;
                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
+               header = &obd->obd_svc_stats->ls_cnt_header[j];
                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
-                        do_div(ret.lc_sum, ret.lc_count);
+                        /* first argument to do_div MUST be __u64 */
+                        __u64 sum = ret.lc_sum;
+                        do_div(sum, ret.lc_count);
+                        ret.lc_sum = sum;
                         i += snprintf(page + i, count - i,
                                       "       %s_per_rpc: "LPU64"\n",
-                                      ret.lc_units, ret.lc_sum);
+                                     header->lc_units, ret.lc_sum);
                         j = (int)ret.lc_sum;
                         if (j > 0)
                                 i += snprintf(page + i, count - i,
@@ -919,9 +1765,11 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                 }
         }
 
+out_climp:
         LPROCFS_CLIMP_EXIT(obd);
         return i;
 }
+EXPORT_SYMBOL(lprocfs_rd_import);
 
 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
                       int *eof, void *data)
@@ -953,6 +1801,7 @@ int lprocfs_rd_state(char *page, char **start, off_t off, int count,
         LPROCFS_CLIMP_EXIT(obd);
         return i;
 }
+EXPORT_SYMBOL(lprocfs_rd_state);
 
 int lprocfs_at_hist_helper(char *page, int count, int rc,
                            struct adaptive_timeout *at)
@@ -963,6 +1812,7 @@ int lprocfs_at_hist_helper(char *page, int count, int rc,
         rc += snprintf(page + rc, count - rc, "\n");
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_at_hist_helper);
 
 /* See also ptlrpc_lprocfs_rd_timeouts */
 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
@@ -1016,6 +1866,7 @@ int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
         LPROCFS_CLIMP_EXIT(obd);
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_rd_timeouts);
 
 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
                              int count, int *eof, void *data)
@@ -1034,6 +1885,7 @@ int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
 }
 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
 
+#ifdef HAVE_SERVER_SUPPORT
 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
                            int *eof,  void *data)
 {
@@ -1043,6 +1895,8 @@ int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
         *eof = 1;
         return snprintf(page, count, "%u\n", obd->obd_num_exports);
 }
+EXPORT_SYMBOL(lprocfs_rd_num_exports);
+#endif
 
 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
                        int *eof, void *data)
@@ -1053,25 +1907,50 @@ int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
         *eof = 1;
         return snprintf(page, count, "%d\n", class->typ_refcnt);
 }
+EXPORT_SYMBOL(lprocfs_rd_numrefs);
 
 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
 {
-        int rc = 0;
+       int rc = 0;
 
-        LASSERT(obd != NULL);
-        LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
-        LASSERT(obd->obd_type->typ_procroot != NULL);
-
-        obd->obd_proc_entry = lprocfs_register(obd->obd_name,
-                                               obd->obd_type->typ_procroot,
-                                               list, obd);
-        if (IS_ERR(obd->obd_proc_entry)) {
-                rc = PTR_ERR(obd->obd_proc_entry);
-                CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
-                obd->obd_proc_entry = NULL;
-        }
-        return rc;
+       LASSERT(obd != NULL);
+       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+       LASSERT(obd->obd_type->typ_procroot != NULL);
+
+       obd->obd_proc_entry = lprocfs_register(obd->obd_name,
+                                              obd->obd_type->typ_procroot,
+                                              list, obd);
+       if (IS_ERR(obd->obd_proc_entry)) {
+               rc = PTR_ERR(obd->obd_proc_entry);
+               CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
+               obd->obd_proc_entry = NULL;
+       }
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_obd_setup);
+#endif
+
+int
+lprocfs_seq_obd_setup(struct obd_device *obd)
+{
+       int rc = 0;
+
+       LASSERT(obd != NULL);
+       LASSERT(obd->obd_vars != NULL);
+       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+       LASSERT(obd->obd_type->typ_procroot != NULL);
+
+       obd->obd_proc_entry = lprocfs_seq_register(obd->obd_name,
+                                                  obd->obd_type->typ_procroot,
+                                                  obd->obd_vars, obd);
+       if (IS_ERR(obd->obd_proc_entry)) {
+               rc = PTR_ERR(obd->obd_proc_entry);
+               CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
+               obd->obd_proc_entry = NULL;
+       }
+       return rc;
 }
+EXPORT_SYMBOL(lprocfs_seq_obd_setup);
 
 int lprocfs_obd_cleanup(struct obd_device *obd)
 {
@@ -1079,7 +1958,6 @@ int lprocfs_obd_cleanup(struct obd_device *obd)
                 return -EINVAL;
         if (obd->obd_proc_exports_entry) {
                 /* Should be no exports left */
-                LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
                 lprocfs_remove(&obd->obd_proc_exports_entry);
                 obd->obd_proc_exports_entry = NULL;
         }
@@ -1089,18 +1967,16 @@ int lprocfs_obd_cleanup(struct obd_device *obd)
         }
         return 0;
 }
+EXPORT_SYMBOL(lprocfs_obd_cleanup);
 
 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
 {
-        CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
-               client_stat->nid_proc, client_stat->nid_stats,
-               client_stat->nid_brw_stats);
-
-        LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
-                 "count %d\n",
-                 cfs_atomic_read(&client_stat->nid_exp_ref_count));
+       CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
+              client_stat->nid_proc, client_stat->nid_stats);
 
-        cfs_hlist_del_init(&client_stat->nid_hash);
+       LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
+                 "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
+                 atomic_read(&client_stat->nid_exp_ref_count));
 
         if (client_stat->nid_proc)
                 lprocfs_remove(&client_stat->nid_proc);
@@ -1108,9 +1984,6 @@ static void lprocfs_free_client_stats(struct nid_stat *client_stat)
         if (client_stat->nid_stats)
                 lprocfs_free_stats(&client_stat->nid_stats);
 
-        if (client_stat->nid_brw_stats)
-                OBD_FREE_PTR(client_stat->nid_brw_stats);
-
         if (client_stat->nid_ldlm_stats)
                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
 
@@ -1121,120 +1994,172 @@ static void lprocfs_free_client_stats(struct nid_stat *client_stat)
 
 void lprocfs_free_per_client_stats(struct obd_device *obd)
 {
+        cfs_hash_t *hash = obd->obd_nid_stats_hash;
         struct nid_stat *stat;
         ENTRY;
 
         /* we need extra list - because hash_exit called to early */
         /* not need locking because all clients is died */
-        while(!cfs_list_empty(&obd->obd_nid_stats)) {
+        while (!cfs_list_empty(&obd->obd_nid_stats)) {
                 stat = cfs_list_entry(obd->obd_nid_stats.next,
                                       struct nid_stat, nid_list);
                 cfs_list_del_init(&stat->nid_list);
+                cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
                 lprocfs_free_client_stats(stat);
         }
-
         EXIT;
 }
+EXPORT_SYMBOL(lprocfs_free_per_client_stats);
+
+int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid)
+{
+       struct lprocfs_counter  *cntr;
+       unsigned int            percpusize;
+       int                     rc = -ENOMEM;
+       unsigned long           flags = 0;
+       int                     i;
+
+       LASSERT(stats->ls_percpu[cpuid] == NULL);
+       LASSERT((stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) == 0);
+
+       percpusize = lprocfs_stats_counter_size(stats);
+       LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[cpuid], percpusize);
+       if (stats->ls_percpu[cpuid] != NULL) {
+               rc = 0;
+               if (unlikely(stats->ls_biggest_alloc_num <= cpuid)) {
+                       if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+                               spin_lock_irqsave(&stats->ls_lock, flags);
+                       else
+                               spin_lock(&stats->ls_lock);
+                       if (stats->ls_biggest_alloc_num <= cpuid)
+                               stats->ls_biggest_alloc_num = cpuid + 1;
+                       if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) {
+                               spin_unlock_irqrestore(&stats->ls_lock, flags);
+                       } else {
+                               spin_unlock(&stats->ls_lock);
+                       }
+               }
+               /* initialize the ls_percpu[cpuid] non-zero counter */
+               for (i = 0; i < stats->ls_num; ++i) {
+                       cntr = lprocfs_stats_counter_get(stats, cpuid, i);
+                       cntr->lc_min = LC_MIN_INIT;
+               }
+       }
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_stats_alloc_one);
 
 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
                                           enum lprocfs_stats_flags flags)
 {
-        struct lprocfs_stats *stats;
-        unsigned int percpusize;
-        unsigned int i, j;
-        unsigned int num_cpu;
+       struct lprocfs_stats    *stats;
+       unsigned int            num_entry;
+       unsigned int            percpusize = 0;
+       int                     i;
 
         if (num == 0)
                 return NULL;
 
-        if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
-
-        OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
-        if (stats == NULL)
-                return NULL;
-
-        if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
-                stats->ls_flags = flags;
-                cfs_spin_lock_init(&stats->ls_lock);
-                /* Use this lock only if there are no percpu areas */
-        } else {
-                stats->ls_flags = 0;
-        }
-
-        percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
-        if (num_cpu > 1)
-                percpusize = CFS_L1_CACHE_ALIGN(percpusize);
-
-        for (i = 0; i < num_cpu; i++) {
-                OBD_ALLOC(stats->ls_percpu[i], percpusize);
-                if (stats->ls_percpu[i] == NULL) {
-                        for (j = 0; j < i; j++) {
-                                OBD_FREE(stats->ls_percpu[j], percpusize);
-                                stats->ls_percpu[j] = NULL;
-                        }
-                        break;
-                }
-        }
-        if (stats->ls_percpu[0] == NULL) {
-                OBD_FREE(stats, offsetof(typeof(*stats),
-                                         ls_percpu[num_cpu]));
-                return NULL;
-        }
-
-        stats->ls_num = num;
-        return stats;
+        if (lprocfs_no_percpu_stats != 0)
+                flags |= LPROCFS_STATS_FLAG_NOPERCPU;
+
+       if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
+               num_entry = 1;
+       else
+               num_entry = num_possible_cpus();
+
+       /* alloc percpu pointers for all possible cpu slots */
+       LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
+       if (stats == NULL)
+               return NULL;
+
+       stats->ls_num = num;
+       stats->ls_flags = flags;
+       spin_lock_init(&stats->ls_lock);
+
+       /* alloc num of counter headers */
+       LIBCFS_ALLOC(stats->ls_cnt_header,
+                    stats->ls_num * sizeof(struct lprocfs_counter_header));
+       if (stats->ls_cnt_header == NULL)
+               goto fail;
+
+       if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
+               /* contains only one set counters */
+               percpusize = lprocfs_stats_counter_size(stats);
+               LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
+               if (stats->ls_percpu[0] == NULL)
+                       goto fail;
+               stats->ls_biggest_alloc_num = 1;
+       } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
+               /* alloc all percpu data, currently only obd_memory use this */
+               for (i = 0; i < num_entry; ++i)
+                       if (lprocfs_stats_alloc_one(stats, i) < 0)
+                               goto fail;
+       }
+
+       return stats;
+
+fail:
+       lprocfs_free_stats(&stats);
+       return NULL;
 }
+EXPORT_SYMBOL(lprocfs_alloc_stats);
 
 void lprocfs_free_stats(struct lprocfs_stats **statsh)
 {
-        struct lprocfs_stats *stats = *statsh;
-        unsigned int num_cpu;
-        unsigned int percpusize;
-        unsigned int i;
+       struct lprocfs_stats *stats = *statsh;
+       unsigned int num_entry;
+       unsigned int percpusize;
+       unsigned int i;
 
         if (stats == NULL || stats->ls_num == 0)
                 return;
         *statsh = NULL;
 
-        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
+       if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
+               num_entry = 1;
+       else
+               num_entry = num_possible_cpus();
 
-        percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
-        if (num_cpu > 1)
-                percpusize = CFS_L1_CACHE_ALIGN(percpusize);
-        for (i = 0; i < num_cpu; i++)
-                OBD_FREE(stats->ls_percpu[i], percpusize);
-        OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
+       percpusize = lprocfs_stats_counter_size(stats);
+       for (i = 0; i < num_entry; i++)
+               if (stats->ls_percpu[i] != NULL)
+                       LIBCFS_FREE(stats->ls_percpu[i], percpusize);
+       if (stats->ls_cnt_header != NULL)
+               LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
+                                       sizeof(struct lprocfs_counter_header));
+       LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
 }
+EXPORT_SYMBOL(lprocfs_free_stats);
 
 void lprocfs_clear_stats(struct lprocfs_stats *stats)
 {
-        struct lprocfs_counter *percpu_cntr;
-        int i,j;
-        unsigned int num_cpu;
-
-        num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
-
-        for (i = 0; i < num_cpu; i++) {
-                for (j = 0; j < stats->ls_num; j++) {
-                        percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
-                        cfs_atomic_inc(&percpu_cntr->lc_cntl.la_entry);
-                        percpu_cntr->lc_count = 0;
-                        percpu_cntr->lc_sum = 0;
-                        percpu_cntr->lc_min = LC_MIN_INIT;
-                        percpu_cntr->lc_max = 0;
-                        percpu_cntr->lc_sumsquare = 0;
-                        cfs_atomic_inc(&percpu_cntr->lc_cntl.la_exit);
-                }
-        }
-
-        lprocfs_stats_unlock(stats);
+       struct lprocfs_counter          *percpu_cntr;
+       int                             i;
+       int                             j;
+       unsigned int                    num_entry;
+       unsigned long                   flags = 0;
+
+       num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+
+       for (i = 0; i < num_entry; i++) {
+               if (stats->ls_percpu[i] == NULL)
+                       continue;
+               for (j = 0; j < stats->ls_num; j++) {
+                       percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
+                       percpu_cntr->lc_count           = 0;
+                       percpu_cntr->lc_min             = LC_MIN_INIT;
+                       percpu_cntr->lc_max             = 0;
+                       percpu_cntr->lc_sumsquare       = 0;
+                       percpu_cntr->lc_sum             = 0;
+                       if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+                               percpu_cntr->lc_sum_irq = 0;
+               }
+       }
+
+       lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
 }
+EXPORT_SYMBOL(lprocfs_clear_stats);
 
 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
                                        size_t len, loff_t *off)
@@ -1249,10 +2174,9 @@ static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
 
 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]);
+       struct lprocfs_stats *stats = p->private;
+
+       return (*pos < stats->ls_num) ? pos : NULL;
 }
 
 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
@@ -1261,80 +2185,78 @@ static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
 
 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
 {
-        struct lprocfs_stats *stats = p->private;
-        ++*pos;
-        return (*pos >= stats->ls_num) ? NULL :
-                &(stats->ls_percpu[0]->lp_cntr[*pos]);
+       (*pos)++;
+
+       return lprocfs_stats_seq_start(p, 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 ret;
-       int idx, rc = 0;
-
-       if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
-               struct timeval now;
-               cfs_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];
-
-       lprocfs_stats_collect(stats, idx, &ret);
-
-       if (ret.lc_count == 0)
-               goto out;
-
-       rc = seq_printf(p, "%-25s "LPD64" 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, " "LPD64" "LPD64" "LPD64,
-                               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, " "LPD64, ret.lc_sumsquare);
-               if (rc < 0)
-                       goto out;
-       }
-       rc = seq_printf(p, "\n");
- out:
-       return (rc < 0) ? rc : 0;
+       struct lprocfs_stats            *stats  = p->private;
+       struct lprocfs_counter_header   *hdr;
+       struct lprocfs_counter           ctr;
+       int                              idx    = *(loff_t *)v;
+       int                              rc     = 0;
+
+       if (idx == 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;
+       }
+
+       hdr = &stats->ls_cnt_header[idx];
+       lprocfs_stats_collect(stats, idx, &ctr);
+
+       if (ctr.lc_count == 0)
+               goto out;
+
+       rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
+                       ctr.lc_count, hdr->lc_units);
+       if (rc < 0)
+               goto out;
+
+       if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
+               rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
+                               ctr.lc_min, ctr.lc_max, ctr.lc_sum);
+               if (rc < 0)
+                       goto out;
+               if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
+                       rc = seq_printf(p, " "LPD64, ctr.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,
+       .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;
-
-        if (LPROCFS_ENTRY_AND_CHECK(dp))
-                return -ENOENT;
+       struct seq_file *seq;
+       int rc;
 
-        rc = seq_open(file, &lprocfs_stats_seq_sops);
-        if (rc) {
-                LPROCFS_EXIT();
-                return rc;
-        }
-        seq = file->private_data;
-        seq->private = dp->data;
-        return 0;
+#ifndef HAVE_ONLY_PROCFS_SEQ
+       if (LPROCFS_ENTRY_CHECK(PDE(inode)))
+               return -ENOENT;
+#endif
+       rc = seq_open(file, &lprocfs_stats_seq_sops);
+       if (rc)
+               return rc;
+       seq = file->private_data;
+       seq->private = PDE_DATA(inode);
+       return 0;
 }
 
 struct file_operations lprocfs_stats_seq_fops = {
@@ -1349,40 +2271,50 @@ struct file_operations lprocfs_stats_seq_fops = {
 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
                            struct lprocfs_stats *stats)
 {
-        struct proc_dir_entry *entry;
-        LASSERT(root != NULL);
+       struct proc_dir_entry *entry;
+       LASSERT(root != NULL);
 
-        entry = create_proc_entry(name, 0644, root);
-        if (entry == NULL)
-                return -ENOMEM;
-        entry->proc_fops = &lprocfs_stats_seq_fops;
-        entry->data = stats;
-        return 0;
+       entry = proc_create_data(name, 0644, root,
+                                &lprocfs_stats_seq_fops, stats);
+       if (entry == NULL)
+               return -ENOMEM;
+       return 0;
 }
+EXPORT_SYMBOL(lprocfs_register_stats);
 
 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
-                          unsigned conf, const char *name, const char *units)
-{
-        struct lprocfs_counter *c;
-        int i;
-        unsigned int num_cpu;
-
-        LASSERT(stats != NULL);
-
-        num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
-
-        for (i = 0; i < num_cpu; i++) {
-                c = &(stats->ls_percpu[i]->lp_cntr[index]);
-                c->lc_config = conf;
-                c->lc_count = 0;
-                c->lc_sum = 0;
-                c->lc_min = LC_MIN_INIT;
-                c->lc_max = 0;
-                c->lc_name = name;
-                c->lc_units = units;
-        }
-
-        lprocfs_stats_unlock(stats);
+                         unsigned conf, const char *name, const char *units)
+{
+       struct lprocfs_counter_header   *header;
+       struct lprocfs_counter          *percpu_cntr;
+       unsigned long                   flags = 0;
+       unsigned int                    i;
+       unsigned int                    num_cpu;
+
+       LASSERT(stats != NULL);
+
+       header = &stats->ls_cnt_header[index];
+       LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
+                index, name, units);
+
+       header->lc_config = conf;
+       header->lc_name   = name;
+       header->lc_units  = units;
+
+       num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+       for (i = 0; i < num_cpu; ++i) {
+               if (stats->ls_percpu[i] == NULL)
+                       continue;
+               percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
+               percpu_cntr->lc_count           = 0;
+               percpu_cntr->lc_min             = LC_MIN_INIT;
+               percpu_cntr->lc_max             = 0;
+               percpu_cntr->lc_sumsquare       = 0;
+               percpu_cntr->lc_sum             = 0;
+               if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
+                       percpu_cntr->lc_sum_irq = 0;
+       }
+       lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
 }
 EXPORT_SYMBOL(lprocfs_counter_init);
 
@@ -1413,7 +2345,6 @@ void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
-        LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
@@ -1456,7 +2387,6 @@ void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
-        LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
@@ -1464,7 +2394,10 @@ void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
+
+       CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
 }
+EXPORT_SYMBOL(lprocfs_init_ops_stats);
 
 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
 {
@@ -1476,8 +2409,7 @@ int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
         LASSERT(obd->obd_proc_entry != NULL);
         LASSERT(obd->obd_cntr_base == 0);
 
-        num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
-                num_private_stats - 1 /* o_owner */;
+       num_stats = NUM_OBD_STATS + num_private_stats;
         stats = lprocfs_alloc_stats(num_stats, 0);
         if (stats == NULL)
                 return -ENOMEM;
@@ -1490,7 +2422,7 @@ int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
                  * <obd.h>, and that the corresponding line item
                  * LPROCFS_OBD_OP_INIT(.., .., opname)
                  * is missing from the list above. */
-                LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
+               LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
                          "Missing obd_stat initializer obd_op "
                          "operation at offset %d.\n", i - num_private_stats);
         }
@@ -1503,39 +2435,32 @@ int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
         }
         return rc;
 }
+EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
 
 void lprocfs_free_obd_stats(struct obd_device *obd)
 {
         if (obd->obd_stats)
                 lprocfs_free_stats(&obd->obd_stats);
 }
+EXPORT_SYMBOL(lprocfs_free_obd_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)
+/* Note that we only init md counters for ops whose offset is less
+ * than NUM_MD_STATS. This is explained in a comment in the definition
+ * of struct md_ops. */
+#define LPROCFS_MD_OP_INIT(base, stats, op)                                   \
+       do {                                                                   \
+               unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
+                                                                              \
+               if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
+                       LASSERT(_idx < stats->ls_num);                         \
+                       lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
+               }                                                              \
+       } while (0)
+
+void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *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(revalidate_lock) +
-                    num_private_stats;
-        stats = lprocfs_alloc_stats(num_stats, 0);
-        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, null_inode);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
@@ -1548,14 +2473,17 @@ int lprocfs_alloc_md_stats(struct obd_device *obd,
         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
         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, fsync);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
+       LPROCFS_MD_OP_INIT(num_private_stats, stats, read_entry);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
+       LPROCFS_MD_OP_INIT(num_private_stats, stats, update_lsm_md);
+       LPROCFS_MD_OP_INIT(num_private_stats, stats, merge_attr);
         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, set_lock_data);
@@ -1566,35 +2494,71 @@ int lprocfs_alloc_md_stats(struct obd_device *obd,
         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
+}
+EXPORT_SYMBOL(lprocfs_init_mps_stats);
 
-        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, "md_stats", stats);
-        if (rc < 0) {
-                lprocfs_free_stats(&stats);
-        } else {
-                obd->md_stats  = stats;
-                obd->md_cntr_base = num_private_stats;
-        }
-        return rc;
+int lprocfs_alloc_md_stats(struct obd_device *obd,
+                          unsigned int num_private_stats)
+{
+       struct lprocfs_stats *stats;
+       unsigned int num_stats;
+       int rc, i;
+
+       CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
+       CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
+       CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
+
+       /* TODO Ensure that this function is only used where
+        * appropriate by adding an assertion to the effect that
+        * obd->obd_type->typ_md_ops is not NULL. We can't do this now
+        * because mdt_procfs_init() uses this function to allocate
+        * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
+        * mdt layer does not use the md_ops interface. This is
+        * confusing and a waste of memory. See LU-2484.
+        */
+       LASSERT(obd->obd_proc_entry != NULL);
+       LASSERT(obd->obd_md_stats == NULL);
+       LASSERT(obd->obd_md_cntr_base == 0);
+
+       num_stats = NUM_MD_STATS + num_private_stats;
+       stats = lprocfs_alloc_stats(num_stats, 0);
+       if (stats == NULL)
+               return -ENOMEM;
+
+       lprocfs_init_mps_stats(num_private_stats, stats);
+
+       for (i = num_private_stats; i < num_stats; i++) {
+               if (stats->ls_cnt_header[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, "md_stats", stats);
+       if (rc < 0) {
+               lprocfs_free_stats(&stats);
+       } else {
+               obd->obd_md_stats = stats;
+               obd->obd_md_cntr_base = num_private_stats;
+       }
+
+       return rc;
 }
+EXPORT_SYMBOL(lprocfs_alloc_md_stats);
 
 void lprocfs_free_md_stats(struct obd_device *obd)
 {
-        struct lprocfs_stats *stats = obd->md_stats;
+       struct lprocfs_stats *stats = obd->obd_md_stats;
 
-        if (stats != NULL) {
-                obd->md_stats = NULL;
-                obd->md_cntr_base = 0;
-                lprocfs_free_stats(&stats);
-        }
+       if (stats != NULL) {
+               obd->obd_md_stats = NULL;
+               obd->obd_md_cntr_base = 0;
+               lprocfs_free_stats(&stats);
+       }
 }
+EXPORT_SYMBOL(lprocfs_free_md_stats);
 
 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
 {
@@ -1617,7 +2581,113 @@ void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
                              0, "ldlm_gl_callback", "reqs");
 }
+EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
+
+#ifdef HAVE_SERVER_SUPPORT
+int lprocfs_exp_nid_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_export *exp = m->private;
+       LASSERT(exp != NULL);
+       return seq_printf(m, "%s\n", obd_export_nid2str(exp));
+}
+
+int lprocfs_exp_print_uuid_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
+                               cfs_hlist_node_t *hnode, void *cb_data)
+
+{
+       struct obd_export *exp = cfs_hash_object(hs, hnode);
+       struct seq_file *m = cb_data;
+
+       if (exp->exp_nid_stats)
+               seq_printf(m, "%s\n", obd_uuid2str(&exp->exp_client_uuid));
+       return 0;
+}
+
+int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data)
+{
+       struct nid_stat *stats = m->private;
+       struct obd_device *obd = stats->nid_obd;
+
+       cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
+                               lprocfs_exp_print_uuid_seq, m);
+       return 0;
+}
+LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
+
+int lprocfs_exp_print_hash_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
+                               cfs_hlist_node_t *hnode, void *cb_data)
+
+{
+       struct seq_file *m = cb_data;
+       struct obd_export *exp = cfs_hash_object(hs, hnode);
+
+       if (exp->exp_lock_hash != NULL) {
+               cfs_hash_debug_header_seq(m);
+               cfs_hash_debug_str_seq(hs, m);
+       }
+       return 0;
+}
+
+int lprocfs_exp_hash_seq_show(struct seq_file *m, void *data)
+{
+       struct nid_stat *stats = m->private;
+       struct obd_device *obd = stats->nid_obd;
+
+       cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
+                               lprocfs_exp_print_hash_seq, m);
+       return 0;
+}
+LPROC_SEQ_FOPS_RO(lprocfs_exp_hash);
 
+int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
+{
+       return seq_printf(m, "%s\n", "Write into this file to clear all nid "
+                               "stats and stale nid entries");
+}
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_show);
+
+static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
+{
+       struct nid_stat *stat = obj;
+       ENTRY;
+
+       CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
+       if (atomic_read(&stat->nid_exp_ref_count) == 1) {
+               /* object has only hash references. */
+               spin_lock(&stat->nid_obd->obd_nid_lock);
+               cfs_list_move(&stat->nid_list, data);
+               spin_unlock(&stat->nid_obd->obd_nid_lock);
+               RETURN(1);
+       }
+       /* we has reference to object - only clear data*/
+       if (stat->nid_stats)
+               lprocfs_clear_stats(stat->nid_stats);
+
+       RETURN(0);
+}
+
+ssize_t
+lprocfs_nid_stats_clear_seq_write(struct file *file, const char *buffer,
+                                       size_t count, loff_t *off)
+{
+       struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
+       struct nid_stat *client_stat;
+       CFS_LIST_HEAD(free_list);
+
+       cfs_hash_cond_del(obd->obd_nid_stats_hash,
+                               lprocfs_nid_stats_clear_write_cb, &free_list);
+
+       while (!cfs_list_empty(&free_list)) {
+               client_stat = cfs_list_entry(free_list.next, struct nid_stat,
+                                               nid_list);
+               cfs_list_del_init(&client_stat->nid_list);
+               lprocfs_free_client_stats(client_stat);
+       }
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
                          int *eof,  void *data)
 {
@@ -1628,10 +2698,10 @@ int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
 }
 
 struct exp_uuid_cb_data {
-        char                   *page;
-        int                     count;
-        int                    *eof;
-        int                    *len;
+       char                   *page;
+       int                     count;
+       int                    *eof;
+       int                    *len;
 };
 
 static void
@@ -1644,15 +2714,18 @@ lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
         cb_data->len = len;
 }
 
-void lprocfs_exp_print_uuid(void *obj, void *cb_data)
+int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
+                           cfs_hlist_node_t *hnode, void *cb_data)
+
 {
-        struct obd_export *exp = (struct obd_export *)obj;
+        struct obd_export *exp = cfs_hash_object(hs, hnode);
         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
 
         if (exp->exp_nid_stats)
                 *data->len += snprintf((data->page + *data->len),
                                        data->count, "%s\n",
                                        obd_uuid2str(&exp->exp_client_uuid));
+        return 0;
 }
 
 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
@@ -1671,21 +2744,23 @@ int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
         return (*cb_data.len);
 }
 
-void lprocfs_exp_print_hash(void *obj, void *cb_data)
+int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
+                           cfs_hlist_node_t *hnode, void *cb_data)
+
 {
         struct exp_uuid_cb_data *data = cb_data;
-        struct obd_export       *exp = obj;
-        cfs_hash_t              *hs;
+        struct obd_export       *exp = cfs_hash_object(hs, hnode);
 
-        hs = exp->exp_lock_hash;
-        if (hs) {
-                if (!*data->len)
+        if (exp->exp_lock_hash != NULL) {
+                if (!*data->len) {
                         *data->len += cfs_hash_debug_header(data->page,
                                                             data->count);
-
+                }
                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
                                                  data->count);
         }
+
+        return 0;
 }
 
 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
@@ -1715,33 +2790,8 @@ int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
 }
 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
 
-int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
-{
-        struct nid_stat *stat = obj;
-        int i;
-        ENTRY;
-        /* object has only hash + iterate_all references.
-         * add/delete blocked by hash bucket lock */
-        CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
-        if (cfs_atomic_read(&stat->nid_exp_ref_count) == 2) {
-                cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
-                cfs_list_move(&stat->nid_list, data);
-                cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
-                RETURN(1);
-        }
-        /* we has reference to object - only clear data*/
-        if (stat->nid_stats)
-                lprocfs_clear_stats(stat->nid_stats);
-
-        if (stat->nid_brw_stats) {
-                for (i = 0; i < BRW_LAST; i++)
-                        lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
-        }
-        RETURN(0);
-}
-
 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
-                                         unsigned long count, void *data)
+                                  unsigned long count, void *data)
 {
         struct obd_device *obd = (struct obd_device *)data;
         struct nid_stat *client_stat;
@@ -1760,9 +2810,9 @@ int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
         return count;
 }
 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
+#endif
 
-int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
-                      int *newnid)
+int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
 {
         struct nid_stat *new_stat, *old_stat;
         struct obd_device *obd = NULL;
@@ -1783,6 +2833,13 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
         if (!nid || *nid == LNET_NID_ANY)
                 RETURN(0);
 
+       spin_lock(&exp->exp_lock);
+       if (exp->exp_nid_stats != NULL) {
+               spin_unlock(&exp->exp_lock);
+               RETURN(-EALREADY);
+       }
+       spin_unlock(&exp->exp_lock);
+
         obd = exp->exp_obd;
 
         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
@@ -1794,65 +2851,79 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
         new_stat->nid               = *nid;
         new_stat->nid_obd           = exp->exp_obd;
         /* we need set default refcount to 1 to balance obd_disconnect */
-        cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
+       atomic_set(&new_stat->nid_exp_ref_count, 1);
 
         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
                                            nid, &new_stat->nid_hash);
         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
                old_stat, libcfs_nid2str(*nid),
-               cfs_atomic_read(&new_stat->nid_exp_ref_count));
-
-        /* Return -EALREADY here so that we know that the /proc
-         * entry already has been created */
-        if (old_stat != new_stat) {
-                /* if this connects to the existing export of same nid,
-                 * we need to release old stats for obd_disconnect won't
-                 * balance the reference gotten in "cfs_hash_findadd_uinque" */
-                if (reconnect && exp->exp_nid_stats)
-                        nidstat_putref(old_stat);
-
-                exp->exp_nid_stats = old_stat;
-                GOTO(destroy_new, rc = -EALREADY);
-        }
+              atomic_read(&new_stat->nid_exp_ref_count));
+
+       /* Return -EALREADY here so that we know that the /proc
+        * entry already has been created */
+       if (old_stat != new_stat) {
+               nidstat_putref(old_stat);
+               GOTO(destroy_new, rc = -EALREADY);
+       }
         /* not found - create */
         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
         if (buffer == NULL)
                 GOTO(destroy_new, rc = -ENOMEM);
 
-        memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
+       memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
+#ifndef HAVE_ONLY_PROCFS_SEQ
         new_stat->nid_proc = lprocfs_register(buffer,
-                                              obd->obd_proc_exports_entry,
-                                              NULL, NULL);
-        OBD_FREE(buffer, LNET_NIDSTR_SIZE);
-
-        if (new_stat->nid_proc == NULL) {
-                CERROR("Error making export directory for nid %s\n",
-                       libcfs_nid2str(*nid));
-                GOTO(destroy_new_ns, rc = -ENOMEM);
-        }
+                                               obd->obd_proc_exports_entry,
+                                               NULL, NULL);
+#else
+       new_stat->nid_proc = lprocfs_seq_register(buffer,
+                                               obd->obd_proc_exports_entry,
+                                               NULL, NULL);
+#endif
+       OBD_FREE(buffer, LNET_NIDSTR_SIZE);
+
+       if (IS_ERR(new_stat->nid_proc)) {
+               rc = PTR_ERR(new_stat->nid_proc);
+               new_stat->nid_proc = NULL;
+               CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
+                      obd->obd_name, libcfs_nid2str(*nid), rc);
+               GOTO(destroy_new_ns, rc);
+       }
 
+#ifndef HAVE_ONLY_PROCFS_SEQ
         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
+#else
+       entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
+                                       new_stat, &lprocfs_exp_uuid_fops);
+#endif
         if (IS_ERR(entry)) {
                 CWARN("Error adding the NID stats file\n");
                 rc = PTR_ERR(entry);
                 GOTO(destroy_new_ns, rc);
         }
 
+#ifndef HAVE_ONLY_PROCFS_SEQ
         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
+#else
+       entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
+                                       new_stat, &lprocfs_exp_hash_fops);
+#endif
         if (IS_ERR(entry)) {
                 CWARN("Error adding the hash file\n");
                 rc = PTR_ERR(entry);
                 GOTO(destroy_new_ns, rc);
         }
 
-        exp->exp_nid_stats = new_stat;
+       spin_lock(&exp->exp_lock);
+       exp->exp_nid_stats = new_stat;
+       spin_unlock(&exp->exp_lock);
         *newnid = 1;
         /* protect competitive add to list, not need locking on destroy */
-        cfs_spin_lock(&obd->obd_nid_lock);
-        cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
-        cfs_spin_unlock(&obd->obd_nid_lock);
+       spin_lock(&obd->obd_nid_lock);
+       cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
+       spin_unlock(&obd->obd_nid_lock);
 
         RETURN(rc);
 
@@ -1866,6 +2937,8 @@ destroy_new:
         OBD_FREE_PTR(new_stat);
         RETURN(rc);
 }
+EXPORT_SYMBOL(lprocfs_exp_setup);
+#endif
 
 int lprocfs_exp_cleanup(struct obd_export *exp)
 {
@@ -1879,12 +2952,55 @@ int lprocfs_exp_cleanup(struct obd_export *exp)
 
         return 0;
 }
+EXPORT_SYMBOL(lprocfs_exp_cleanup);
+
+__s64 lprocfs_read_helper(struct lprocfs_counter *lc,
+                         struct lprocfs_counter_header *header,
+                         enum lprocfs_stats_flags flags,
+                         enum lprocfs_fields_flags field)
+{
+       __s64 ret = 0;
+
+       if (lc == NULL || header == NULL)
+               RETURN(0);
+
+       switch (field) {
+               case LPROCFS_FIELDS_FLAGS_CONFIG:
+                       ret = header->lc_config;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_SUM:
+                       ret = lc->lc_sum;
+                       if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
+                               ret += lc->lc_sum_irq;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_MIN:
+                       ret = lc->lc_min;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_MAX:
+                       ret = lc->lc_max;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_AVG:
+                       ret = (lc->lc_max - lc->lc_min) / 2;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
+                       ret = lc->lc_sumsquare;
+                       break;
+               case LPROCFS_FIELDS_FLAGS_COUNT:
+                       ret = lc->lc_count;
+                       break;
+               default:
+                       break;
+       };
+       RETURN(ret);
+}
+EXPORT_SYMBOL(lprocfs_read_helper);
 
 int lprocfs_write_helper(const char *buffer, unsigned long count,
                          int *val)
 {
         return lprocfs_write_frac_helper(buffer, count, val, 1);
 }
+EXPORT_SYMBOL(lprocfs_write_helper);
 
 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
                               int *val, int mult)
@@ -1894,7 +3010,7 @@ int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
         if (count > (sizeof(kernbuf) - 1))
                 return -EINVAL;
 
-        if (cfs_copy_from_user(kernbuf, buffer, count))
+       if (copy_from_user(kernbuf, buffer, count))
                 return -EFAULT;
 
         kernbuf[count] = '\0';
@@ -1927,6 +3043,7 @@ int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
         }
         return 0;
 }
+EXPORT_SYMBOL(lprocfs_write_frac_helper);
 
 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
                              int mult)
@@ -1981,11 +3098,38 @@ int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
         buffer[prtn++] ='\n';
         return prtn;
 }
+EXPORT_SYMBOL(lprocfs_read_frac_helper);
+
+int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
+{
+       long decimal_val, frac_val;
+
+       decimal_val = val / mult;
+       seq_printf(m, "%ld", decimal_val);
+       frac_val = val % mult;
+
+       if (frac_val > 0) {
+               frac_val *= 100;
+               frac_val /= mult;
+       }
+       if (frac_val > 0) {
+               /* Three cases: x0, xx, 0x */
+               if ((frac_val % 10) != 0)
+                       seq_printf(m, ".%ld", frac_val);
+               else
+                       seq_printf(m, ".%ld", frac_val / 10);
+       }
+
+       seq_printf(m, "\n");
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
 
 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
 {
         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
 }
+EXPORT_SYMBOL(lprocfs_write_u64_helper);
 
 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
                               __u64 *val, int mult)
@@ -1997,7 +3141,7 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
         if (count > (sizeof(kernbuf) - 1))
                 return -EINVAL;
 
-        if (cfs_copy_from_user(kernbuf, buffer, count))
+       if (copy_from_user(kernbuf, buffer, count))
                 return -EFAULT;
 
         kernbuf[count] = '\0';
@@ -2026,18 +3170,20 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
         }
 
         units = 1;
-        switch(*end) {
-        case 'p': case 'P':
-                units <<= 10;
-        case 't': case 'T':
-                units <<= 10;
-        case 'g': case 'G':
-                units <<= 10;
-        case 'm': case 'M':
-                units <<= 10;
-        case 'k': case 'K':
-                units <<= 10;
-        }
+       if (end != NULL) {
+               switch (*end) {
+               case 'p': case 'P':
+                       units <<= 10;
+               case 't': case 'T':
+                       units <<= 10;
+               case 'g': case 'G':
+                       units <<= 10;
+               case 'm': case 'M':
+                       units <<= 10;
+               case 'k': case 'K':
+                       units <<= 10;
+               }
+       }
         /* Specified units override the multiplier */
         if (units)
                 mult = mult < 0 ? -units : units;
@@ -2047,27 +3193,80 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
         *val = whole * mult + frac;
         return 0;
 }
+EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
 
-int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
-                       struct file_operations *seq_fops, void *data)
+static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
 {
-        struct proc_dir_entry *entry;
-        ENTRY;
+       size_t l2;
 
-        entry = create_proc_entry(name, mode, parent);
-        if (entry == NULL)
-                RETURN(-ENOMEM);
-        entry->proc_fops = seq_fops;
-        entry->data = data;
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       while (len >= l2) {
+               len--;
+               if (!memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
 
-        RETURN(0);
+/**
+ * Find the string \a name in the input \a buffer, and return a pointer to the
+ * value immediately following \a name, reducing \a count appropriately.
+ * If \a name is not found the original \a buffer is returned.
+ */
+char *lprocfs_find_named_value(const char *buffer, const char *name,
+                               size_t *count)
+{
+       char *val;
+       size_t buflen = *count;
+
+       /* there is no strnstr() in rhel5 and ubuntu kernels */
+       val = lprocfs_strnstr(buffer, name, buflen);
+       if (val == NULL)
+               return (char *)buffer;
+
+       val += strlen(name);                             /* skip prefix */
+       while (val < buffer + buflen && isspace(*val)) /* skip separator */
+               val++;
+
+       *count = 0;
+       while (val < buffer + buflen && isalnum(*val)) {
+               ++*count;
+               ++val;
+       }
+
+       return val - *count;
+}
+EXPORT_SYMBOL(lprocfs_find_named_value);
+
+int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
+                      const char *name,
+                      mode_t mode,
+                      const struct file_operations *seq_fops,
+                      void *data)
+{
+       struct proc_dir_entry *entry;
+       ENTRY;
+
+       /* Disallow secretly (un)writable entries. */
+       LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
+
+       entry = proc_create_data(name, mode, parent, seq_fops, data);
+
+       if (entry == NULL)
+               RETURN(-ENOMEM);
+
+       RETURN(0);
 }
 EXPORT_SYMBOL(lprocfs_seq_create);
 
-__inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
-                                      mode_t mode,
-                                      struct file_operations *seq_fops,
-                                      void *data)
+int lprocfs_obd_seq_create(struct obd_device *dev,
+                          const char *name,
+                          mode_t mode,
+                          const struct file_operations *seq_fops,
+                          void *data)
 {
         return (lprocfs_seq_create(dev->obd_proc_entry, name,
                                    mode, seq_fops, data));
@@ -2076,23 +3275,23 @@ EXPORT_SYMBOL(lprocfs_obd_seq_create);
 
 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
 {
-        if (value >= OBD_HIST_MAX)
-                value = OBD_HIST_MAX - 1;
+       if (value >= OBD_HIST_MAX)
+               value = OBD_HIST_MAX - 1;
 
-        cfs_spin_lock(&oh->oh_lock);
-        oh->oh_buckets[value]++;
-        cfs_spin_unlock(&oh->oh_lock);
+       spin_lock(&oh->oh_lock);
+       oh->oh_buckets[value]++;
+       spin_unlock(&oh->oh_lock);
 }
 EXPORT_SYMBOL(lprocfs_oh_tally);
 
 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
 {
-        unsigned int val;
+       unsigned int val = 0;
 
-        for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
-                ;
+       if (likely(value != 0))
+               val = min(fls(value - 1), OBD_HIST_MAX);
 
-        lprocfs_oh_tally(oh, val);
+       lprocfs_oh_tally(oh, val);
 }
 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
 
@@ -2109,12 +3308,187 @@ EXPORT_SYMBOL(lprocfs_oh_sum);
 
 void lprocfs_oh_clear(struct obd_histogram *oh)
 {
-        cfs_spin_lock(&oh->oh_lock);
-        memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
-        cfs_spin_unlock(&oh->oh_lock);
+       spin_lock(&oh->oh_lock);
+       memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
+       spin_unlock(&oh->oh_lock);
 }
 EXPORT_SYMBOL(lprocfs_oh_clear);
 
+#ifdef HAVE_SERVER_SUPPORT
+int lprocfs_hash_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       int c = 0;
+
+       if (obd == NULL)
+               return 0;
+
+       c += cfs_hash_debug_header_seq(m);
+       c += cfs_hash_debug_str_seq(obd->obd_uuid_hash, m);
+       c += cfs_hash_debug_str_seq(obd->obd_nid_hash, m);
+       c += cfs_hash_debug_str_seq(obd->obd_nid_stats_hash, m);
+       return c;
+}
+EXPORT_SYMBOL(lprocfs_hash_seq_show);
+
+int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+
+       LASSERT(obd != NULL);
+
+       seq_printf(m, "status: \n");
+       if (obd->obd_max_recoverable_clients == 0) {
+               seq_printf(m, "INACTIVE\n");
+               goto out;
+       }
+
+       /* sampled unlocked, but really... */
+       if (obd->obd_recovering == 0) {
+               seq_printf(m, "COMPLETE\n");
+               seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
+               seq_printf(m, "recovery_duration: %lu\n",
+                               obd->obd_recovery_end - obd->obd_recovery_start);
+               /* Number of clients that have completed recovery */
+               seq_printf(m, "completed_clients: %d/%d\n",
+                               obd->obd_max_recoverable_clients -
+                               obd->obd_stale_clients,
+                               obd->obd_max_recoverable_clients);
+               seq_printf(m, "replayed_requests: %d\n",
+                               obd->obd_replayed_requests);
+               seq_printf(m, "last_transno: "LPD64"\n",
+                               obd->obd_next_recovery_transno - 1);
+               seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
+                               "ENABLED" : "DISABLED");
+               seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
+                               "DISABLED" : "ENABLED");
+               goto out;
+       }
+
+       seq_printf(m, "RECOVERING\n");
+       seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
+       seq_printf(m, "time_remaining: %lu\n",
+                       cfs_time_current_sec() >=
+                       obd->obd_recovery_start +
+                       obd->obd_recovery_timeout ? 0 :
+                       obd->obd_recovery_start +
+                       obd->obd_recovery_timeout -
+                       cfs_time_current_sec());
+       seq_printf(m, "connected_clients: %d/%d\n",
+                       atomic_read(&obd->obd_connected_clients),
+                       obd->obd_max_recoverable_clients);
+       /* Number of clients that have completed recovery */
+       seq_printf(m, "req_replay_clients: %d\n",
+                       atomic_read(&obd->obd_req_replay_clients));
+       seq_printf(m, "lock_repay_clients: %d\n",
+                       atomic_read(&obd->obd_lock_replay_clients));
+       seq_printf(m, "completed_clients: %d\n",
+                       atomic_read(&obd->obd_connected_clients) -
+                       atomic_read(&obd->obd_lock_replay_clients));
+       seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
+       seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
+       seq_printf(m, "queued_requests: %d\n",
+                       obd->obd_requests_queued_for_recovery);
+       seq_printf(m, "next_transno: "LPD64"\n",
+                       obd->obd_next_recovery_transno);
+out:
+       return 0;
+}
+EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
+
+int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+
+       LASSERT(obd != NULL);
+       return seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
+}
+EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
+
+ssize_t
+lprocfs_ir_factor_seq_write(struct file *file, const char *buffer,
+                               size_t count, loff_t *off)
+{
+       struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
+       int val, rc;
+
+       LASSERT(obd != NULL);
+       rc = lprocfs_write_helper(buffer, count, &val);
+       if (rc)
+               return rc;
+
+       if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
+               return -EINVAL;
+
+       obd->obd_recovery_ir_factor = val;
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
+
+int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+
+       LASSERT(obd != NULL);
+       return seq_printf(m, "%d\n", obd->obd_recovery_timeout);
+}
+EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
+
+ssize_t
+lprocfs_recovery_time_soft_seq_write(struct file *file, const char *buffer,
+                                       size_t count, loff_t *off)
+{
+       struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
+       int val, rc;
+
+       LASSERT(obd != NULL);
+       rc = lprocfs_write_helper(buffer, count, &val);
+       if (rc)
+               return rc;
+
+       obd->obd_recovery_timeout = val;
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
+
+int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+
+       LASSERT(obd != NULL);
+       return seq_printf(m, "%u\n", obd->obd_recovery_time_hard);
+}
+EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
+
+ssize_t
+lprocfs_recovery_time_hard_seq_write(struct file *file, const char *buffer,
+                                       size_t count, loff_t *off)
+{
+       struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
+       int val, rc;
+
+       LASSERT(obd != NULL);
+       rc = lprocfs_write_helper(buffer, count, &val);
+       if (rc)
+               return rc;
+
+       obd->obd_recovery_time_hard = val;
+       return count;
+}
+EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
+
+int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = m->private;
+       struct obd_device_target *target = &obd->u.obt;
+
+       LASSERT(obd != NULL);
+       LASSERT(target->obt_magic == OBT_MAGIC);
+       return seq_printf(m, "%u\n", obd->u.obt.obt_instance);
+}
+EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
+
+#ifndef HAVE_ONLY_PROCFS_SEQ
 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
                         int count, int *eof, void *data)
 {
@@ -2128,11 +3502,6 @@ int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
-#ifdef HAVE_QUOTA_SUPPORT
-        if (obd->u.obt.obt_qctxt.lqc_lqs_hash)
-                c += cfs_hash_debug_str(obd->u.obt.obt_qctxt.lqc_lqs_hash,
-                                        page + c, count - c);
-#endif
 
         return c;
 }
@@ -2153,11 +3522,13 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
            what we need to read */
         *start = page + off;
 
-        /* We know we are allocated a page here.
-           Also we know that this function will
-           not need to write more than a page
-           so we can truncate at CFS_PAGE_SIZE.  */
-        size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
+       /*
+        * We know we are allocated a page here.
+        * Also we know that this function will
+        * not need to write more than a page
+        * so we can truncate at PAGE_CACHE_SIZE.
+        */
+       size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
 
         /* Initialize the page */
         memset(page, 0, size);
@@ -2199,8 +3570,13 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
                                          "last_transno: "LPD64"\n",
                                          obd->obd_next_recovery_transno - 1)<=0)
                         goto out;
-                if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
-                                         obd->obd_version_recov ? "ON" : "OFF")<=0)
+               if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
+                                        obd->obd_version_recov ?
+                                        "ENABLED" : "DISABLED") <=0)
+                        goto out;
+               if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
+                                        obd->obd_no_ir ?
+                                        "DISABLED" : "ENABLED") <= 0)
                         goto out;
                 goto fclose;
         }
@@ -2211,25 +3587,29 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
                                  obd->obd_recovery_start) <= 0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
-                           cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
-                           obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
+                                 cfs_time_current_sec() >=
+                                 obd->obd_recovery_start +
+                                 obd->obd_recovery_timeout ? 0 :
+                                 obd->obd_recovery_start +
+                                 obd->obd_recovery_timeout -
+                                 cfs_time_current_sec()) <= 0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
-                                 obd->obd_connected_clients,
+                                atomic_read(&obd->obd_connected_clients),
                                  obd->obd_max_recoverable_clients) <= 0)
                 goto out;
         /* Number of clients that have completed recovery */
         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
-                                 cfs_atomic_read(&obd->obd_req_replay_clients))
+                                atomic_read(&obd->obd_req_replay_clients))
                 <= 0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
-                                 cfs_atomic_read(&obd->obd_lock_replay_clients))
+                                atomic_read(&obd->obd_lock_replay_clients))
                 <=0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
-                                 obd->obd_connected_clients -
-                                 cfs_atomic_read(&obd->obd_lock_replay_clients))
+                                atomic_read(&obd->obd_connected_clients) -
+                                atomic_read(&obd->obd_lock_replay_clients))
                 <=0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
@@ -2253,6 +3633,36 @@ out:
 }
 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
 
+int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
+                             int count, int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%d\n",
+                        obd->obd_recovery_ir_factor);
+}
+EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
+
+int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
+                             unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
+                return -EINVAL;
+
+        obd->obd_recovery_ir_factor = val;
+        return count;
+}
+EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
+
 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
 {
@@ -2286,7 +3696,7 @@ int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
         struct obd_device *obd = data;
         LASSERT(obd != NULL);
 
-        return snprintf(page, count, "%lu\n", obd->obd_recovery_time_hard);
+        return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
 }
 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
 
@@ -2306,69 +3716,45 @@ int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
 }
 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
 
-int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
-                          int count, int *eof, void *data)
+int lprocfs_target_rd_instance(char *page, char **start, off_t off,
+                              int count, int *eof, void *data)
 {
-        struct obd_device *obd = (struct obd_device *)data;
+       struct obd_device *obd = (struct obd_device *)data;
+       struct obd_device_target *target = &obd->u.obt;
 
-        LASSERT(obd != NULL);
-        LASSERT(obd->u.obt.obt_vfsmnt->mnt_devname);
-        *eof = 1;
-        return snprintf(page, count, "%s\n",
-                        obd->u.obt.obt_vfsmnt->mnt_devname);
+       LASSERT(obd != NULL);
+       LASSERT(target->obt_magic == OBT_MAGIC);
+       *eof = 1;
+       return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
 }
-EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
+EXPORT_SYMBOL(lprocfs_target_rd_instance);
+#endif /* HAVE_ONLY_PROCFS_SEQ */
+#endif /* HAVE_SERVER_SUPPORT */
 
-EXPORT_SYMBOL(lprocfs_register);
-EXPORT_SYMBOL(lprocfs_srch);
-EXPORT_SYMBOL(lprocfs_remove);
-EXPORT_SYMBOL(lprocfs_remove_proc_entry);
-EXPORT_SYMBOL(lprocfs_add_vars);
-EXPORT_SYMBOL(lprocfs_obd_setup);
-EXPORT_SYMBOL(lprocfs_obd_cleanup);
-EXPORT_SYMBOL(lprocfs_add_simple);
-EXPORT_SYMBOL(lprocfs_add_symlink);
-EXPORT_SYMBOL(lprocfs_free_per_client_stats);
-EXPORT_SYMBOL(lprocfs_alloc_stats);
-EXPORT_SYMBOL(lprocfs_free_stats);
-EXPORT_SYMBOL(lprocfs_clear_stats);
-EXPORT_SYMBOL(lprocfs_register_stats);
-EXPORT_SYMBOL(lprocfs_init_ops_stats);
-EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
-EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
-EXPORT_SYMBOL(lprocfs_alloc_md_stats);
-EXPORT_SYMBOL(lprocfs_free_obd_stats);
-EXPORT_SYMBOL(lprocfs_free_md_stats);
-EXPORT_SYMBOL(lprocfs_exp_setup);
-EXPORT_SYMBOL(lprocfs_exp_cleanup);
+int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
+                                     int count, int *eof, void *data)
+{
+        struct obd_device *dev = data;
+        struct client_obd *cli = &dev->u.cli;
+        int rc;
 
-EXPORT_SYMBOL(lprocfs_rd_u64);
-EXPORT_SYMBOL(lprocfs_rd_atomic);
-EXPORT_SYMBOL(lprocfs_wr_atomic);
-EXPORT_SYMBOL(lprocfs_rd_uint);
-EXPORT_SYMBOL(lprocfs_wr_uint);
-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_at_hist_helper);
-EXPORT_SYMBOL(lprocfs_rd_import);
-EXPORT_SYMBOL(lprocfs_rd_state);
-EXPORT_SYMBOL(lprocfs_rd_timeouts);
-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);
+        client_obd_list_lock(&cli->cl_loi_list_lock);
+        rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
+        client_obd_list_unlock(&cli->cl_loi_list_lock);
+        return rc;
+}
+EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
 
-EXPORT_SYMBOL(lprocfs_write_helper);
-EXPORT_SYMBOL(lprocfs_write_frac_helper);
-EXPORT_SYMBOL(lprocfs_read_frac_helper);
-EXPORT_SYMBOL(lprocfs_write_u64_helper);
-EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
-EXPORT_SYMBOL(lprocfs_stats_collect);
+int lprocfs_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *dev = data;
+       struct client_obd *cli = &dev->u.cli;
+       int rc;
+
+       client_obd_list_lock(&cli->cl_loi_list_lock);
+       rc = seq_printf(m, "%d\n", cli->cl_max_pages_per_rpc);
+       client_obd_list_unlock(&cli->cl_loi_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL(lprocfs_obd_max_pages_per_rpc_seq_show);
 #endif /* LPROCFS*/