Whamcloud - gitweb
LU-9091 obdclass: allow bare KMGTPE param suffix
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index 63b28a8..71d1edd 100644 (file)
@@ -207,110 +207,6 @@ lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
 }
 EXPORT_SYMBOL(lprocfs_add_vars);
 
-void ldebugfs_remove(struct dentry **entryp)
-{
-       debugfs_remove_recursive(*entryp);
-       *entryp = NULL;
-}
-EXPORT_SYMBOL_GPL(ldebugfs_remove);
-
-#ifndef HAVE_REMOVE_PROC_SUBTREE
-/* for b=10866, global variable */
-DECLARE_RWSEM(_lprocfs_lock);
-EXPORT_SYMBOL(_lprocfs_lock);
-
-static 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 || IS_ERR(root))
-               return;
-
-       parent = root->parent;
-       LASSERT(parent != NULL);
-
-       while (1) {
-               while (temp->subdir)
-                       temp = temp->subdir;
-
-               rm_entry = temp;
-               temp = temp->parent;
-
-               /*
-                * Memory corruption once caused this to fail, and
-                * without this LASSERT we would loop here forever.
-                */
-               LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
-                        "0x%p  %s/%s len %d\n", rm_entry, temp->name,
-                        rm_entry->name, (int)strlen(rm_entry->name));
-
-               remove_proc_entry(rm_entry->name, temp);
-               if (temp == parent)
-                       break;
-       }
-}
-
-int remove_proc_subtree(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);
-
-       down_write(&_lprocfs_lock);
-       /* 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);
-
-       up_write(&_lprocfs_lock);
-       return 0;
-}
-#endif /* !HAVE_REMOVE_PROC_SUBTREE */
-
-#ifndef HAVE_PROC_REMOVE
-void proc_remove(struct proc_dir_entry *de)
-{
-#ifndef HAVE_REMOVE_PROC_SUBTREE
-       down_write(&_lprocfs_lock); /* search vs remove race */
-       lprocfs_remove_nolock(&de);
-       up_write(&_lprocfs_lock);
-#else
-       if (de)
-               remove_proc_subtree(de->name, de->parent);
-#endif
-}
-#endif
-
 void lprocfs_remove(struct proc_dir_entry **rooth)
 {
        proc_remove(*rooth);
@@ -325,31 +221,6 @@ void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 }
 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
 
-struct dentry *ldebugfs_register(const char *name, struct dentry *parent,
-                                struct lprocfs_vars *list, void *data)
-{
-       struct dentry *entry;
-
-       entry = debugfs_create_dir(name, parent);
-       if (IS_ERR_OR_NULL(entry)) {
-               entry = entry ?: ERR_PTR(-ENOMEM);
-               goto out;
-       }
-
-       if (!IS_ERR_OR_NULL(list)) {
-               int rc;
-
-               rc = ldebugfs_add_vars(entry, list, data);
-               if (rc) {
-                       debugfs_remove(entry);
-                       entry = ERR_PTR(rc);
-               }
-       }
-out:
-       return entry;
-}
-EXPORT_SYMBOL_GPL(ldebugfs_register);
-
 struct proc_dir_entry *
 lprocfs_register(const char *name, struct proc_dir_entry *parent,
                 struct lprocfs_vars *list, void *data)
@@ -523,17 +394,18 @@ ssize_t conn_uuid_show(struct kobject *kobj, struct attribute *attr, char *buf)
 {
        struct obd_device *obd = container_of(kobj, struct obd_device,
                                              obd_kset.kobj);
+       struct obd_import *imp;
        struct ptlrpc_connection *conn;
        ssize_t count;
 
-       LPROCFS_CLIMP_CHECK(obd);
-       conn = obd->u.cli.cl_import->imp_connection;
-       if (conn && obd->u.cli.cl_import)
-               count = sprintf(buf, "%s\n", conn->c_remote_uuid.uuid);
-       else
-               count = sprintf(buf, "%s\n", "<none>");
+       with_imp_locked(obd, imp, count) {
+               conn = imp->imp_connection;
+               if (conn)
+                       count = sprintf(buf, "%s\n", conn->c_remote_uuid.uuid);
+               else
+                       count = sprintf(buf, "%s\n", "<none>");
+       }
 
-       LPROCFS_CLIMP_EXIT(obd);
        return count;
 }
 EXPORT_SYMBOL(conn_uuid_show);
