Whamcloud - gitweb
LU-8836 lprocfs: move lprocfs_stats_[un]lock to a source file
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index c68bb31..53e46a6 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
@@ -300,20 +296,28 @@ EXPORT_SYMBOL(lprocfs_uint_seq_show);
 int lprocfs_wr_uint(struct file *file, const char __user *buffer,
                     unsigned long count, void *data)
 {
-        unsigned *p = data;
-        char dummy[MAX_STRING_SIZE + 1], *end;
-        unsigned long tmp;
+       unsigned        *p = data;
+       char             dummy[MAX_STRING_SIZE + 1];
+       char            *end;
+       unsigned long    tmp;
 
-        dummy[MAX_STRING_SIZE] = '\0';
-       if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
-                return -EFAULT;
+       if (count >= sizeof(dummy))
+               return -EINVAL;
 
-        tmp = simple_strtoul(dummy, &end, 0);
-        if (dummy == end)
-                return -EINVAL;
+       if (count == 0)
+               return 0;
+
+       if (copy_from_user(dummy, buffer, count))
+               return -EFAULT;
+
+       dummy[count] = 0;
+
+       tmp = simple_strtoul(dummy, &end, 0);
+       if (dummy == end)
+               return -EINVAL;
 
-        *p = (unsigned int)tmp;
-        return count;
+       *p = (unsigned int)tmp;
+       return count;
 }
 EXPORT_SYMBOL(lprocfs_wr_uint);
 
@@ -335,7 +339,7 @@ EXPORT_SYMBOL(lprocfs_uint_seq_write);
 int lprocfs_u64_seq_show(struct seq_file *m, void *data)
 {
        LASSERT(data != NULL);
-       seq_printf(m, LPU64"\n", *(__u64 *)data);
+       seq_printf(m, "%llu\n", *(__u64 *)data);
        return 0;
 }
 EXPORT_SYMBOL(lprocfs_u64_seq_show);
@@ -416,7 +420,7 @@ int lprocfs_kbytestotal_seq_show(struct seq_file *m, void *data)
                while (blk_size >>= 1)
                        result <<= 1;
 
-               seq_printf(m, LPU64"\n", result);
+               seq_printf(m, "%llu\n", result);
        }
        return rc;
 }
@@ -436,7 +440,7 @@ int lprocfs_kbytesfree_seq_show(struct seq_file *m, void *data)
                while (blk_size >>= 1)
                        result <<= 1;
 
-               seq_printf(m, LPU64"\n", result);
+               seq_printf(m, "%llu\n", result);
        }
        return rc;
 }
@@ -456,7 +460,7 @@ int lprocfs_kbytesavail_seq_show(struct seq_file *m, void *data)
                while (blk_size >>= 1)
                        result <<= 1;
 
-               seq_printf(m, LPU64"\n", result);
+               seq_printf(m, "%llu\n", result);
        }
        return rc;
 }
@@ -470,7 +474,7 @@ int lprocfs_filestotal_seq_show(struct seq_file *m, void *data)
                            cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                            OBD_STATFS_NODELAY);
        if (!rc)
-               seq_printf(m, LPU64"\n", osfs.os_files);
+               seq_printf(m, "%llu\n", osfs.os_files);
        return rc;
 }
 EXPORT_SYMBOL(lprocfs_filestotal_seq_show);
@@ -483,7 +487,7 @@ int lprocfs_filesfree_seq_show(struct seq_file *m, void *data)
                            cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
                            OBD_STATFS_NODELAY);
        if (!rc)
-               seq_printf(m, LPU64"\n", osfs.os_ffree);
+               seq_printf(m, "%llu\n", osfs.os_ffree);
        return rc;
 }
 EXPORT_SYMBOL(lprocfs_filesfree_seq_show);
@@ -528,6 +532,95 @@ int lprocfs_conn_uuid_seq_show(struct seq_file *m, void *data)
 EXPORT_SYMBOL(lprocfs_conn_uuid_seq_show);
 
 /** add up per-cpu counters */
