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
lprocfs_counter_add(struct lprocfs_stats * stats,int idx,long amount)44 void 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 == NULL)
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 smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags);
60 if (smp_id < 0)
61 return;
62
63 header = &stats->ls_cnt_header[idx];
64 percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx);
65 percpu_cntr->lc_count++;
66
67 if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
68 /*
69 * lprocfs_counter_add() can be called in interrupt context,
70 * as memory allocation could trigger memory shrinker call
71 * ldlm_pool_shrink(), which calls lprocfs_counter_add().
72 * LU-1727.
73 *
74 */
75 if (in_interrupt() &&
76 (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
77 percpu_cntr->lc_sum_irq += amount;
78 else
79 percpu_cntr->lc_sum += amount;
80
81 if (header->lc_config & LPROCFS_CNTR_STDDEV)
82 percpu_cntr->lc_sumsquare += (__s64)amount * amount;
83 if (amount < percpu_cntr->lc_min)
84 percpu_cntr->lc_min = amount;
85 if (amount > percpu_cntr->lc_max)
86 percpu_cntr->lc_max = amount;
87 }
88 lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags);
89 }
90 EXPORT_SYMBOL(lprocfs_counter_add);
91
lprocfs_counter_sub(struct lprocfs_stats * stats,int idx,long amount)92 void lprocfs_counter_sub(struct lprocfs_stats *stats, int idx, long amount)
93 {
94 struct lprocfs_counter *percpu_cntr;
95 struct lprocfs_counter_header *header;
96 int smp_id;
97 unsigned long flags = 0;
98
99 if (stats == NULL)
100 return;
101
102 LASSERTF(0 <= idx && idx < stats->ls_num,
103 "idx %d, ls_num %hu\n", idx, stats->ls_num);
104
105 /* With per-client stats, statistics are allocated only for
106 * single CPU area, so the smp_id should be 0 always. */
107 smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags);
108 if (smp_id < 0)
109 return;
110
111 header = &stats->ls_cnt_header[idx];
112 percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx);
113 if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
114 /*
115 * Sometimes we use RCU callbacks to free memory which calls
116 * lprocfs_counter_sub(), and RCU callbacks may execute in
117 * softirq context - right now that's the only case we're in
118 * softirq context here, use separate counter for that.
119 * bz20650.
120 *
121 */
122 if (in_interrupt() &&
123 (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
124 percpu_cntr->lc_sum_irq -= amount;
125 else
126 percpu_cntr->lc_sum -= amount;
127 }
128 lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags);
129 }
130 EXPORT_SYMBOL(lprocfs_counter_sub);
131