@@ -546,13 +418,12 @@ int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data)
        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);
-       seq_printf(m, "%s\t%s%s\n", obd2cli_tgt(obd), imp_state_name,
-                  imp->imp_deactive ? "\tDEACTIVATED" : "");
+       with_imp_locked(obd, imp, rc) {
+               imp_state_name = ptlrpc_import_state_name(imp->imp_state);
+               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);
@@ -784,8 +655,9 @@ static const char *obd_connect_names[] = {
        "selinux_policy",       /* 0x400 */
        "lsom",                 /* 0x800 */
        "pcc",                  /* 0x1000 */
-       "plain_layout",         /* 0x2000 */
+       "crush",                /* 0x2000 */
        "async_discard",        /* 0x4000 */
+       "client_encryption",    /* 0x8000 */
        NULL
 };
 
@@ -919,22 +791,19 @@ obd_connect_data_seqprint(struct seq_file *m, struct obd_connect_data *ocd)
                           ocd->ocd_maxmodrpcs);
 }
 
-int lprocfs_import_seq_show(struct seq_file *m, void *data)
+static void lprocfs_import_seq_show_locked(struct seq_file *m,
+                                          struct obd_device *obd,
+                                          struct obd_import *imp)
 {
        char nidstr[LNET_NIDSTR_SIZE];
        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"
@@ -983,16 +852,13 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
        spin_unlock(&imp->imp_lock);
 
        if (!obd->obd_svc_stats)
-               goto out_climp;
+               return;
 
        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
+       if (ret.lc_count != 0)
+               ret.lc_sum = div64_s64(ret.lc_sum, ret.lc_count);
+       else
                ret.lc_sum = 0;
        seq_printf(m, "    rpcs:\n"
                   "       inflight: %u\n"
@@ -1031,10 +897,7 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                                      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;
+                       ret.lc_sum = div64_s64(ret.lc_sum, ret.lc_count);
                        seq_printf(m, "    %s_data_averages:\n"
                                   "       bytes_per_rpc: %llu\n",
                                   rw ? "write" : "read",
@@ -1045,10 +908,7 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                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;
+                       ret.lc_sum = div64_s64(ret.lc_sum, ret.lc_count);
                        seq_printf(m, "       %s_per_rpc: %llu\n",
                                   header->lc_units, ret.lc_sum);
                        j = (int)ret.lc_sum;
@@ -1057,10 +917,18 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                                           k / j, (100 * k / j) % 100);
                }
        }
+}
 
-out_climp:
-       LPROCFS_CLIMP_EXIT(obd);
-       return 0;
+int lprocfs_import_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = (struct obd_device *)data;
+       struct obd_import *imp;
+       int rv;
+
+       LASSERT(obd != NULL);
+       with_imp_locked(obd, imp, rv)
+               lprocfs_import_seq_show_locked(m, obd, imp);
+       return rv;
 }
 EXPORT_SYMBOL(lprocfs_import_seq_show);
 
@@ -1069,26 +937,25 @@ 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;
+       int rc;
 
        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, " - [ %lld, %s ]\n", (s64)ish->ish_time,
-                          ptlrpc_import_state_name(ish->ish_state));
+       with_imp_locked(obd, imp, rc) {
+               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, " - [ %lld, %s ]\n", (s64)ish->ish_time,
+                                  ptlrpc_import_state_name(ish->ish_state));
+               }
        }
 
-       LPROCFS_CLIMP_EXIT(obd);
-       return 0;
+       return rc;
 }
 EXPORT_SYMBOL(lprocfs_state_seq_show);
 
@@ -1103,17 +970,15 @@ int lprocfs_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
 EXPORT_SYMBOL(lprocfs_at_hist_helper);
 
 /* See also ptlrpc_lprocfs_timeouts_show_seq */
