4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/lprocfs_status.c
38 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
41 #define DEBUG_SUBSYSTEM S_CLASS
43 #include "../include/obd_class.h"
44 #include "../include/lprocfs_status.h"
45 #include "../include/lustre/lustre_idl.h"
46 #include <linux/seq_file.h>
47 #include <linux/ctype.h>
49 static const char * const obd_connect_names
[] = {
63 "join_file(obsolete)",
67 "remote_client_by_force",
79 "alt_checksum_algorithm",
107 int obd_connect_flags2str(char *page
, int count
, __u64 flags
, char *sep
)
112 for (i
= 0; obd_connect_names
[i
] != NULL
; i
++, mask
<<= 1) {
114 ret
+= snprintf(page
+ ret
, count
- ret
, "%s%s",
115 ret
? sep
: "", obd_connect_names
[i
]);
117 if (flags
& ~(mask
- 1))
118 ret
+= snprintf(page
+ ret
, count
- ret
,
119 "%sunknown flags %#llx",
120 ret
? sep
: "", flags
& ~(mask
- 1));
123 EXPORT_SYMBOL(obd_connect_flags2str
);
125 int lprocfs_read_frac_helper(char *buffer
, unsigned long count
, long val
,
128 long decimal_val
, frac_val
;
134 decimal_val
= val
/ mult
;
135 prtn
= snprintf(buffer
, count
, "%ld", decimal_val
);
136 frac_val
= val
% mult
;
138 if (prtn
< (count
- 4) && frac_val
> 0) {
140 int i
, temp_mult
= 1, frac_bits
= 0;
142 temp_frac
= frac_val
* 10;
143 buffer
[prtn
++] = '.';
144 while (frac_bits
< 2 && (temp_frac
/ mult
) < 1) {
145 /* only reserved 2 bits fraction */
146 buffer
[prtn
++] = '0';
151 * Need to think these cases :
152 * 1. #echo x.00 > /proc/xxx output result : x
153 * 2. #echo x.0x > /proc/xxx output result : x.0x
154 * 3. #echo x.x0 > /proc/xxx output result : x.x
155 * 4. #echo x.xx > /proc/xxx output result : x.xx
156 * Only reserved 2 bits fraction.
158 for (i
= 0; i
< (5 - prtn
); i
++)
161 frac_bits
= min((int)count
- prtn
, 3 - frac_bits
);
162 prtn
+= snprintf(buffer
+ prtn
, frac_bits
, "%ld",
163 frac_val
* temp_mult
/ mult
);
166 while (buffer
[prtn
] < '1' || buffer
[prtn
] > '9') {
168 if (buffer
[prtn
] == '.') {
175 buffer
[prtn
++] = '\n';
178 EXPORT_SYMBOL(lprocfs_read_frac_helper
);
180 int lprocfs_write_frac_helper(const char __user
*buffer
, unsigned long count
,
183 char kernbuf
[20], *end
, *pbuf
;
185 if (count
> (sizeof(kernbuf
) - 1))
188 if (copy_from_user(kernbuf
, buffer
, count
))
191 kernbuf
[count
] = '\0';
198 *val
= (int)simple_strtoul(pbuf
, &end
, 10) * mult
;
202 if (end
!= NULL
&& *end
== '.') {
203 int temp_val
, pow
= 1;
207 if (strlen(pbuf
) > 5)
208 pbuf
[5] = '\0'; /*only allow 5bits fractional*/
210 temp_val
= (int)simple_strtoul(pbuf
, &end
, 10) * mult
;
213 for (i
= 0; i
< (end
- pbuf
); i
++)
216 *val
+= temp_val
/ pow
;
221 EXPORT_SYMBOL(lprocfs_write_frac_helper
);
223 static int lprocfs_no_percpu_stats
;
224 module_param(lprocfs_no_percpu_stats
, int, 0644);
225 MODULE_PARM_DESC(lprocfs_no_percpu_stats
, "Do not alloc percpu data for lprocfs stats");
227 #define MAX_STRING_SIZE 128
229 int lprocfs_single_release(struct inode
*inode
, struct file
*file
)
231 return single_release(inode
, file
);
233 EXPORT_SYMBOL(lprocfs_single_release
);
235 int lprocfs_seq_release(struct inode
*inode
, struct file
*file
)
237 return seq_release(inode
, file
);
239 EXPORT_SYMBOL(lprocfs_seq_release
);
241 /* lprocfs API calls */
243 struct dentry
*ldebugfs_add_simple(struct dentry
*root
,
244 char *name
, void *data
,
245 struct file_operations
*fops
)
247 struct dentry
*entry
;
250 if (root
== NULL
|| name
== NULL
|| fops
== NULL
)
251 return ERR_PTR(-EINVAL
);
257 entry
= debugfs_create_file(name
, mode
, root
, data
, fops
);
258 if (IS_ERR_OR_NULL(entry
)) {
259 CERROR("LprocFS: No memory to create <debugfs> entry %s", name
);
260 return entry
?: ERR_PTR(-ENOMEM
);
264 EXPORT_SYMBOL(ldebugfs_add_simple
);
266 static struct file_operations lprocfs_generic_fops
= { };
268 int ldebugfs_add_vars(struct dentry
*parent
,
269 struct lprocfs_vars
*list
,
272 if (IS_ERR_OR_NULL(parent
) || IS_ERR_OR_NULL(list
))
275 while (list
->name
!= NULL
) {
276 struct dentry
*entry
;
279 if (list
->proc_mode
!= 0000) {
280 mode
= list
->proc_mode
;
281 } else if (list
->fops
) {
282 if (list
->fops
->read
)
284 if (list
->fops
->write
)
287 entry
= debugfs_create_file(list
->name
, mode
, parent
,
289 list
->fops
?: &lprocfs_generic_fops
291 if (IS_ERR_OR_NULL(entry
))
292 return entry
? PTR_ERR(entry
) : -ENOMEM
;
297 EXPORT_SYMBOL(ldebugfs_add_vars
);
299 void ldebugfs_remove(struct dentry
**entryp
)
301 debugfs_remove_recursive(*entryp
);
304 EXPORT_SYMBOL(ldebugfs_remove
);
306 struct dentry
*ldebugfs_register(const char *name
,
307 struct dentry
*parent
,
308 struct lprocfs_vars
*list
, void *data
)
310 struct dentry
*entry
;
312 entry
= debugfs_create_dir(name
, parent
);
313 if (IS_ERR_OR_NULL(entry
)) {
314 entry
= entry
?: ERR_PTR(-ENOMEM
);
318 if (!IS_ERR_OR_NULL(list
)) {
321 rc
= ldebugfs_add_vars(entry
, list
, data
);
323 debugfs_remove(entry
);
330 EXPORT_SYMBOL(ldebugfs_register
);
332 /* Generic callbacks */
333 int lprocfs_rd_uint(struct seq_file
*m
, void *data
)
335 seq_printf(m
, "%u\n", *(unsigned int *)data
);
338 EXPORT_SYMBOL(lprocfs_rd_uint
);
340 int lprocfs_wr_uint(struct file
*file
, const char __user
*buffer
,
341 unsigned long count
, void *data
)
344 char dummy
[MAX_STRING_SIZE
+ 1], *end
;
347 dummy
[MAX_STRING_SIZE
] = '\0';
348 if (copy_from_user(dummy
, buffer
, MAX_STRING_SIZE
))
351 tmp
= simple_strtoul(dummy
, &end
, 0);
355 *p
= (unsigned int)tmp
;
358 EXPORT_SYMBOL(lprocfs_wr_uint
);
360 static ssize_t
uuid_show(struct kobject
*kobj
, struct attribute
*attr
,
363 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
366 return sprintf(buf
, "%s\n", obd
->obd_uuid
.uuid
);
368 LUSTRE_RO_ATTR(uuid
);
370 static ssize_t
blocksize_show(struct kobject
*kobj
, struct attribute
*attr
,
373 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
375 struct obd_statfs osfs
;
376 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
377 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
380 return sprintf(buf
, "%u\n", osfs
.os_bsize
);
384 LUSTRE_RO_ATTR(blocksize
);
386 static ssize_t
kbytestotal_show(struct kobject
*kobj
, struct attribute
*attr
,
389 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
391 struct obd_statfs osfs
;
392 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
393 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
396 __u32 blk_size
= osfs
.os_bsize
>> 10;
397 __u64 result
= osfs
.os_blocks
;
399 while (blk_size
>>= 1)
402 return sprintf(buf
, "%llu\n", result
);
407 LUSTRE_RO_ATTR(kbytestotal
);
409 static ssize_t
kbytesfree_show(struct kobject
*kobj
, struct attribute
*attr
,
412 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
414 struct obd_statfs osfs
;
415 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
416 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
419 __u32 blk_size
= osfs
.os_bsize
>> 10;
420 __u64 result
= osfs
.os_bfree
;
422 while (blk_size
>>= 1)
425 return sprintf(buf
, "%llu\n", result
);
430 LUSTRE_RO_ATTR(kbytesfree
);
432 static ssize_t
kbytesavail_show(struct kobject
*kobj
, struct attribute
*attr
,
435 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
437 struct obd_statfs osfs
;
438 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
439 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
442 __u32 blk_size
= osfs
.os_bsize
>> 10;
443 __u64 result
= osfs
.os_bavail
;
445 while (blk_size
>>= 1)
448 return sprintf(buf
, "%llu\n", result
);
453 LUSTRE_RO_ATTR(kbytesavail
);
455 static ssize_t
filestotal_show(struct kobject
*kobj
, struct attribute
*attr
,
458 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
460 struct obd_statfs osfs
;
461 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
462 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
465 return sprintf(buf
, "%llu\n", osfs
.os_files
);
469 LUSTRE_RO_ATTR(filestotal
);
471 static ssize_t
filesfree_show(struct kobject
*kobj
, struct attribute
*attr
,
474 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
476 struct obd_statfs osfs
;
477 int rc
= obd_statfs(NULL
, obd
->obd_self_export
, &osfs
,
478 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
481 return sprintf(buf
, "%llu\n", osfs
.os_ffree
);
485 LUSTRE_RO_ATTR(filesfree
);
487 int lprocfs_rd_server_uuid(struct seq_file
*m
, void *data
)
489 struct obd_device
*obd
= data
;
490 struct obd_import
*imp
;
491 char *imp_state_name
= NULL
;
494 LASSERT(obd
!= NULL
);
495 rc
= lprocfs_climp_check(obd
);
499 imp
= obd
->u
.cli
.cl_import
;
500 imp_state_name
= ptlrpc_import_state_name(imp
->imp_state
);
501 seq_printf(m
, "%s\t%s%s\n",
502 obd2cli_tgt(obd
), imp_state_name
,
503 imp
->imp_deactive
? "\tDEACTIVATED" : "");
505 LPROCFS_CLIMP_EXIT(obd
);
509 EXPORT_SYMBOL(lprocfs_rd_server_uuid
);
511 int lprocfs_rd_conn_uuid(struct seq_file
*m
, void *data
)
513 struct obd_device
*obd
= data
;
514 struct ptlrpc_connection
*conn
;
517 LASSERT(obd
!= NULL
);
519 rc
= lprocfs_climp_check(obd
);
523 conn
= obd
->u
.cli
.cl_import
->imp_connection
;
524 if (conn
&& obd
->u
.cli
.cl_import
)
525 seq_printf(m
, "%s\n", conn
->c_remote_uuid
.uuid
);
527 seq_puts(m
, "<none>\n");
529 LPROCFS_CLIMP_EXIT(obd
);
533 EXPORT_SYMBOL(lprocfs_rd_conn_uuid
);
535 /** add up per-cpu counters */
536 void lprocfs_stats_collect(struct lprocfs_stats
*stats
, int idx
,
537 struct lprocfs_counter
*cnt
)
539 unsigned int num_entry
;
540 struct lprocfs_counter
*percpu_cntr
;
542 unsigned long flags
= 0;
544 memset(cnt
, 0, sizeof(*cnt
));
547 /* set count to 1 to avoid divide-by-zero errs in callers */
552 cnt
->lc_min
= LC_MIN_INIT
;
554 num_entry
= lprocfs_stats_lock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
556 for (i
= 0; i
< num_entry
; i
++) {
557 if (stats
->ls_percpu
[i
] == NULL
)
559 percpu_cntr
= lprocfs_stats_counter_get(stats
, i
, idx
);
561 cnt
->lc_count
+= percpu_cntr
->lc_count
;
562 cnt
->lc_sum
+= percpu_cntr
->lc_sum
;
563 if (percpu_cntr
->lc_min
< cnt
->lc_min
)
564 cnt
->lc_min
= percpu_cntr
->lc_min
;
565 if (percpu_cntr
->lc_max
> cnt
->lc_max
)
566 cnt
->lc_max
= percpu_cntr
->lc_max
;
567 cnt
->lc_sumsquare
+= percpu_cntr
->lc_sumsquare
;
570 lprocfs_stats_unlock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
572 EXPORT_SYMBOL(lprocfs_stats_collect
);
575 * Append a space separated list of current set flags to str.
577 #define flag2str(flag, first) \
579 if (imp->imp_##flag) \
580 seq_printf(m, "%s" #flag, first ? "" : ", "); \
582 static int obd_import_flags2str(struct obd_import
*imp
, struct seq_file
*m
)
586 if (imp
->imp_obd
->obd_no_recov
) {
587 seq_printf(m
, "no_recov");
591 flag2str(invalid
, first
);
593 flag2str(deactive
, first
);
594 flag2str(replayable
, first
);
595 flag2str(pingable
, first
);
601 static void obd_connect_seq_flags2str(struct seq_file
*m
, __u64 flags
, char *sep
)
607 for (i
= 0; obd_connect_names
[i
] != NULL
; i
++, mask
<<= 1) {
609 seq_printf(m
, "%s%s",
610 first
? sep
: "", obd_connect_names
[i
]);
614 if (flags
& ~(mask
- 1))
615 seq_printf(m
, "%sunknown flags %#llx",
616 first
? sep
: "", flags
& ~(mask
- 1));
619 int lprocfs_rd_import(struct seq_file
*m
, void *data
)
621 char nidstr
[LNET_NIDSTR_SIZE
];
622 struct lprocfs_counter ret
;
623 struct lprocfs_counter_header
*header
;
624 struct obd_device
*obd
= data
;
625 struct obd_import
*imp
;
626 struct obd_import_conn
*conn
;
632 LASSERT(obd
!= NULL
);
633 rc
= lprocfs_climp_check(obd
);
637 imp
= obd
->u
.cli
.cl_import
;
648 ptlrpc_import_state_name(imp
->imp_state
),
649 imp
->imp_connect_data
.ocd_instance
);
650 obd_connect_seq_flags2str(m
, imp
->imp_connect_data
.ocd_connect_flags
, ", ");
654 obd_import_flags2str(imp
, m
);
659 " failover_nids: [");
660 spin_lock(&imp
->imp_lock
);
662 list_for_each_entry(conn
, &imp
->imp_conn_list
, oic_item
) {
663 libcfs_nid2str_r(conn
->oic_conn
->c_peer
.nid
,
664 nidstr
, sizeof(nidstr
));
665 seq_printf(m
, "%s%s", j
? ", " : "", nidstr
);
668 libcfs_nid2str_r(imp
->imp_connection
->c_peer
.nid
,
669 nidstr
, sizeof(nidstr
));
672 " current_connection: %s\n"
673 " connection_attempts: %u\n"
675 " in-progress_invalidations: %u\n",
676 imp
->imp_connection
== NULL
? "<none>" : nidstr
,
679 atomic_read(&imp
->imp_inval_count
));
680 spin_unlock(&imp
->imp_lock
);
682 if (obd
->obd_svc_stats
== NULL
)
685 header
= &obd
->obd_svc_stats
->ls_cnt_header
[PTLRPC_REQWAIT_CNTR
];
686 lprocfs_stats_collect(obd
->obd_svc_stats
, PTLRPC_REQWAIT_CNTR
, &ret
);
687 if (ret
.lc_count
!= 0) {
688 /* first argument to do_div MUST be __u64 */
689 __u64 sum
= ret
.lc_sum
;
691 do_div(sum
, ret
.lc_count
);
698 " unregistering: %u\n"
700 " avg_waittime: %llu %s\n",
701 atomic_read(&imp
->imp_inflight
),
702 atomic_read(&imp
->imp_unregistering
),
703 atomic_read(&imp
->imp_timeouts
),
704 ret
.lc_sum
, header
->lc_units
);
707 for (j
= 0; j
< IMP_AT_MAX_PORTALS
; j
++) {
708 if (imp
->imp_at
.iat_portal
[j
] == 0)
710 k
= max_t(unsigned int, k
,
711 at_get(&imp
->imp_at
.iat_service_estimate
[j
]));
714 " service_estimates:\n"
715 " services: %u sec\n"
716 " network: %u sec\n",
718 at_get(&imp
->imp_at
.iat_net_latency
));
722 " last_replay: %llu\n"
723 " peer_committed: %llu\n"
724 " last_checked: %llu\n",
725 imp
->imp_last_replay_transno
,
726 imp
->imp_peer_committed_transno
,
727 imp
->imp_last_transno_checked
);
730 for (rw
= 0; rw
<= 1; rw
++) {
731 lprocfs_stats_collect(obd
->obd_svc_stats
,
732 PTLRPC_LAST_CNTR
+ BRW_READ_BYTES
+ rw
,
734 if (ret
.lc_sum
> 0 && ret
.lc_count
> 0) {
735 /* first argument to do_div MUST be __u64 */
736 __u64 sum
= ret
.lc_sum
;
738 do_div(sum
, ret
.lc_count
);
741 " %s_data_averages:\n"
742 " bytes_per_rpc: %llu\n",
743 rw
? "write" : "read",
747 j
= opcode_offset(OST_READ
+ rw
) + EXTRA_MAX_OPCODES
;
748 header
= &obd
->obd_svc_stats
->ls_cnt_header
[j
];
749 lprocfs_stats_collect(obd
->obd_svc_stats
, j
, &ret
);
750 if (ret
.lc_sum
> 0 && ret
.lc_count
!= 0) {
751 /* first argument to do_div MUST be __u64 */
752 __u64 sum
= ret
.lc_sum
;
754 do_div(sum
, ret
.lc_count
);
757 " %s_per_rpc: %llu\n",
758 header
->lc_units
, ret
.lc_sum
);
762 " MB_per_sec: %u.%.02u\n",
763 k
/ j
, (100 * k
/ j
) % 100);
768 LPROCFS_CLIMP_EXIT(obd
);
771 EXPORT_SYMBOL(lprocfs_rd_import
);
773 int lprocfs_rd_state(struct seq_file
*m
, void *data
)
775 struct obd_device
*obd
= data
;
776 struct obd_import
*imp
;
779 LASSERT(obd
!= NULL
);
780 rc
= lprocfs_climp_check(obd
);
784 imp
= obd
->u
.cli
.cl_import
;
786 seq_printf(m
, "current_state: %s\n",
787 ptlrpc_import_state_name(imp
->imp_state
));
788 seq_printf(m
, "state_history:\n");
789 k
= imp
->imp_state_hist_idx
;
790 for (j
= 0; j
< IMP_STATE_HIST_LEN
; j
++) {
791 struct import_state_hist
*ish
=
792 &imp
->imp_state_hist
[(k
+ j
) % IMP_STATE_HIST_LEN
];
793 if (ish
->ish_state
== 0)
795 seq_printf(m
, " - [%lld, %s]\n", (s64
)ish
->ish_time
,
796 ptlrpc_import_state_name(ish
->ish_state
));
799 LPROCFS_CLIMP_EXIT(obd
);
802 EXPORT_SYMBOL(lprocfs_rd_state
);
804 int lprocfs_at_hist_helper(struct seq_file
*m
, struct adaptive_timeout
*at
)
808 for (i
= 0; i
< AT_BINS
; i
++)
809 seq_printf(m
, "%3u ", at
->at_hist
[i
]);
813 EXPORT_SYMBOL(lprocfs_at_hist_helper
);
815 /* See also ptlrpc_lprocfs_rd_timeouts */
816 int lprocfs_rd_timeouts(struct seq_file
*m
, void *data
)
818 struct obd_device
*obd
= data
;
819 struct obd_import
*imp
;
820 unsigned int cur
, worst
;
821 time64_t now
, worstt
;
825 LASSERT(obd
!= NULL
);
826 rc
= lprocfs_climp_check(obd
);
830 imp
= obd
->u
.cli
.cl_import
;
832 now
= ktime_get_real_seconds();
834 /* Some network health info for kicks */
835 s2dhms(&ts
, now
- imp
->imp_last_reply_time
);
836 seq_printf(m
, "%-10s : %lld, " DHMS_FMT
" ago\n",
837 "last reply", (s64
)imp
->imp_last_reply_time
, DHMS_VARS(&ts
));
839 cur
= at_get(&imp
->imp_at
.iat_net_latency
);
840 worst
= imp
->imp_at
.iat_net_latency
.at_worst_ever
;
841 worstt
= imp
->imp_at
.iat_net_latency
.at_worst_time
;
842 s2dhms(&ts
, now
- worstt
);
843 seq_printf(m
, "%-10s : cur %3u worst %3u (at %lld, " DHMS_FMT
" ago) ",
844 "network", cur
, worst
, (s64
)worstt
, DHMS_VARS(&ts
));
845 lprocfs_at_hist_helper(m
, &imp
->imp_at
.iat_net_latency
);
847 for (i
= 0; i
< IMP_AT_MAX_PORTALS
; i
++) {
848 if (imp
->imp_at
.iat_portal
[i
] == 0)
850 cur
= at_get(&imp
->imp_at
.iat_service_estimate
[i
]);
851 worst
= imp
->imp_at
.iat_service_estimate
[i
].at_worst_ever
;
852 worstt
= imp
->imp_at
.iat_service_estimate
[i
].at_worst_time
;
853 s2dhms(&ts
, now
- worstt
);
854 seq_printf(m
, "portal %-2d : cur %3u worst %3u (at %lld, "
855 DHMS_FMT
" ago) ", imp
->imp_at
.iat_portal
[i
],
856 cur
, worst
, (s64
)worstt
, DHMS_VARS(&ts
));
857 lprocfs_at_hist_helper(m
, &imp
->imp_at
.iat_service_estimate
[i
]);
860 LPROCFS_CLIMP_EXIT(obd
);
863 EXPORT_SYMBOL(lprocfs_rd_timeouts
);
865 int lprocfs_rd_connect_flags(struct seq_file
*m
, void *data
)
867 struct obd_device
*obd
= data
;
871 rc
= lprocfs_climp_check(obd
);
875 flags
= obd
->u
.cli
.cl_import
->imp_connect_data
.ocd_connect_flags
;
876 seq_printf(m
, "flags=%#llx\n", flags
);
877 obd_connect_seq_flags2str(m
, flags
, "\n");
879 LPROCFS_CLIMP_EXIT(obd
);
882 EXPORT_SYMBOL(lprocfs_rd_connect_flags
);
884 static struct attribute
*obd_def_attrs
[] = {
885 &lustre_attr_blocksize
.attr
,
886 &lustre_attr_kbytestotal
.attr
,
887 &lustre_attr_kbytesfree
.attr
,
888 &lustre_attr_kbytesavail
.attr
,
889 &lustre_attr_filestotal
.attr
,
890 &lustre_attr_filesfree
.attr
,
891 &lustre_attr_uuid
.attr
,
895 static void obd_sysfs_release(struct kobject
*kobj
)
897 struct obd_device
*obd
= container_of(kobj
, struct obd_device
,
900 complete(&obd
->obd_kobj_unregister
);
903 static struct kobj_type obd_ktype
= {
904 .default_attrs
= obd_def_attrs
,
905 .sysfs_ops
= &lustre_sysfs_ops
,
906 .release
= obd_sysfs_release
,
909 int lprocfs_obd_setup(struct obd_device
*obd
, struct lprocfs_vars
*list
,
910 struct attribute_group
*attrs
)
914 init_completion(&obd
->obd_kobj_unregister
);
915 rc
= kobject_init_and_add(&obd
->obd_kobj
, &obd_ktype
,
916 obd
->obd_type
->typ_kobj
,
917 "%s", obd
->obd_name
);
922 rc
= sysfs_create_group(&obd
->obd_kobj
, attrs
);
924 kobject_put(&obd
->obd_kobj
);
929 obd
->obd_debugfs_entry
= ldebugfs_register(obd
->obd_name
,
930 obd
->obd_type
->typ_debugfs_entry
,
932 if (IS_ERR_OR_NULL(obd
->obd_debugfs_entry
)) {
933 rc
= obd
->obd_debugfs_entry
? PTR_ERR(obd
->obd_debugfs_entry
)
935 CERROR("error %d setting up lprocfs for %s\n",
937 obd
->obd_debugfs_entry
= NULL
;
942 EXPORT_SYMBOL(lprocfs_obd_setup
);
944 int lprocfs_obd_cleanup(struct obd_device
*obd
)
949 if (!IS_ERR_OR_NULL(obd
->obd_debugfs_entry
))
950 ldebugfs_remove(&obd
->obd_debugfs_entry
);
952 kobject_put(&obd
->obd_kobj
);
953 wait_for_completion(&obd
->obd_kobj_unregister
);
957 EXPORT_SYMBOL(lprocfs_obd_cleanup
);
959 int lprocfs_stats_alloc_one(struct lprocfs_stats
*stats
, unsigned int cpuid
)
961 struct lprocfs_counter
*cntr
;
962 unsigned int percpusize
;
964 unsigned long flags
= 0;
967 LASSERT(stats
->ls_percpu
[cpuid
] == NULL
);
968 LASSERT((stats
->ls_flags
& LPROCFS_STATS_FLAG_NOPERCPU
) == 0);
970 percpusize
= lprocfs_stats_counter_size(stats
);
971 LIBCFS_ALLOC_ATOMIC(stats
->ls_percpu
[cpuid
], percpusize
);
972 if (stats
->ls_percpu
[cpuid
] != NULL
) {
974 if (unlikely(stats
->ls_biggest_alloc_num
<= cpuid
)) {
975 if (stats
->ls_flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
)
976 spin_lock_irqsave(&stats
->ls_lock
, flags
);
978 spin_lock(&stats
->ls_lock
);
979 if (stats
->ls_biggest_alloc_num
<= cpuid
)
980 stats
->ls_biggest_alloc_num
= cpuid
+ 1;
981 if (stats
->ls_flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
)
982 spin_unlock_irqrestore(&stats
->ls_lock
, flags
);
984 spin_unlock(&stats
->ls_lock
);
986 /* initialize the ls_percpu[cpuid] non-zero counter */
987 for (i
= 0; i
< stats
->ls_num
; ++i
) {
988 cntr
= lprocfs_stats_counter_get(stats
, cpuid
, i
);
989 cntr
->lc_min
= LC_MIN_INIT
;
994 EXPORT_SYMBOL(lprocfs_stats_alloc_one
);
996 struct lprocfs_stats
*lprocfs_alloc_stats(unsigned int num
,
997 enum lprocfs_stats_flags flags
)
999 struct lprocfs_stats
*stats
;
1000 unsigned int num_entry
;
1001 unsigned int percpusize
= 0;
1007 if (lprocfs_no_percpu_stats
!= 0)
1008 flags
|= LPROCFS_STATS_FLAG_NOPERCPU
;
1010 if (flags
& LPROCFS_STATS_FLAG_NOPERCPU
)
1013 num_entry
= num_possible_cpus();
1015 /* alloc percpu pointers for all possible cpu slots */
1016 LIBCFS_ALLOC(stats
, offsetof(typeof(*stats
), ls_percpu
[num_entry
]));
1020 stats
->ls_num
= num
;
1021 stats
->ls_flags
= flags
;
1022 spin_lock_init(&stats
->ls_lock
);
1024 /* alloc num of counter headers */
1025 LIBCFS_ALLOC(stats
->ls_cnt_header
,
1026 stats
->ls_num
* sizeof(struct lprocfs_counter_header
));
1027 if (stats
->ls_cnt_header
== NULL
)
1030 if ((flags
& LPROCFS_STATS_FLAG_NOPERCPU
) != 0) {
1031 /* contains only one set counters */
1032 percpusize
= lprocfs_stats_counter_size(stats
);
1033 LIBCFS_ALLOC_ATOMIC(stats
->ls_percpu
[0], percpusize
);
1034 if (stats
->ls_percpu
[0] == NULL
)
1036 stats
->ls_biggest_alloc_num
= 1;
1037 } else if ((flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
) != 0) {
1038 /* alloc all percpu data */
1039 for (i
= 0; i
< num_entry
; ++i
)
1040 if (lprocfs_stats_alloc_one(stats
, i
) < 0)
1047 lprocfs_free_stats(&stats
);
1050 EXPORT_SYMBOL(lprocfs_alloc_stats
);
1052 void lprocfs_free_stats(struct lprocfs_stats
**statsh
)
1054 struct lprocfs_stats
*stats
= *statsh
;
1055 unsigned int num_entry
;
1056 unsigned int percpusize
;
1059 if (stats
== NULL
|| stats
->ls_num
== 0)
1063 if (stats
->ls_flags
& LPROCFS_STATS_FLAG_NOPERCPU
)
1066 num_entry
= num_possible_cpus();
1068 percpusize
= lprocfs_stats_counter_size(stats
);
1069 for (i
= 0; i
< num_entry
; i
++)
1070 if (stats
->ls_percpu
[i
] != NULL
)
1071 LIBCFS_FREE(stats
->ls_percpu
[i
], percpusize
);
1072 if (stats
->ls_cnt_header
!= NULL
)
1073 LIBCFS_FREE(stats
->ls_cnt_header
, stats
->ls_num
*
1074 sizeof(struct lprocfs_counter_header
));
1075 LIBCFS_FREE(stats
, offsetof(typeof(*stats
), ls_percpu
[num_entry
]));
1077 EXPORT_SYMBOL(lprocfs_free_stats
);
1079 void lprocfs_clear_stats(struct lprocfs_stats
*stats
)
1081 struct lprocfs_counter
*percpu_cntr
;
1084 unsigned int num_entry
;
1085 unsigned long flags
= 0;
1087 num_entry
= lprocfs_stats_lock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
1089 for (i
= 0; i
< num_entry
; i
++) {
1090 if (stats
->ls_percpu
[i
] == NULL
)
1092 for (j
= 0; j
< stats
->ls_num
; j
++) {
1093 percpu_cntr
= lprocfs_stats_counter_get(stats
, i
, j
);
1094 percpu_cntr
->lc_count
= 0;
1095 percpu_cntr
->lc_min
= LC_MIN_INIT
;
1096 percpu_cntr
->lc_max
= 0;
1097 percpu_cntr
->lc_sumsquare
= 0;
1098 percpu_cntr
->lc_sum
= 0;
1099 if (stats
->ls_flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
)
1100 percpu_cntr
->lc_sum_irq
= 0;
1104 lprocfs_stats_unlock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
1106 EXPORT_SYMBOL(lprocfs_clear_stats
);
1108 static ssize_t
lprocfs_stats_seq_write(struct file
*file
,
1109 const char __user
*buf
,
1110 size_t len
, loff_t
*off
)
1112 struct seq_file
*seq
= file
->private_data
;
1113 struct lprocfs_stats
*stats
= seq
->private;
1115 lprocfs_clear_stats(stats
);
1120 static void *lprocfs_stats_seq_start(struct seq_file
*p
, loff_t
*pos
)
1122 struct lprocfs_stats
*stats
= p
->private;
1124 return (*pos
< stats
->ls_num
) ? pos
: NULL
;
1127 static void lprocfs_stats_seq_stop(struct seq_file
*p
, void *v
)
1131 static void *lprocfs_stats_seq_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
1134 return lprocfs_stats_seq_start(p
, pos
);
1137 /* seq file export of one lprocfs counter */
1138 static int lprocfs_stats_seq_show(struct seq_file
*p
, void *v
)
1140 struct lprocfs_stats
*stats
= p
->private;
1141 struct lprocfs_counter_header
*hdr
;
1142 struct lprocfs_counter ctr
;
1143 int idx
= *(loff_t
*)v
;
1146 struct timespec64 now
;
1148 ktime_get_real_ts64(&now
);
1149 seq_printf(p
, "%-25s %llu.%9lu secs.usecs\n",
1151 (s64
)now
.tv_sec
, (unsigned long)now
.tv_nsec
);
1154 hdr
= &stats
->ls_cnt_header
[idx
];
1155 lprocfs_stats_collect(stats
, idx
, &ctr
);
1157 if (ctr
.lc_count
!= 0) {
1158 seq_printf(p
, "%-25s %lld samples [%s]",
1159 hdr
->lc_name
, ctr
.lc_count
, hdr
->lc_units
);
1161 if ((hdr
->lc_config
& LPROCFS_CNTR_AVGMINMAX
) &&
1162 (ctr
.lc_count
> 0)) {
1163 seq_printf(p
, " %lld %lld %lld",
1164 ctr
.lc_min
, ctr
.lc_max
, ctr
.lc_sum
);
1165 if (hdr
->lc_config
& LPROCFS_CNTR_STDDEV
)
1166 seq_printf(p
, " %lld", ctr
.lc_sumsquare
);
1174 static const struct seq_operations lprocfs_stats_seq_sops
= {
1175 .start
= lprocfs_stats_seq_start
,
1176 .stop
= lprocfs_stats_seq_stop
,
1177 .next
= lprocfs_stats_seq_next
,
1178 .show
= lprocfs_stats_seq_show
,
1181 static int lprocfs_stats_seq_open(struct inode
*inode
, struct file
*file
)
1183 struct seq_file
*seq
;
1186 rc
= seq_open(file
, &lprocfs_stats_seq_sops
);
1190 seq
= file
->private_data
;
1191 seq
->private = inode
->i_private
;
1196 struct file_operations lprocfs_stats_seq_fops
= {
1197 .owner
= THIS_MODULE
,
1198 .open
= lprocfs_stats_seq_open
,
1200 .write
= lprocfs_stats_seq_write
,
1201 .llseek
= seq_lseek
,
1202 .release
= lprocfs_seq_release
,
1205 int ldebugfs_register_stats(struct dentry
*parent
, const char *name
,
1206 struct lprocfs_stats
*stats
)
1208 struct dentry
*entry
;
1210 LASSERT(!IS_ERR_OR_NULL(parent
));
1212 entry
= debugfs_create_file(name
, 0644, parent
, stats
,
1213 &lprocfs_stats_seq_fops
);
1214 if (IS_ERR_OR_NULL(entry
))
1215 return entry
? PTR_ERR(entry
) : -ENOMEM
;
1219 EXPORT_SYMBOL(ldebugfs_register_stats
);
1221 void lprocfs_counter_init(struct lprocfs_stats
*stats
, int index
,
1222 unsigned conf
, const char *name
, const char *units
)
1224 struct lprocfs_counter_header
*header
;
1225 struct lprocfs_counter
*percpu_cntr
;
1226 unsigned long flags
= 0;
1228 unsigned int num_cpu
;
1230 LASSERT(stats
!= NULL
);
1232 header
= &stats
->ls_cnt_header
[index
];
1233 LASSERTF(header
!= NULL
, "Failed to allocate stats header:[%d]%s/%s\n",
1234 index
, name
, units
);
1236 header
->lc_config
= conf
;
1237 header
->lc_name
= name
;
1238 header
->lc_units
= units
;
1240 num_cpu
= lprocfs_stats_lock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
1241 for (i
= 0; i
< num_cpu
; ++i
) {
1242 if (stats
->ls_percpu
[i
] == NULL
)
1244 percpu_cntr
= lprocfs_stats_counter_get(stats
, i
, index
);
1245 percpu_cntr
->lc_count
= 0;
1246 percpu_cntr
->lc_min
= LC_MIN_INIT
;
1247 percpu_cntr
->lc_max
= 0;
1248 percpu_cntr
->lc_sumsquare
= 0;
1249 percpu_cntr
->lc_sum
= 0;
1250 if ((stats
->ls_flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
) != 0)
1251 percpu_cntr
->lc_sum_irq
= 0;
1253 lprocfs_stats_unlock(stats
, LPROCFS_GET_NUM_CPU
, &flags
);
1255 EXPORT_SYMBOL(lprocfs_counter_init
);
1257 int lprocfs_exp_cleanup(struct obd_export
*exp
)
1261 EXPORT_SYMBOL(lprocfs_exp_cleanup
);
1263 __s64
lprocfs_read_helper(struct lprocfs_counter
*lc
,
1264 struct lprocfs_counter_header
*header
,
1265 enum lprocfs_stats_flags flags
,
1266 enum lprocfs_fields_flags field
)
1270 if (lc
== NULL
|| header
== NULL
)
1274 case LPROCFS_FIELDS_FLAGS_CONFIG
:
1275 ret
= header
->lc_config
;
1277 case LPROCFS_FIELDS_FLAGS_SUM
:
1279 if ((flags
& LPROCFS_STATS_FLAG_IRQ_SAFE
) != 0)
1280 ret
+= lc
->lc_sum_irq
;
1282 case LPROCFS_FIELDS_FLAGS_MIN
:
1285 case LPROCFS_FIELDS_FLAGS_MAX
:
1288 case LPROCFS_FIELDS_FLAGS_AVG
:
1289 ret
= (lc
->lc_max
- lc
->lc_min
) / 2;
1291 case LPROCFS_FIELDS_FLAGS_SUMSQUARE
:
1292 ret
= lc
->lc_sumsquare
;
1294 case LPROCFS_FIELDS_FLAGS_COUNT
:
1303 EXPORT_SYMBOL(lprocfs_read_helper
);
1305 int lprocfs_write_helper(const char __user
*buffer
, unsigned long count
,
1308 return lprocfs_write_frac_helper(buffer
, count
, val
, 1);
1310 EXPORT_SYMBOL(lprocfs_write_helper
);
1312 int lprocfs_write_u64_helper(const char __user
*buffer
, unsigned long count
,
1315 return lprocfs_write_frac_u64_helper(buffer
, count
, val
, 1);
1317 EXPORT_SYMBOL(lprocfs_write_u64_helper
);
1319 int lprocfs_write_frac_u64_helper(const char *buffer
, unsigned long count
,
1320 __u64
*val
, int mult
)
1322 char kernbuf
[22], *end
, *pbuf
;
1323 __u64 whole
, frac
= 0, units
;
1324 unsigned frac_d
= 1;
1327 if (count
> (sizeof(kernbuf
) - 1))
1330 if (copy_from_user(kernbuf
, buffer
, count
))
1333 kernbuf
[count
] = '\0';
1340 whole
= simple_strtoull(pbuf
, &end
, 10);
1349 /* need to limit frac_d to a __u32 */
1350 if (strlen(pbuf
) > 10)
1353 frac
= simple_strtoull(pbuf
, &end
, 10);
1354 /* count decimal places */
1355 for (i
= 0; i
< (end
- pbuf
); i
++)
1360 switch (tolower(*end
)) {
1372 /* Specified units override the multiplier */
1377 do_div(frac
, frac_d
);
1378 *val
= sign
* (whole
* mult
+ frac
);
1381 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper
);
1383 static char *lprocfs_strnstr(const char *s1
, const char *s2
, size_t len
)
1392 if (!memcmp(s1
, s2
, l2
))
1400 * Find the string \a name in the input \a buffer, and return a pointer to the
1401 * value immediately following \a name, reducing \a count appropriately.
1402 * If \a name is not found the original \a buffer is returned.
1404 char *lprocfs_find_named_value(const char *buffer
, const char *name
,
1408 size_t buflen
= *count
;
1410 /* there is no strnstr() in rhel5 and ubuntu kernels */
1411 val
= lprocfs_strnstr(buffer
, name
, buflen
);
1413 return (char *)buffer
;
1415 val
+= strlen(name
); /* skip prefix */
1416 while (val
< buffer
+ buflen
&& isspace(*val
)) /* skip separator */
1420 while (val
< buffer
+ buflen
&& isalnum(*val
)) {
1425 return val
- *count
;
1427 EXPORT_SYMBOL(lprocfs_find_named_value
);
1429 int ldebugfs_seq_create(struct dentry
*parent
,
1432 const struct file_operations
*seq_fops
,
1435 struct dentry
*entry
;
1437 /* Disallow secretly (un)writable entries. */
1438 LASSERT((seq_fops
->write
== NULL
) == ((mode
& 0222) == 0));
1440 entry
= debugfs_create_file(name
, mode
, parent
, data
, seq_fops
);
1441 if (IS_ERR_OR_NULL(entry
))
1442 return entry
? PTR_ERR(entry
) : -ENOMEM
;
1446 EXPORT_SYMBOL(ldebugfs_seq_create
);
1448 int ldebugfs_obd_seq_create(struct obd_device
*dev
,
1451 const struct file_operations
*seq_fops
,
1454 return ldebugfs_seq_create(dev
->obd_debugfs_entry
, name
,
1455 mode
, seq_fops
, data
);
1457 EXPORT_SYMBOL(ldebugfs_obd_seq_create
);
1459 void lprocfs_oh_tally(struct obd_histogram
*oh
, unsigned int value
)
1461 if (value
>= OBD_HIST_MAX
)
1462 value
= OBD_HIST_MAX
- 1;
1464 spin_lock(&oh
->oh_lock
);
1465 oh
->oh_buckets
[value
]++;
1466 spin_unlock(&oh
->oh_lock
);
1468 EXPORT_SYMBOL(lprocfs_oh_tally
);
1470 void lprocfs_oh_tally_log2(struct obd_histogram
*oh
, unsigned int value
)
1474 for (val
= 0; ((1 << val
) < value
) && (val
<= OBD_HIST_MAX
); val
++)
1477 lprocfs_oh_tally(oh
, val
);
1479 EXPORT_SYMBOL(lprocfs_oh_tally_log2
);
1481 unsigned long lprocfs_oh_sum(struct obd_histogram
*oh
)
1483 unsigned long ret
= 0;
1486 for (i
= 0; i
< OBD_HIST_MAX
; i
++)
1487 ret
+= oh
->oh_buckets
[i
];
1490 EXPORT_SYMBOL(lprocfs_oh_sum
);
1492 void lprocfs_oh_clear(struct obd_histogram
*oh
)
1494 spin_lock(&oh
->oh_lock
);
1495 memset(oh
->oh_buckets
, 0, sizeof(oh
->oh_buckets
));
1496 spin_unlock(&oh
->oh_lock
);
1498 EXPORT_SYMBOL(lprocfs_oh_clear
);
1500 static ssize_t
lustre_attr_show(struct kobject
*kobj
,
1501 struct attribute
*attr
, char *buf
)
1503 struct lustre_attr
*a
= container_of(attr
, struct lustre_attr
, attr
);
1505 return a
->show
? a
->show(kobj
, attr
, buf
) : 0;
1508 static ssize_t
lustre_attr_store(struct kobject
*kobj
, struct attribute
*attr
,
1509 const char *buf
, size_t len
)
1511 struct lustre_attr
*a
= container_of(attr
, struct lustre_attr
, attr
);
1513 return a
->store
? a
->store(kobj
, attr
, buf
, len
) : len
;
1516 const struct sysfs_ops lustre_sysfs_ops
= {
1517 .show
= lustre_attr_show
,
1518 .store
= lustre_attr_store
,
1520 EXPORT_SYMBOL_GPL(lustre_sysfs_ops
);