Whamcloud - gitweb
LU-1448 llite: Prevent NULL pointer dereference on disabled OSC
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index 6926153..8b6b191 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, Whamcloud, Inc.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -38,9 +38,6 @@
  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
  */
 
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_CLASS
 
 #ifndef __KERNEL__
 #include <lustre_fsfilt.h>
 #include <lustre_log.h>
 #include <lustre/lustre_idl.h>
+#include <dt_object.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 */
@@ -92,9 +94,9 @@ struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
 {
         struct proc_dir_entry *temp;
 
-        LPROCFS_ENTRY();
+        LPROCFS_SRCH_ENTRY();
         temp = __lprocfs_srch(head, name);
-        LPROCFS_EXIT();
+        LPROCFS_SRCH_EXIT();
         return temp;
 }
 
@@ -401,9 +403,23 @@ 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));
 
+#ifdef HAVE_PROCFS_USERS
+                /* if procfs uses user count to synchronize deletion of
+                 * proc entry, there is no protection for rm_entry->data,
+                 * then lprocfs_fops_read and lprocfs_fops_write maybe
+                 * call proc_dir_entry->read_proc (or write_proc) with
+                 * proc_dir_entry->data == NULL, then cause kernel Oops.
+                 * see bug19706 for detailed information */
+
+                /* procfs won't free rm_entry->data if it isn't a LINK,
+                 * and Lustre won't use rm_entry->data if it is a LINK */
+                if (S_ISLNK(rm_entry->mode))
+                        rm_entry->data = NULL;
+#else
                 /* Now, the rm_entry->deleted flags is protected
                  * by _lprocfs_lock. */
                 rm_entry->data = NULL;
+#endif
                 remove_proc_entry(rm_entry->name, temp);
                 if (temp == parent)
                         break;
@@ -538,8 +554,9 @@ int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
 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) {
@@ -549,11 +566,26 @@ int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_blksize(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               *eof = 1;
+               rc = snprintf(page, count, "%d\n",
+                               (unsigned) osfs.os_bsize);
+       }
+       return rc;
+}
+
 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) {
@@ -569,11 +601,31 @@ int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_kbytestotal(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_blocks;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               *eof = 1;
+               rc = snprintf(page, count, LPU64"\n", result);
+       }
+       return rc;
+}
+
 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) {
@@ -589,11 +641,31 @@ int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_kbytesfree(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_bfree;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               *eof = 1;
+               rc = snprintf(page, count, LPU64"\n", result);
+       }
+       return rc;
+}
+
 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) {
@@ -609,11 +681,31 @@ int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_kbytesavail(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               __u32 blk_size = osfs.os_bsize >> 10;
+               __u64 result = osfs.os_bavail;
+
+               while (blk_size >>= 1)
+                       result <<= 1;
+
+               *eof = 1;
+               rc = snprintf(page, count, LPU64"\n", result);
+       }
+       return rc;
+}
+
 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
                           int *eof, void *data)
 {
-        struct obd_statfs osfs;
-        int rc = obd_statfs(data, &osfs,
+        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) {
@@ -624,11 +716,26 @@ int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_filestotal(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               *eof = 1;
+               rc = snprintf(page, count, LPU64"\n", osfs.os_files);
+       }
+
+       return rc;
+}
+
 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
                          int *eof, void *data)
 {
-        struct obd_statfs osfs;
-        int rc = obd_statfs(data, &osfs,
+        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) {
@@ -638,6 +745,19 @@ int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
         return rc;
 }
 
+int lprocfs_osd_rd_filesfree(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       struct dt_device *dt = data;
+       struct obd_statfs osfs;
+       int rc = dt_statfs(NULL, dt, &osfs);
+       if (!rc) {
+               *eof = 1;
+               rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
+       }
+       return rc;
+}
+
 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
                            int *eof, void *data)
 {
@@ -686,10 +806,12 @@ int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
 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;
+       unsigned int            num_entry;
+       struct lprocfs_counter  t;
+       struct lprocfs_counter *percpu_cntr;
+       int                     centry;
+       int                     i;
+       unsigned long           flags = 0;
 
         memset(cnt, 0, sizeof(*cnt));
 
@@ -701,13 +823,12 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
 
         cnt->lc_min = LC_MIN_INIT;
 
-        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
+       num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
 
-        for (i = 0; i < num_cpu; i++) {
-                percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
+       for (i = 0; i < num_entry; i++) {
+               if (stats->ls_percpu[i] == NULL)
+                       continue;
+               percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
 
                 do {
                         centry = cfs_atomic_read(&percpu_cntr-> \
@@ -730,7 +851,8 @@ void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
                 cnt->lc_sumsquare += t.lc_sumsquare;
         }
 
-        cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
+       cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
+       lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
 }
 
 /**
@@ -793,10 +915,17 @@ static const char *obd_connect_names[] = {
         "large_ea",
         "full20",
         "layout_lock",
+        "64bithash",
+        "object_max_bytes",
+        "imp_recov",
+        "jobstats",
+        "umask",
+        "einprogress",
+        "grant_param",
         NULL
 };
 
-static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
+int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
 {
         __u64 mask = 1;
         int i, ret = 0;
@@ -812,6 +941,7 @@ static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
                                 ret ? sep : "", flags & ~(mask - 1));
         return ret;
 }
+EXPORT_SYMBOL(obd_connect_flags2str);
 
 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                       int *eof, void *data)
@@ -832,10 +962,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,
                                    ", ");
@@ -855,17 +987,18 @@ int lprocfs_rd_import(char *page, char **start, off_t off, int count,
                               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,
+                     cfs_atomic_read(&imp->imp_inval_count));
+       cfs_spin_unlock(&imp->imp_lock);
 
         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
         if (ret.lc_count != 0) {
@@ -1122,10 +1255,8 @@ static void lprocfs_free_client_stats(struct nid_stat *client_stat)
                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));
-
-        cfs_hlist_del_init(&client_stat->nid_hash);
+                 "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);
@@ -1146,41 +1277,47 @@ 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;
 }
 
 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 percpusize;
+       unsigned int num_entry;
 
         if (num == 0)
                 return NULL;
 
-        if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
-                num_cpu = 1;
-        else
-                num_cpu = cfs_num_possible_cpus();
+        if (lprocfs_no_percpu_stats != 0)
+                flags |= LPROCFS_STATS_FLAG_NOPERCPU;
 
-        OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
-        if (stats == NULL)
-                return NULL;
+       if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
+               num_entry = 1;
+       else
+               num_entry = cfs_num_possible_cpus() + 1;
+
+       /* alloc percpu pointers for all possible cpu slots */
+       OBD_ALLOC(stats, offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
+       if (stats == NULL)
+               return NULL;
 
+       stats->ls_num = num;
+       stats->ls_biggest_alloc_num = 1;
         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
                 stats->ls_flags = flags;
                 cfs_spin_lock_init(&stats->ls_lock);
@@ -1189,76 +1326,84 @@ struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
                 stats->ls_flags = 0;
         }
 
-        percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
-        if (num_cpu > 1)
-                percpusize = CFS_L1_CACHE_ALIGN(percpusize);
+       percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
+       if (num_entry > 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;
+       /* for no percpu area, the 0th entry is for real use,
+        * for percpu area, the 0th entry is for intialized entry template */
+       OBD_ALLOC(stats->ls_percpu[0], percpusize);
+       if (stats->ls_percpu[0] == NULL) {
+               OBD_FREE(stats,
+                        offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
+               stats = NULL;
+       }
+       return 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 = cfs_num_possible_cpus() + 1;
 
-        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 = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
+       if (num_entry > 1)
+               percpusize = CFS_L1_CACHE_ALIGN(percpusize);
+       for (i = 0; i < num_entry; i++)
+               if (stats->ls_percpu[i] != NULL)
+                       OBD_FREE(stats->ls_percpu[i], percpusize);
+       OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
 }
 
 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 int            percpusize;
+       unsigned long           flags = 0;
+
+       num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+
+       percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
+       if (num_entry > 1)
+               percpusize = CFS_L1_CACHE_ALIGN(percpusize);
+
+       for (i = 0; i < num_entry; i++) {
+               if (stats->ls_percpu[i] == NULL)
+                       continue;
+               /* the 1st percpu entry was statically allocated in
+                * lprocfs_alloc_stats() */
+               if (i > 0) {
+                       OBD_FREE(stats->ls_percpu[i], percpusize);
+                       stats->ls_percpu[i] = NULL;
+                       continue;
+               }
+               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, LPROCFS_GET_NUM_CPU, &flags);
 }
 
 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
@@ -1393,28 +1538,23 @@ int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
 }
 
 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
-                          unsigned conf, const char *name, const char *units)
+                         unsigned conf, const char *name, const char *units)
 {
-        struct lprocfs_counter *c;
-        int i;
-        unsigned int num_cpu;
+       struct lprocfs_counter *c     = &(stats->ls_percpu[0]->lp_cntr[index]);
+       unsigned long           flags = 0;
 
-        LASSERT(stats != NULL);
+       LASSERT(stats != NULL);
+       LASSERT(stats->ls_percpu[0] != 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);
+       lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+       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, LPROCFS_GET_NUM_CPU, &flags);
 }
 EXPORT_SYMBOL(lprocfs_counter_init);
 