-int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
+static void lprocfs_timeouts_seq_show_locked(struct seq_file *m,
+                                            struct obd_device *obd,
+                                            struct obd_import *imp)
 {
-       struct obd_device *obd = (struct obd_device *)data;
-       struct obd_import *imp;
        unsigned int cur, worst;
        time64_t now, worstt;
        int i;
 
        LASSERT(obd != NULL);
-       LPROCFS_CLIMP_CHECK(obd);
-       imp = obd->u.cli.cl_import;
 
        now = ktime_get_real_seconds();
 
@@ -1140,9 +1005,17 @@ int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
                           (s64)(now - worstt));
                lprocfs_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
        }
+}
 
-       LPROCFS_CLIMP_EXIT(obd);
-       return 0;
+int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
+{
+       struct obd_device *obd = (struct obd_device *)data;
+       struct obd_import *imp;
+       int rc;
+
+       with_imp_locked(obd, imp, rc)
+               lprocfs_timeouts_seq_show_locked(m, obd, imp);
+       return rc;
 }
 EXPORT_SYMBOL(lprocfs_timeouts_seq_show);
 
@@ -1151,16 +1024,19 @@ int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data)
        struct obd_device *obd = data;
        __u64 flags;
        __u64 flags2;
+       struct obd_import *imp;
+       int rc;
 
-       LPROCFS_CLIMP_CHECK(obd);
-       flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
-       flags2 = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags2;
-       seq_printf(m, "flags=%#llx\n", flags);
-       seq_printf(m, "flags2=%#llx\n", flags2);
-       obd_connect_seq_flags2str(m, flags, flags2, "\n");
-       seq_printf(m, "\n");
-       LPROCFS_CLIMP_EXIT(obd);
-       return 0;
+       with_imp_locked(obd, imp, rc) {
+               flags = imp->imp_connect_data.ocd_connect_flags;
+               flags2 = imp->imp_connect_data.ocd_connect_flags2;
+               seq_printf(m, "flags=%#llx\n", flags);
+               seq_printf(m, "flags2=%#llx\n", flags2);
+               obd_connect_seq_flags2str(m, flags, flags2, "\n");
+               seq_printf(m, "\n");
+       }
+
+       return rc;
 }
 EXPORT_SYMBOL(lprocfs_connect_flags_seq_show);
 
@@ -1223,21 +1099,9 @@ int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only)
 
        if (!obd->obd_type->typ_procroot)
                debugfs_vars = obd->obd_vars;
-       obd->obd_debugfs_entry = ldebugfs_register(obd->obd_name,
-                                                  obd->obd_type->typ_debugfs_entry,
-                                                  debugfs_vars, obd);
-       if (IS_ERR_OR_NULL(obd->obd_debugfs_entry)) {
-               rc = obd->obd_debugfs_entry ? PTR_ERR(obd->obd_debugfs_entry)
-                                           : -ENOMEM;
-               CERROR("error %d setting up debugfs for %s\n",
-                      rc, obd->obd_name);
-               obd->obd_debugfs_entry = NULL;
-
-               sysfs_remove_files(&obd->obd_kset.kobj, obd->obd_attrs);
-               obd->obd_attrs = NULL;
-               kset_unregister(&obd->obd_kset);
-               return rc;
-       }
+       obd->obd_debugfs_entry = debugfs_create_dir(
+               obd->obd_name, obd->obd_type->typ_debugfs_entry);
+       ldebugfs_add_vars(obd->obd_debugfs_entry, debugfs_vars, obd);
 
        if (obd->obd_proc_entry || !obd->obd_type->typ_procroot)
                GOTO(already_registered, rc);
@@ -1250,7 +1114,9 @@ int lprocfs_obd_setup(struct obd_device *obd, bool uuid_only)
                CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
                obd->obd_proc_entry = NULL;
 
-               ldebugfs_remove(&obd->obd_debugfs_entry);
+               debugfs_remove_recursive(obd->obd_debugfs_entry);
+               obd->obd_debugfs_entry = NULL;
+
                sysfs_remove_files(&obd->obd_kset.kobj, obd->obd_attrs);
                obd->obd_attrs = NULL;
                kset_unregister(&obd->obd_kset);
@@ -1277,8 +1143,8 @@ int lprocfs_obd_cleanup(struct obd_device *obd)
                obd->obd_proc_entry = NULL;
        }
 