+
+/**
+ * Lock statistics structure for access, possibly only on this CPU.
+ *
+ * The statistics struct may be allocated with per-CPU structures for
+ * efficient concurrent update (usually only on server-wide stats), or
+ * as a single global struct (e.g. for per-client or per-job statistics),
+ * so the required locking depends on the type of structure allocated.
+ *
+ * For per-CPU statistics, pin the thread to the current cpuid so that
+ * will only access the statistics for that CPU.  If the stats structure
+ * for the current CPU has not been allocated (or previously freed),
+ * allocate it now.  The per-CPU statistics do not need locking since
+ * the thread is pinned to the CPU during update.
+ *
+ * For global statistics, lock the stats structure to prevent concurrent update.
+ *
+ * \param[in] stats    statistics structure to lock
+ * \param[in] opc      type of operation:
+ *                     LPROCFS_GET_SMP_ID: "lock" and return current CPU index
+ *                             for incrementing statistics for that CPU
+ *                     LPROCFS_GET_NUM_CPU: "lock" and return number of used
+ *                             CPU indices to iterate over all indices
+ * \param[out] flags   CPU interrupt saved state for IRQ-safe locking
+ *
+ * \retval cpuid of current thread or number of allocated structs
+ * \retval negative on error (only for opc LPROCFS_GET_SMP_ID + per-CPU stats)
+ */
+int lprocfs_stats_lock(struct lprocfs_stats *stats,
+                      enum lprocfs_stats_lock_ops opc,
+                      unsigned long *flags)
+{
+       if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+               if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+                       spin_lock_irqsave(&stats->ls_lock, *flags);
+               else
+                       spin_lock(&stats->ls_lock);
+               return opc == LPROCFS_GET_NUM_CPU ? 1 : 0;
+       }
+
+       switch (opc) {
+       case LPROCFS_GET_SMP_ID: {
+               unsigned int cpuid = get_cpu();
+
+               if (unlikely(!stats->ls_percpu[cpuid])) {
+                       int rc = lprocfs_stats_alloc_one(stats, cpuid);
+
+                       if (rc < 0) {
+                               put_cpu();
+                               return rc;
+                       }
+               }
+               return cpuid;
+       }
+       case LPROCFS_GET_NUM_CPU:
+               return stats->ls_biggest_alloc_num;
+       default:
+               LBUG();
+       }
+}
+
+/**
+ * Unlock statistics structure after access.
+ *
+ * Unlock the lock acquired via lprocfs_stats_lock() for global statistics,
+ * or unpin this thread from the current cpuid for per-CPU statistics.
+ *
+ * This function must be called using the same arguments as used when calling
+ * lprocfs_stats_lock() so that the correct operation can be performed.
+ *
+ * \param[in] stats    statistics structure to unlock
+ * \param[in] opc      type of operation (current cpuid or number of structs)
+ * \param[in] flags    CPU interrupt saved state for IRQ-safe locking
+ */
+void lprocfs_stats_unlock(struct lprocfs_stats *stats,
+                         enum lprocfs_stats_lock_ops opc,
+                         unsigned long *flags)
+{
+       if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) {
+               if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
+                       spin_unlock_irqrestore(&stats->ls_lock, *flags);
+               else
+                       spin_unlock(&stats->ls_lock);
+       } else if (opc == LPROCFS_GET_SMP_ID) {
+               put_cpu();
+       }
+}
+
+/** add up per-cpu counters */
 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
                           struct lprocfs_counter *cnt)
 {
@@ -685,7 +778,7 @@ static void obd_connect_seq_flags2str(struct seq_file *m, __u64 flags,
        }
 
        if (flags & ~(mask - 1)) {
-               seq_printf(m, "%sunknown_"LPX64,
+               seq_printf(m, "%sunknown_%#llx",
                           first ? "" : sep, flags & ~(mask - 1));
                first = false;
        }
@@ -702,7 +795,7 @@ static void obd_connect_seq_flags2str(struct seq_file *m, __u64 flags,
        }
 
        if (flags2 & ~(mask - 1)) {
-               seq_printf(m, "%sunknown2_"LPX64,
+               seq_printf(m, "%sunknown2_%#llx",
                           first ? "" : sep, flags2 & ~(mask - 1));
                first = false;
        }
@@ -722,7 +815,7 @@ int obd_connect_flags2str(char *page, int count, __u64 flags, __u64 flags2,
 
        if (flags & ~(mask - 1))
                ret += snprintf(page + ret, count - ret,
-                               "%sunknown_"LPX64,
+                               "%sunknown_%#llx",
                                ret ? sep : "", flags & ~(mask - 1));
 
        if (!(flags & OBD_CONNECT_FLAGS2) || flags2 == 0)
@@ -736,7 +829,7 @@ int obd_connect_flags2str(char *page, int count, __u64 flags, __u64 flags2,
 
        if (flags2 & ~(mask - 1))
                ret += snprintf(page + ret, count - ret,
-                               "%sunknown2_"LPX64,
+                               "%sunknown2_%#llx",
                                ret ? sep : "", flags2 & ~(mask - 1));
 
        return ret;
@@ -752,7 +845,7 @@ static void obd_connect_data_seqprint(struct seq_file *m,
        flags = ocd->ocd_connect_flags;
 
        seq_printf(m, "    connect_data:\n"
-                  "       flags: "LPX64"\n"
+                  "       flags: %#llx\n"
                   "       instance: %u\n",
                   ocd->ocd_connect_flags,
                   ocd->ocd_instance);
@@ -771,7 +864,7 @@ static void obd_connect_data_seqprint(struct seq_file *m,
        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",
+               seq_printf(m, "       ibits_known: %#llx\n",
                           ocd->ocd_ibits_known);
        if (flags & OBD_CONNECT_GRANT_PARAM)
                seq_printf(m, "       grant_block_size: %d\n"
@@ -783,7 +876,7 @@ static void obd_connect_data_seqprint(struct seq_file *m,
                           ocd->ocd_grant_max_blks << ocd->ocd_grant_blkbits,
                           ocd->ocd_grant_tax_kb << 10);
        if (flags & OBD_CONNECT_TRANSNO)
-               seq_printf(m, "       first_transno: "LPX64"\n",
+               seq_printf(m, "       first_transno: %#llx\n",
                           ocd->ocd_transno);
        if (flags & OBD_CONNECT_CKSUM)
                seq_printf(m, "       cksum_types: %#x\n",
@@ -791,7 +884,7 @@ static void obd_connect_data_seqprint(struct seq_file *m,
        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",
+               seq_printf(m, "       max_object_bytes: %llu\n",
                           ocd->ocd_maxbytes);
        if (flags & OBD_CONNECT_MULTIMODRPCS)
                seq_printf(m, "       max_mod_rpcs: %hu\n",
@@ -875,7 +968,7 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                   "       inflight: %u\n"
                   "       unregistering: %u\n"
                   "       timeouts: %u\n"
-                  "       avg_waittime: "LPU64" %s\n",
+                  "       avg_waittime: %llu %s\n",
                   atomic_read(&imp->imp_inflight),
                   atomic_read(&imp->imp_unregistering),
                   atomic_read(&imp->imp_timeouts),
@@ -895,9 +988,9 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                   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",
+                  "       last_replay: %llu\n"
+                  "       peer_committed: %llu\n"
+                  "       last_checked: %llu\n",
                   imp->imp_last_replay_transno,
                   imp->imp_peer_committed_transno,
                   imp->imp_last_transno_checked);
@@ -913,7 +1006,7 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                        do_div(sum, ret.lc_count);
                        ret.lc_sum = sum;
                        seq_printf(m, "    %s_data_averages:\n"
-                                  "       bytes_per_rpc: "LPU64"\n",
+                                  "       bytes_per_rpc: %llu\n",
                                   rw ? "write" : "read",
                                   ret.lc_sum);
                }
@@ -926,7 +1019,7 @@ int lprocfs_import_seq_show(struct seq_file *m, void *data)
                        __u64 sum = ret.lc_sum;
                        do_div(sum, ret.lc_count);
                        ret.lc_sum = sum;
-                       seq_printf(m, "       %s_per_rpc: "LPU64"\n",
+                       seq_printf(m, "       %s_per_rpc: %llu\n",
                                   header->lc_units, ret.lc_sum);
                        j = (int)ret.lc_sum;
                        if (j > 0)
@@ -1036,8 +1129,8 @@ int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data)
        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="LPX64"\n", flags);
-       seq_printf(m, "flags2="LPX64"\n", 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);
@@ -1119,7 +1212,6 @@ int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid)
        }
        return rc;
 }
-EXPORT_SYMBOL(lprocfs_stats_alloc_one);
 
 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
                                           enum lprocfs_stats_flags flags)
@@ -1204,6 +1296,32 @@ void lprocfs_free_stats(struct lprocfs_stats **statsh)
 }
 EXPORT_SYMBOL(lprocfs_free_stats);
 
+u64 lprocfs_stats_collector(struct lprocfs_stats *stats, int idx,
+                           enum lprocfs_fields_flags field)
+{
+       unsigned long flags = 0;
+       unsigned int num_cpu;
+       unsigned int i;
+       u64 ret = 0;
+
+       LASSERT(stats);
+
+       num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
+       for (i = 0; i < num_cpu; i++) {
+               struct lprocfs_counter *cntr;
+
+               if (!stats->ls_percpu[i])
+                       continue;
+
+               cntr = lprocfs_stats_counter_get(stats, i, idx);
+               ret += lprocfs_read_helper(cntr, &stats->ls_cnt_header[idx],
+                                          stats->ls_flags, field);
+       }
+       lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
+       return ret;
+}
+EXPORT_SYMBOL(lprocfs_stats_collector);
+
 void lprocfs_clear_stats(struct lprocfs_stats *stats)
 {
        struct lprocfs_counter          *percpu_cntr;
@@ -1270,7 +1388,6 @@ static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
        struct lprocfs_counter_header   *hdr;
        struct lprocfs_counter           ctr;
        int                              idx    = *(loff_t *)v;
-       int                              rc     = 0;
 
        if (idx == 0) {
                struct timeval now;
@@ -1278,34 +1395,25 @@ static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
                do_gettimeofday(&now);
                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;
+               return 0;
 
-       seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
+       seq_printf(p, "%-25s %lld 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) {
-               seq_printf(p, " "LPD64" "LPD64" "LPD64,
+               seq_printf(p, " %lld %lld %lld",
                           ctr.lc_min, ctr.lc_max, ctr.lc_sum);
-               if (rc < 0)
-                       goto out;
                if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
-                       seq_printf(p, " "LPD64, ctr.lc_sumsquare);
-               if (rc < 0)
-                       goto out;
+                       seq_printf(p, " %llu", ctr.lc_sumsquare);
        }
        seq_putc(p, '\n');
-out:
-       return (rc < 0) ? rc : 0;
+       return 0;
 }
 
 static const struct seq_operations lprocfs_stats_seq_sops = {
@@ -1431,7 +1539,6 @@ void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
-        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);
 }
@@ -1935,12 +2042,14 @@ EXPORT_SYMBOL(lprocfs_str_to_s64);
 int lprocfs_str_with_units_to_s64(const char __user *buffer,
                                  unsigned long count, __s64 *val, char defunit)
 {
-       __u64 mult;
+       __u64 mult = 1;
        int rc;
 
-       rc = get_mult(defunit, &mult);
-       if (rc)
-               return rc;
+       if (defunit != '1') {
+               rc = get_mult(defunit, &mult);
+               if (rc)
+                       return rc;
+       }
 
        return str_to_s64_internal(buffer, count, val, mult, true);
 }