linux/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 *
  19 * http://www.gnu.org/licenses/gpl-2.0.html
  20 *
  21 * GPL HEADER END
  22 */
  23/*
  24 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  25 * Use is subject to license terms.
  26 *
  27 * Copyright (c) 2012, 2013, Intel Corporation.
  28 */
  29/*
  30 * This file is part of Lustre, http://www.lustre.org/
  31 * Lustre is a trademark of Sun Microsystems, Inc.
  32 *
  33 * lustre/obdclass/lprocfs_counters.c
  34 *
  35 * Lustre lprocfs counter routines
  36 *
  37 * Author: Andreas Dilger <andreas.dilger@intel.com>
  38 */
  39
  40#include <linux/module.h>
  41#include "../include/lprocfs_status.h"
  42#include "../include/obd_support.h"
  43
  44void lprocfs_counter_add(struct lprocfs_stats *stats, int idx, long amount)
  45{
  46        struct lprocfs_counter          *percpu_cntr;
  47        struct lprocfs_counter_header   *header;
  48        int                             smp_id;
  49        unsigned long                   flags = 0;
  50
  51        if (!stats)
  52                return;
  53
  54        LASSERTF(0 <= idx && idx < stats->ls_num,
  55                 "idx %d, ls_num %hu\n", idx, stats->ls_num);
  56
  57        /* With per-client stats, statistics are allocated only for
  58         * single CPU area, so the smp_id should be 0 always.
  59         */
  60        smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags);
  61        if (smp_id < 0)
  62                return;
  63
  64        header = &stats->ls_cnt_header[idx];
  65        percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx);
  66        percpu_cntr->lc_count++;
  67
  68        if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
  69                /*
  70                 * lprocfs_counter_add() can be called in interrupt context,
  71                 * as memory allocation could trigger memory shrinker call
  72                 * ldlm_pool_shrink(), which calls lprocfs_counter_add().
  73                 * LU-1727.
  74                 *
  75                 */
  76                if (in_interrupt() &&
  77                    (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
  78                        percpu_cntr->lc_sum_irq += amount;
  79                else
  80                        percpu_cntr->lc_sum += amount;
  81
  82                if (header->lc_config & LPROCFS_CNTR_STDDEV)
  83                        percpu_cntr->lc_sumsquare += (__s64)amount * amount;
  84                if (amount < percpu_cntr->lc_min)
  85                        percpu_cntr->lc_min = amount;
  86                if (amount > percpu_cntr->lc_max)
  87                        percpu_cntr->lc_max = amount;
  88        }
  89        lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags);
  90}
  91EXPORT_SYMBOL(lprocfs_counter_add);
  92
  93void lprocfs_counter_sub(struct lprocfs_stats *stats, int idx, long amount)
  94{
  95        struct lprocfs_counter          *percpu_cntr;
  96        struct lprocfs_counter_header   *header;
  97        int                             smp_id;
  98        unsigned long                   flags = 0;
  99
 100        if (!stats)
 101                return;
 102
 103        LASSERTF(0 <= idx && idx < stats->ls_num,
 104                 "idx %d, ls_num %hu\n", idx, stats->ls_num);
 105
 106        /* With per-client stats, statistics are allocated only for
 107         * single CPU area, so the smp_id should be 0 always.
 108         */
 109        smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags);
 110        if (smp_id < 0)
 111                return;
 112
 113        header = &stats->ls_cnt_header[idx];
 114        percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx);
 115        if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
 116                /*
 117                 * Sometimes we use RCU callbacks to free memory which calls
 118                 * lprocfs_counter_sub(), and RCU callbacks may execute in
 119                 * softirq context - right now that's the only case we're in
 120                 * softirq context here, use separate counter for that.
 121                 * bz20650.
 122                 *
 123                 */
 124                if (in_interrupt() &&
 125                    (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
 126                        percpu_cntr->lc_sum_irq -= amount;
 127                else
 128                        percpu_cntr->lc_sum -= amount;
 129        }
 130        lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags);
 131}
 132EXPORT_SYMBOL(lprocfs_counter_sub);
 133