-       if (!IS_ERR_OR_NULL(obd->obd_debugfs_entry))
-               ldebugfs_remove(&obd->obd_debugfs_entry);
+       debugfs_remove_recursive(obd->obd_debugfs_entry);
+       obd->obd_debugfs_entry = NULL;
 
        /* obd device never allocated a kset */
        if (!obd->obd_kset.kobj.state_initialized)
@@ -1361,8 +1227,7 @@ struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
        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));
+       CFS_ALLOC_PTR_ARRAY(stats->ls_cnt_header, stats->ls_num);
        if (!stats->ls_cnt_header)
                goto fail;
 
@@ -1409,8 +1274,7 @@ void lprocfs_free_stats(struct lprocfs_stats **statsh)
                if (stats->ls_percpu[i])
                        LIBCFS_FREE(stats->ls_percpu[i], percpusize);
        if (stats->ls_cnt_header)
-               LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
-                                       sizeof(struct lprocfs_counter_header));
+               CFS_FREE_PTR_ARRAY(stats->ls_cnt_header, stats->ls_num);
        LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
 }
 EXPORT_SYMBOL(lprocfs_free_stats);
@@ -1547,10 +1411,6 @@ static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc;
 
-       rc = LPROCFS_ENTRY_CHECK(inode);
-       if (rc < 0)
-               return rc;
-
        rc = seq_open(file, &lprocfs_stats_seq_sops);
        if (rc)
                return rc;
@@ -1771,6 +1631,193 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
 }
 EXPORT_SYMBOL(lprocfs_read_helper);
 