@@ -1757,7 +1897,7 @@ 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)
+static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
 {
         struct nid_stat *stat = obj;
         int i;
@@ -1803,8 +1943,7 @@ int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
 }
 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
 
-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;
@@ -1844,15 +1983,16 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
                old_stat, libcfs_nid2str(*nid),
                cfs_atomic_read(&new_stat->nid_exp_ref_count));
 
+        /* We need to release old stats because lprocfs_exp_cleanup() hasn't
+         * been and will never be called. */
+        if (exp->exp_nid_stats) {
+                nidstat_putref(exp->exp_nid_stats);
+                exp->exp_nid_stats = NULL;
+        }
+
         /* 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);
         }
@@ -2249,6 +2389,9 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
                                          obd->obd_version_recov ? "ON" : "OFF")<=0)
                         goto out;
+                if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
+                                         obd->obd_no_ir ? "OFF" : "ON") <= 0)
+                        goto out;
                 goto fclose;
         }
 
@@ -2258,11 +2401,15 @@ 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,
+                                 cfs_atomic_read(&obd->obd_connected_clients),
                                  obd->obd_max_recoverable_clients) <= 0)
                 goto out;
         /* Number of clients that have completed recovery */
@@ -2275,7 +2422,7 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
                 <=0)
                 goto out;
         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
-                                 obd->obd_connected_clients -
+                                 cfs_atomic_read(&obd->obd_connected_clients) -
                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
                 <=0)
                 goto out;
@@ -2300,6 +2447,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)
 {
@@ -2333,7 +2510,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);
 
@@ -2366,6 +2543,33 @@ int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
 }
 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
 
+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;
+
+        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);
+
+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_target *target = &obd->u.obt;
+
+        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_target_rd_instance);
+
 EXPORT_SYMBOL(lprocfs_register);
 EXPORT_SYMBOL(lprocfs_srch);
 EXPORT_SYMBOL(lprocfs_remove);