+/**
+ * string_to_size - convert ASCII string representing a numerical
+ *                 value with optional units to 64-bit binary value
+ *
+ * @size:      The numerical value extract out of @buffer
+ * @buffer:    passed in string to parse
+ * @count:     length of the @buffer
+ *
+ * This function returns a 64-bit binary value if @buffer contains a valid
+ * numerical string. The string is parsed to 3 significant figures after
+ * the decimal point. Support the string containing an optional units at
+ * the end which can be base 2 or base 10 in value. If no units are given
+ * the string is assumed to just a numerical value.
+ *
+ * Returns:    @count if the string is successfully parsed,
+ *             -errno on invalid input strings. Error values:
+ *
+ *  - ``-EINVAL``: @buffer is not a proper numerical string
+ *  - ``-EOVERFLOW``: results does not fit into 64 bits.
+ *  - ``-E2BIG ``: @buffer is too large (not a valid number)
+ */
+int string_to_size(u64 *size, const char *buffer, size_t count)
+{
+       /* For string_get_size() it can support values above exabytes,
+        * (ZiB, YiB) due to breaking the return value into a size and
+        * bulk size to avoid 64 bit overflow. We don't break the size
+        * up into block size units so we don't support ZiB or YiB.
+        */
+       static const char *const units_10[] = {
+               "kB", "MB", "GB", "TB", "PB", "EB",
+       };
+       static const char *const units_2[] = {
+               "K",  "M",  "G",  "T",  "P",  "E",
+       };
+       static const char *const *const units_str[] = {
+               [STRING_UNITS_2] = units_2,
+               [STRING_UNITS_10] = units_10,
+       };
+       static const unsigned int coeff[] = {
+               [STRING_UNITS_10] = 1000,
+               [STRING_UNITS_2] = 1024,
+       };
+       enum string_size_units unit = STRING_UNITS_2;
+       u64 whole, blk_size = 1;
+       char kernbuf[22], *end;
+       size_t len = count;
+       int rc;
+       int i;
+
+       if (count >= sizeof(kernbuf)) {
+               CERROR("count %zd > buffer %zd\n", count, sizeof(kernbuf));
+               return -E2BIG;
+       }
+
+       *size = 0;
+       /* The "iB" suffix is optionally allowed for indicating base-2 numbers.
+        * If suffix is only "B" and not "iB" then we treat it as base-10.
+        */
+       end = strstr(buffer, "B");
+       if (end && *(end - 1) != 'i')
+               unit = STRING_UNITS_10;
+
+       i = unit == STRING_UNITS_2 ? ARRAY_SIZE(units_2) - 1 :
+                                    ARRAY_SIZE(units_10) - 1;
+       do {
+               end = strnstr(buffer, units_str[unit][i], count);
+               if (end) {
+                       for (; i >= 0; i--)
+                               blk_size *= coeff[unit];
+                       len = end - buffer;
+                       break;
+               }
+       } while (i--);
+
+       /* as 'B' is a substring of all units, we need to handle it
+        * separately.
+        */
+       if (!end) {
+               /* 'B' is only acceptable letter at this point */
+               end = strnchr(buffer, count, 'B');
+               if (end) {
+                       len = end - buffer;
+
+                       if (count - len > 2 ||
+                           (count - len == 2 && strcmp(end, "B\n") != 0)) {
+                               CDEBUG(D_INFO, "unknown suffix '%s'\n", buffer);
+                               return -EINVAL;
+                       }
+               }
+               /* kstrtoull will error out if it has non digits */
+               goto numbers_only;
+       }
+
+       end = strnchr(buffer, count, '.');
+       if (end) {
+               /* need to limit 3 decimal places */
+               char rem[4] = "000";
+               u64 frac = 0;
+               size_t off;
+
+               len = end - buffer;
+               end++;
+
+               /* limit to 3 decimal points */
+               off = min_t(size_t, 3, strspn(end, "0123456789"));
+               /* need to limit frac_d to a u32 */
+               memcpy(rem, end, off);
+               rc = kstrtoull(rem, 10, &frac);
+               if (rc)
+                       return rc;
+
+               if (fls64(frac) + fls64(blk_size) - 1 > 64)
+                       return -EOVERFLOW;
+
+               frac *= blk_size;
+               do_div(frac, 1000);
+               *size += frac;
+       }
+numbers_only:
+       snprintf(kernbuf, sizeof(kernbuf), "%.*s", (int)len, buffer);
+       rc = kstrtoull(kernbuf, 10, &whole);
+       if (rc)
+               return rc;
+
+       if (whole != 0 && fls64(whole) + fls64(blk_size) - 1 > 64)
+               return -EOVERFLOW;
+
+       *size += whole * blk_size;
+
+       return count;
+}
+EXPORT_SYMBOL(string_to_size);
+
+/**
+ * sysfs_memparse - parse a ASCII string to 64-bit binary value,
+ *                 with optional units
+ *
+ * @buffer:    kernel pointer to input string
+ * @count:     number of bytes in the input @buffer
+ * @val:       (output) binary value returned to caller
+ * @defunit:   default unit suffix to use if none is provided
+ *
+ * Parses a string into a number. The number stored at @buffer is
+ * potentially suffixed with K, M, G, T, P, E. Besides these other
+ * valid suffix units are shown in the string_to_size() function.
+ * If the string lacks a suffix then the defunit is used. The defunit
+ * should be given as a binary unit (e.g. MiB) as that is the standard
+ * for tunables in Lustre. If no unit suffix is given (e.g. 'G'), then
+ * it is assumed to be in binary units.
+ *
+ * Returns:    0 on success or -errno on failure.
+ */
+int sysfs_memparse(const char *buffer, size_t count, u64 *val,
+                  const char *defunit)
+{
+       const char *param = buffer;
+       char tmp_buf[23];
+       int rc;
+
+       count = strlen(buffer);
+       while (count > 0 && isspace(buffer[count - 1]))
+               count--;
+
+       if (!count)
+               RETURN(-EINVAL);
+
+       /* If there isn't already a unit on this value, append @defunit.
+        * Units of 'B' don't affect the value, so don't bother adding.
+        */
+       if (!isalpha(buffer[count - 1]) && defunit[0] != 'B') {
+               if (count + 3 >= sizeof(tmp_buf)) {
+                       CERROR("count %zd > size %zd\n", count, sizeof(param));
+                       RETURN(-E2BIG);
+               }
+
+               scnprintf(tmp_buf, sizeof(tmp_buf), "%.*s%s", (int)count,
+                         buffer, defunit);
+               param = tmp_buf;
+               count = strlen(param);
+       }
+
+       rc = string_to_size(val, param, count);
+
+       return rc < 0 ? rc : 0;
+}
+EXPORT_SYMBOL(sysfs_memparse);
+
 /* Obtains the conversion factor for the unit specified */
 static int get_mult(char unit, __u64 *mult)
 {
@@ -1781,15 +1828,19 @@ static int get_mult(char unit, __u64 *mult)
        case 'p':
        case 'P':
                units <<= 10;
+               /* fallthrough */
        case 't':
        case 'T':
                units <<= 10;
+               /* fallthrough */
        case 'g':
        case 'G':
                units <<= 10;
+               /* fallthrough */
        case 'm':
        case 'M':
                units <<= 10;
+               /* fallthrough */
        case 'k':
        case 'K':
                units <<= 10;
@@ -1984,34 +2035,31 @@ static int str_to_u64_parse(char *buffer, unsigned long count,
  * have a unit as the last character. The function handles overflow/underflow
  * of the signed integer.
  */
-static int str_to_s64_internal(const char __user *buffer, unsigned long count,
-                              __s64 *val, __u64 def_mult, bool allow_units)
+int lu_str_to_s64(char *buffer, unsigned long count, __s64 *val, char defunit)
 {
-       char kernbuf[22];
+       __u64 mult = 1;
        __u64 tmp;
        unsigned int offset = 0;
        int signed sign = 1;
        __u64 max = LLONG_MAX;
        int rc = 0;
 
-       if (count > (sizeof(kernbuf) - 1))
-               return -EINVAL;
-
-       if (copy_from_user(kernbuf, buffer, count))
-               return -EFAULT;
-
-       kernbuf[count] = '\0';
+       if (defunit != '1') {
+               rc = get_mult(defunit, &mult);
+               if (rc)
+                       return rc;
+       }
 
        /* keep track of our sign */
-       if (*kernbuf == '-') {
+       if (*buffer == '-') {
                sign = -1;
                offset++;
                /* equivalent to max = -LLONG_MIN, avoids overflow */
                max++;
        }
 
-       rc = str_to_u64_parse(kernbuf + offset, count - offset,
-                             &tmp, def_mult, allow_units);
+       rc = str_to_u64_parse(buffer + offset, count - offset,
+                             &tmp, mult, true);
        if (rc)
                return rc;
 
@@ -2023,7 +2071,31 @@ static int str_to_s64_internal(const char __user *buffer, unsigned long count,
 
        return 0;
 }
+EXPORT_SYMBOL(lu_str_to_s64);
+
+/* identical to s64 version, but does not handle overflow */
+static int str_to_u64_internal(const char __user *buffer, unsigned long count,
+                              __u64 *val, __u64 def_mult, bool allow_units)
+{
+       char kernbuf[22];
+       unsigned int offset = 0;
+       int rc = 0;
+
+       if (count > (sizeof(kernbuf) - 1))
+               return -EINVAL;
+
+       if (copy_from_user(kernbuf, buffer, count))
+               return -EFAULT;
 
+       kernbuf[count] = '\0';
+
+       rc = str_to_u64_parse(kernbuf + offset, count - offset,
+                             val, def_mult, allow_units);
+       if (rc)
+               return rc;
+
+       return 0;
+}
 /**
  * Convert a user string into a signed 64 bit number. This function produces
  * an error when the value parsed from the string times multiplier underflows or
@@ -2044,6 +2116,24 @@ static int str_to_s64_internal(const char __user *buffer, unsigned long count,
 int lprocfs_str_with_units_to_s64(const char __user *buffer,
                                  unsigned long count, __s64 *val, char defunit)
 {
+       char kernbuf[22];
+
+       if (count > (sizeof(kernbuf) - 1))
+               return -EINVAL;
+
+       if (copy_from_user(kernbuf, buffer, count))
+               return -EFAULT;
+
+       kernbuf[count] = '\0';
+
+       return lu_str_to_s64(kernbuf, count, val, defunit);
+}
+EXPORT_SYMBOL(lprocfs_str_with_units_to_s64);
+
+/* identical to s64 version above, but does not handle overflow */
+int lprocfs_str_with_units_to_u64(const char __user *buffer,
+                                 unsigned long count, __u64 *val, char defunit)
+{
        __u64 mult = 1;
        int rc;
 
@@ -2053,9 +2143,9 @@ int lprocfs_str_with_units_to_s64(const char __user *buffer,
                        return rc;
        }
 
-       return str_to_s64_internal(buffer, count, val, mult, true);
+       return str_to_u64_internal(buffer, count, val, mult, true);
 }
-EXPORT_SYMBOL(lprocfs_str_with_units_to_s64);
+EXPORT_SYMBOL(lprocfs_str_with_units_to_u64);
 
 char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
 {
@@ -2141,14 +2231,14 @@ int lprocfs_seq_create(struct proc_dir_entry *parent,
 }
 EXPORT_SYMBOL(lprocfs_seq_create);
 
-int lprocfs_obd_seq_create(struct obd_device *dev,
+int lprocfs_obd_seq_create(struct obd_device *obd,
                           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));
+       return lprocfs_seq_create(obd->obd_proc_entry, name,
+                                 mode, seq_fops, data);
 }
 EXPORT_SYMBOL(lprocfs_obd_seq_create);
 
@@ -2219,8 +2309,8 @@ EXPORT_SYMBOL_GPL(lustre_sysfs_ops);
 
 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;
+       struct obd_device *obd = data;
+       struct client_obd *cli = &obd->u.cli;
 
        spin_lock(&cli->cl_loi_list_lock);
        seq_printf(m, "%d\n", cli->cl_max_pages_per_rpc);
@@ -2233,49 +2323,57 @@ ssize_t lprocfs_obd_max_pages_per_rpc_seq_write(struct file *file,
                                                const char __user *buffer,
                                                size_t count, loff_t *off)
 {
-       struct obd_device *dev =
-               ((struct seq_file *)file->private_data)->private;
-       struct client_obd *cli = &dev->u.cli;
-       struct obd_connect_data *ocd = &cli->cl_import->imp_connect_data;
+       struct seq_file *m = file->private_data;
+       struct obd_device *obd = m->private;
+       struct client_obd *cli = &obd->u.cli;
+       struct obd_import *imp;
+       struct obd_connect_data *ocd;
        int chunk_mask, rc;
-       s64 val;
+       char kernbuf[22];
+       u64 val;
+
+       if (count > sizeof(kernbuf) - 1)
+               return -EINVAL;
+
+       if (copy_from_user(kernbuf, buffer, count))
+               return -EFAULT;
+
+       kernbuf[count] = '\0';
 
-       rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '1');
+       rc = sysfs_memparse(kernbuf, count, &val, "B");
        if (rc)
                return rc;
-       if (val < 0)
-               return -ERANGE;
 
        /* if the max_pages is specified in bytes, convert to pages */
        if (val >= ONE_MB_BRW_SIZE)
                val >>= PAGE_SHIFT;
 
-       LPROCFS_CLIMP_CHECK(dev);
-
-       chunk_mask = ~((1 << (cli->cl_chunkbits - PAGE_SHIFT)) - 1);
-       /* max_pages_per_rpc must be chunk aligned */
-       val = (val + ~chunk_mask) & chunk_mask;
-       if (val == 0 || (ocd->ocd_brw_size != 0 &&
-                        val > ocd->ocd_brw_size >> PAGE_SHIFT)) {
-               LPROCFS_CLIMP_EXIT(dev);
-               return -ERANGE;
+       with_imp_locked(obd, imp, rc) {
+               ocd = &imp->imp_connect_data;
+               chunk_mask = ~((1 << (cli->cl_chunkbits - PAGE_SHIFT)) - 1);
+               /* max_pages_per_rpc must be chunk aligned */
+               val = (val + ~chunk_mask) & chunk_mask;
+               if (val == 0 || (ocd->ocd_brw_size != 0 &&
+                                val > ocd->ocd_brw_size >> PAGE_SHIFT)) {
+                       rc = -ERANGE;
+               } else {
+                       spin_lock(&cli->cl_loi_list_lock);
+                       cli->cl_max_pages_per_rpc = val;
+                       client_adjust_max_dirty(cli);
+                       spin_unlock(&cli->cl_loi_list_lock);
+               }
        }
-       spin_lock(&cli->cl_loi_list_lock);
-       cli->cl_max_pages_per_rpc = val;
-       client_adjust_max_dirty(cli);
-       spin_unlock(&cli->cl_loi_list_lock);
 
-       LPROCFS_CLIMP_EXIT(dev);
-       return count;
+       return rc ?: count;
 }
 EXPORT_SYMBOL(lprocfs_obd_max_pages_per_rpc_seq_write);
 
 ssize_t short_io_bytes_show(struct kobject *kobj, struct attribute *attr,
                            char *buf)
 {
-       struct obd_device *dev = container_of(kobj, struct obd_device,
+       struct obd_device *obd = container_of(kobj, struct obd_device,
                                              obd_kset.kobj);
-       struct client_obd *cli = &dev->u.cli;
+       struct client_obd *cli = &obd->u.cli;
        int rc;
 
        spin_lock(&cli->cl_loi_list_lock);
@@ -2291,32 +2389,30 @@ EXPORT_SYMBOL(short_io_bytes_show);
 ssize_t short_io_bytes_store(struct kobject *kobj, struct attribute *attr,
                             const char *buffer, size_t count)
 {
-       struct obd_device *dev = container_of(kobj, struct obd_device,
+       struct obd_device *obd = container_of(kobj, struct obd_device,
                                              obd_kset.kobj);
-       struct client_obd *cli = &dev->u.cli;
-       u32 val;
+       struct client_obd *cli = &obd->u.cli;
+       u64 val;
        int rc;
 
-       LPROCFS_CLIMP_CHECK(dev);
-
-       rc = kstrtouint(buffer, 0, &val);
-       if (rc)
-               GOTO(out, rc);
+       if (strcmp(buffer, "-1") == 0) {
+               val = OBD_DEF_SHORT_IO_BYTES;
+       } else {
+               rc = sysfs_memparse(buffer, count, &val, "B");
+               if (rc)
+                       GOTO(out, rc);
+       }
 
-       if (val && (val < MIN_SHORT_IO_BYTES || val > OBD_MAX_SHORT_IO_BYTES))
+       if (val && (val < MIN_SHORT_IO_BYTES || val > LNET_MTU))
                GOTO(out, rc = -ERANGE);
 
        rc = count;
 
        spin_lock(&cli->cl_loi_list_lock);
-       if (val > (cli->cl_max_pages_per_rpc << PAGE_SHIFT))
-               rc = -ERANGE;
-       else
-               cli->cl_max_short_io_bytes = val;
+       cli->cl_max_short_io_bytes = min_t(u64, val, OST_MAX_SHORT_IO_BYTES);
        spin_unlock(&cli->cl_loi_list_lock);
 
 out:
-       LPROCFS_CLIMP_EXIT(dev);
        return rc;
 }
 EXPORT_SYMBOL(short_io_bytes_store);
@@ -2389,7 +2485,7 @@ int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
        int rc;
        char *kernbuf = NULL;
        char *errmsg;
-       struct list_head tmp;
+       LIST_HEAD(tmp);
        int len = count;
        ENTRY;
 
@@ -2415,16 +2511,15 @@ int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
        if ((len == 4 && strncmp(kernbuf, "NONE", len) == 0) ||
            (len == 5 && strncmp(kernbuf, "clear", len) == 0)) {
                /* empty string is special case */
-               down_write(&squash->rsi_sem);
+               spin_lock(&squash->rsi_lock);
                if (!list_empty(&squash->rsi_nosquash_nids))
                        cfs_free_nidlist(&squash->rsi_nosquash_nids);
-               up_write(&squash->rsi_sem);
+               spin_unlock(&squash->rsi_lock);
                LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name);
                OBD_FREE(kernbuf, count + 1);
                RETURN(count);
        }
 
-       INIT_LIST_HEAD(&tmp);
        if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) {
                errmsg = "can't parse";
                GOTO(failed, rc = -EINVAL);
@@ -2434,11 +2529,11 @@ int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
        OBD_FREE(kernbuf, count + 1);
        kernbuf = NULL;
 
-       down_write(&squash->rsi_sem);
+       spin_lock(&squash->rsi_lock);
        if (!list_empty(&squash->rsi_nosquash_nids))
                cfs_free_nidlist(&squash->rsi_nosquash_nids);
        list_splice(&tmp, &squash->rsi_nosquash_nids);
-       up_write(&squash->rsi_sem);
+       spin_unlock(&squash->rsi_lock);
 
        RETURN(count);