1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
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>
42 # define EXPORT_SYMTAB
44 #define DEBUG_SUBSYSTEM S_CLASS
47 # include <liblustre.h>
50 #include <obd_class.h>
51 #include <lprocfs_status.h>
52 #include <lustre_fsfilt.h>
53 #include <lustre_log.h>
54 #include <lustre/lustre_idl.h>
58 #define MAX_STRING_SIZE 128
60 /* for bug 10866, global variable */
61 DECLARE_RWSEM(_lprocfs_lock);
62 EXPORT_SYMBOL(_lprocfs_lock);
64 int lprocfs_seq_release(struct inode *inode, struct file *file)
67 return seq_release(inode, file);
69 EXPORT_SYMBOL(lprocfs_seq_release);
71 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
74 struct proc_dir_entry *temp;
81 while (temp != NULL) {
82 if (strcmp(temp->name, name) == 0) {
93 /* lprocfs API calls */
95 /* Function that emulates snprintf but also has the side effect of advancing
96 the page pointer for the next write into the buffer, incrementing the total
97 length written to the buffer, and decrementing the size left in the
99 static int lprocfs_obd_snprintf(char **page, int end, int *len,
100 const char *format, ...)
108 va_start(list, format);
109 n = vsnprintf(*page, end - *len, format, list);
112 *page += n; *len += n;
116 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
118 read_proc_t *read_proc,
119 write_proc_t *write_proc,
121 struct file_operations *fops)
123 cfs_proc_dir_entry_t *proc;
126 if (root == NULL || name == NULL)
127 return ERR_PTR(-EINVAL);
134 proc = create_proc_entry(name, mode, root);
136 CERROR("LprocFS: No memory to create /proc entry %s", name);
137 return ERR_PTR(-ENOMEM);
139 proc->read_proc = read_proc;
140 proc->write_proc = write_proc;
143 proc->proc_fops = fops;
147 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
148 struct proc_dir_entry *parent, const char *dest)
150 struct proc_dir_entry *entry;
152 if (parent == NULL || dest == NULL)
155 entry = proc_symlink(name, parent, dest);
157 CERROR("LprocFS: Could not create symbolic link from %s to %s",
162 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
163 size_t size, loff_t *ppos)
165 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
166 char *page, *start = NULL;
167 int rc = 0, eof = 1, count;
169 if (*ppos >= CFS_PAGE_SIZE)
172 page = (char *)__get_free_page(GFP_KERNEL);
177 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
178 if (!dp->deleted && dp->read_proc)
179 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
185 /* for lustre proc read, the read count must be less than PAGE_SIZE */
194 start = page + *ppos;
195 } else if (start < page) {
199 count = (rc < size) ? rc : size;
200 if (copy_to_user(buf, start, count)) {
207 free_page((unsigned long)page);
211 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
212 size_t size, loff_t *ppos)
214 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
218 if (!dp->deleted && dp->write_proc)
219 rc = dp->write_proc(f, buf, size, dp->data);
224 static struct file_operations lprocfs_generic_fops = {
225 .owner = THIS_MODULE,
226 .read = lprocfs_fops_read,
227 .write = lprocfs_fops_write,
230 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
232 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
233 struct obd_device *obd = dp->data;
235 atomic_inc(&obd->obd_evict_inprogress);
240 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
242 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
243 struct obd_device *obd = dp->data;
245 atomic_dec(&obd->obd_evict_inprogress);
246 wake_up(&obd->obd_evict_inprogress_waitq);
251 struct file_operations lprocfs_evict_client_fops = {
252 .owner = THIS_MODULE,
253 .read = lprocfs_fops_read,
254 .write = lprocfs_fops_write,
255 .open = lprocfs_evict_client_open,
256 .release = lprocfs_evict_client_release,
258 EXPORT_SYMBOL(lprocfs_evict_client_fops);
263 * \param root [in] The parent proc entry on which new entry will be added.
264 * \param list [in] Array of proc entries to be added.
265 * \param data [in] The argument to be passed when entries read/write routines
266 * are called through /proc file.
268 * \retval 0 on success
271 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
274 if (root == NULL || list == NULL)
277 while (list->name != NULL) {
278 struct proc_dir_entry *cur_root, *proc;
279 char *pathcopy, *cur, *next, pathbuf[64];
280 int pathsize = strlen(list->name) + 1;
285 /* need copy of path for strsep */
286 if (strlen(list->name) > sizeof(pathbuf) - 1) {
287 OBD_ALLOC(pathcopy, pathsize);
288 if (pathcopy == NULL)
295 strcpy(pathcopy, list->name);
297 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
298 if (*cur =='\0') /* skip double/trailing "/" */
301 proc = lprocfs_srch(cur_root, cur);
302 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
303 cur_root->name, cur, next,
304 (proc ? "exists" : "new"));
306 cur_root = (proc ? proc :
307 proc_mkdir(cur, cur_root));
308 } else if (proc == NULL) {
310 if (list->proc_mode != 0000) {
311 mode = list->proc_mode;
315 if (list->write_fptr)
318 proc = create_proc_entry(cur, mode, cur_root);
322 if (pathcopy != pathbuf)
323 OBD_FREE(pathcopy, pathsize);
325 if (cur_root == NULL || proc == NULL) {
326 CERROR("LprocFS: No memory to create /proc entry %s",
332 proc->proc_fops = list->fops;
334 proc->proc_fops = &lprocfs_generic_fops;
335 proc->read_proc = list->read_fptr;
336 proc->write_proc = list->write_fptr;
337 proc->data = (list->data ? list->data : data);
343 void lprocfs_remove(struct proc_dir_entry **rooth)
345 struct proc_dir_entry *root = *rooth;
346 struct proc_dir_entry *temp = root;
347 struct proc_dir_entry *rm_entry;
348 struct proc_dir_entry *parent;
354 parent = root->parent;
355 LASSERT(parent != NULL);
356 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
359 while (temp->subdir != NULL)
365 /* Memory corruption once caused this to fail, and
366 without this LASSERT we would loop here forever. */
367 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
368 "0x%p %s/%s len %d\n", rm_entry, temp->name,
369 rm_entry->name, (int)strlen(rm_entry->name));
371 /* Now, the rm_entry->deleted flags is protected
372 * by _lprocfs_lock. */
373 rm_entry->data = NULL;
374 remove_proc_entry(rm_entry->name, temp);
378 LPROCFS_WRITE_EXIT();
381 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
383 LASSERT(parent != NULL);
384 remove_proc_entry(name, parent);
387 struct proc_dir_entry *lprocfs_register(const char *name,
388 struct proc_dir_entry *parent,
389 struct lprocfs_vars *list, void *data)
391 struct proc_dir_entry *newchild;
393 newchild = lprocfs_srch(parent, name);
394 if (newchild != NULL) {
395 CERROR(" Lproc: Attempting to register %s more than once \n",
397 return ERR_PTR(-EALREADY);
400 newchild = proc_mkdir(name, parent);
401 if (newchild != NULL && list != NULL) {
402 int rc = lprocfs_add_vars(newchild, list, data);
404 lprocfs_remove(&newchild);
411 /* Generic callbacks */
412 int lprocfs_rd_uint(char *page, char **start, off_t off,
413 int count, int *eof, void *data)
415 unsigned int *temp = data;
416 return snprintf(page, count, "%u\n", *temp);
419 int lprocfs_wr_uint(struct file *file, const char *buffer,
420 unsigned long count, void *data)
423 char dummy[MAX_STRING_SIZE + 1], *end;
426 dummy[MAX_STRING_SIZE] = '\0';
427 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
430 tmp = simple_strtoul(dummy, &end, 0);
434 *p = (unsigned int)tmp;
438 int lprocfs_rd_u64(char *page, char **start, off_t off,
439 int count, int *eof, void *data)
441 LASSERT(data != NULL);
443 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
446 int lprocfs_rd_atomic(char *page, char **start, off_t off,
447 int count, int *eof, void *data)
449 atomic_t *atom = data;
450 LASSERT(atom != NULL);
452 return snprintf(page, count, "%d\n", atomic_read(atom));
455 int lprocfs_wr_atomic(struct file *file, const char *buffer,
456 unsigned long count, void *data)
458 atomic_t *atm = data;
462 rc = lprocfs_write_helper(buffer, count, &val);
469 atomic_set(atm, val);
473 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
474 int *eof, void *data)
476 struct obd_device *obd = data;
478 LASSERT(obd != NULL);
480 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
483 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
484 int *eof, void *data)
486 struct obd_device *dev = data;
488 LASSERT(dev != NULL);
489 LASSERT(dev->obd_name != NULL);
491 return snprintf(page, count, "%s\n", dev->obd_name);
494 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
497 struct obd_device *obd = data;
499 LASSERT(obd != NULL);
500 LASSERT(obd->obd_fsops != NULL);
501 LASSERT(obd->obd_fsops->fs_type != NULL);
502 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
505 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
506 int *eof, void *data)
508 struct obd_statfs osfs;
509 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
513 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
518 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
519 int *eof, void *data)
521 struct obd_statfs osfs;
522 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
525 __u32 blk_size = osfs.os_bsize >> 10;
526 __u64 result = osfs.os_blocks;
528 while (blk_size >>= 1)
532 rc = snprintf(page, count, LPU64"\n", result);
537 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
538 int *eof, void *data)
540 struct obd_statfs osfs;
541 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
544 __u32 blk_size = osfs.os_bsize >> 10;
545 __u64 result = osfs.os_bfree;
547 while (blk_size >>= 1)
551 rc = snprintf(page, count, LPU64"\n", result);
556 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
557 int *eof, void *data)
559 struct obd_statfs osfs;
560 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
563 __u32 blk_size = osfs.os_bsize >> 10;
564 __u64 result = osfs.os_bavail;
566 while (blk_size >>= 1)
570 rc = snprintf(page, count, LPU64"\n", result);
575 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
576 int *eof, void *data)
578 struct obd_statfs osfs;
579 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
583 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
589 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
590 int *eof, void *data)
592 struct obd_statfs osfs;
593 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
597 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
602 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
603 int *eof, void *data)
605 struct obd_device *obd = data;
606 struct obd_import *imp;
607 char *imp_state_name = NULL;
610 LASSERT(obd != NULL);
611 LPROCFS_CLIMP_CHECK(obd);
612 imp = obd->u.cli.cl_import;
613 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
615 rc = snprintf(page, count, "%s\t%s%s\n",
616 obd2cli_tgt(obd), imp_state_name,
617 imp->imp_deactive ? "\tDEACTIVATED" : "");
619 LPROCFS_CLIMP_EXIT(obd);
623 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
624 int *eof, void *data)
626 struct obd_device *obd = data;
627 struct ptlrpc_connection *conn;
630 LASSERT(obd != NULL);
632 LPROCFS_CLIMP_CHECK(obd);
633 conn = obd->u.cli.cl_import->imp_connection;
634 LASSERT(conn != NULL);
636 if (obd->u.cli.cl_import) {
637 rc = snprintf(page, count, "%s\n",
638 conn->c_remote_uuid.uuid);
640 rc = snprintf(page, count, "%s\n", "<none>");
643 LPROCFS_CLIMP_EXIT(obd);
647 /** add up per-cpu counters */
648 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
649 struct lprocfs_counter *cnt)
651 unsigned int num_cpu;
652 struct lprocfs_counter t;
653 struct lprocfs_counter *percpu_cntr;
656 memset(cnt, 0, sizeof(*cnt));
659 /* set count to 1 to avoid divide-by-zero errs in callers */
664 cnt->lc_min = LC_MIN_INIT;
666 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
669 num_cpu = num_possible_cpus();
671 for (i = 0; i < num_cpu; i++) {
672 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
675 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
676 t.lc_count = percpu_cntr->lc_count;
677 t.lc_sum = percpu_cntr->lc_sum;
678 t.lc_min = percpu_cntr->lc_min;
679 t.lc_max = percpu_cntr->lc_max;
680 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
681 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
682 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
683 cnt->lc_count += t.lc_count;
684 cnt->lc_sum += t.lc_sum;
685 if (t.lc_min < cnt->lc_min)
686 cnt->lc_min = t.lc_min;
687 if (t.lc_max > cnt->lc_max)
688 cnt->lc_max = t.lc_max;
689 cnt->lc_sumsquare += t.lc_sumsquare;
692 cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
696 * Append a space separated list of current set flags to str.
698 #define flag2str(flag) \
699 if (imp->imp_##flag && max - len > 0) \
700 len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
701 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
705 if (imp->imp_obd->obd_no_recov)
706 len += snprintf(str, max - len, "no_recov");
710 flag2str(replayable);
713 flag2str(last_recon);
718 static const char *obd_connect_names[] = {
745 "mds_mds_connection",
748 "alt_checksum_algorithm",
757 static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
762 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
764 ret += snprintf(page + ret, count - ret, "%s%s",
765 ret ? sep : "", obd_connect_names[i]);
767 if (flags & ~(mask - 1))
768 ret += snprintf(page + ret, count - ret,
769 "%sunknown flags "LPX64,
770 ret ? sep : "", flags & ~(mask - 1));
774 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
775 int *eof, void *data)
777 struct lprocfs_counter ret;
778 struct obd_device *obd = (struct obd_device *)data;
779 struct obd_import *imp;
782 LASSERT(obd != NULL);
783 LPROCFS_CLIMP_CHECK(obd);
784 imp = obd->u.cli.cl_import;
787 i = snprintf(page, count,
791 " current_connection: %s\n"
796 imp->imp_connection->c_remote_uuid.uuid,
797 ptlrpc_import_state_name(imp->imp_state));
798 i += obd_connect_flags2str(page + i, count - i,
799 imp->imp_connect_data.ocd_connect_flags,
801 i += snprintf(page + i, count - i,
804 i += obd_import_flags2str(imp, page + i, count - i);
806 i += snprintf(page + i, count - i,
809 " connection_attempts: %u\n"
811 " in-progress_invalidations: %u\n",
814 atomic_read(&imp->imp_inval_count));
816 lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
817 do_div(ret.lc_sum, ret.lc_count);
818 i += snprintf(page + i, count - i,
821 " unregistering: %u\n"
823 " avg_waittime: "LPU64" %s\n",
824 atomic_read(&imp->imp_inflight),
825 atomic_read(&imp->imp_unregistering),
826 atomic_read(&imp->imp_timeouts),
827 ret.lc_sum, ret.lc_units);
830 for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
831 if (imp->imp_at.iat_portal[j] == 0)
833 k = max_t(unsigned int, k,
834 at_get(&imp->imp_at.iat_service_estimate[j]));
836 i += snprintf(page + i, count - i,
837 " service_estimates:\n"
838 " services: %u sec\n"
839 " network: %u sec\n",
841 at_get(&imp->imp_at.iat_net_latency));
843 i += snprintf(page + i, count - i,
845 " last_replay: "LPU64"\n"
846 " peer_committed: "LPU64"\n"
847 " last_checked: "LPU64"\n",
848 imp->imp_last_replay_transno,
849 imp->imp_peer_committed_transno,
850 imp->imp_last_transno_checked);
853 for (rw = 0; rw <= 1; rw++) {
854 lprocfs_stats_collect(obd->obd_svc_stats,
855 PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
857 if (ret.lc_sum > 0) {
858 do_div(ret.lc_sum, ret.lc_count);
859 i += snprintf(page + i, count - i,
860 " %s_data_averages:\n"
861 " bytes_per_rpc: "LPU64"\n",
862 rw ? "write" : "read",
866 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
867 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
868 if (ret.lc_sum > 0) {
869 do_div(ret.lc_sum, ret.lc_count);
870 i += snprintf(page + i, count - i,
871 " %s_per_rpc: "LPU64"\n",
872 ret.lc_units, ret.lc_sum);
875 i += snprintf(page + i, count - i,
876 " MB_per_sec: %u.%.02u\n",
877 k / j, (100 * k / j) % 100);
881 LPROCFS_CLIMP_EXIT(obd);
885 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
886 int *eof, void *data)
888 struct obd_device *obd = (struct obd_device *)data;
889 struct obd_import *imp;
892 LASSERT(obd != NULL);
893 LPROCFS_CLIMP_CHECK(obd);
894 imp = obd->u.cli.cl_import;
897 i = snprintf(page, count, "current_state: %s\n",
898 ptlrpc_import_state_name(imp->imp_state));
899 i += snprintf(page + i, count - i,
901 k = imp->imp_state_hist_idx;
902 for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
903 struct import_state_hist *ish =
904 &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
905 if (ish->ish_state == 0)
907 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
909 ptlrpc_import_state_name(ish->ish_state));
912 LPROCFS_CLIMP_EXIT(obd);
916 int lprocfs_at_hist_helper(char *page, int count, int rc,
917 struct adaptive_timeout *at)
920 for (i = 0; i < AT_BINS; i++)
921 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
922 rc += snprintf(page + rc, count - rc, "\n");
926 int lprocfs_rd_quota_resend_count(char *page, char **start, off_t off,
927 int count, int *eof, void *data)
929 struct obd_device *obd = data;
931 return snprintf(page, count, "%d\n",
932 atomic_read(&obd->u.cli.cl_quota_resends));
935 int lprocfs_wr_quota_resend_count(struct file *file, const char *buffer,
936 unsigned long count, void *data)
938 struct obd_device *obd = data;
941 rc = lprocfs_write_helper(buffer, count, &val);
945 atomic_set(&obd->u.cli.cl_quota_resends, val);
950 /* See also ptlrpc_lprocfs_rd_timeouts */
951 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
952 int *eof, void *data)
954 struct obd_device *obd = (struct obd_device *)data;
955 struct obd_import *imp;
956 unsigned int cur, worst;
961 LASSERT(obd != NULL);
962 LPROCFS_CLIMP_CHECK(obd);
963 imp = obd->u.cli.cl_import;
966 now = cfs_time_current_sec();
968 /* Some network health info for kicks */
969 s2dhms(&ts, now - imp->imp_last_reply_time);
970 rc += snprintf(page + rc, count - rc,
971 "%-10s : %ld, "DHMS_FMT" ago\n",
972 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
974 cur = at_get(&imp->imp_at.iat_net_latency);
975 worst = imp->imp_at.iat_net_latency.at_worst_ever;
976 worstt = imp->imp_at.iat_net_latency.at_worst_time;
977 s2dhms(&ts, now - worstt);
978 rc += snprintf(page + rc, count - rc,
979 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
980 "network", cur, worst, worstt, DHMS_VARS(&ts));
981 rc = lprocfs_at_hist_helper(page, count, rc,
982 &imp->imp_at.iat_net_latency);
984 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
985 if (imp->imp_at.iat_portal[i] == 0)
987 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
988 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
989 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
990 s2dhms(&ts, now - worstt);
991 rc += snprintf(page + rc, count - rc,
992 "portal %-2d : cur %3u worst %3u (at %ld, "
993 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
994 cur, worst, worstt, DHMS_VARS(&ts));
995 rc = lprocfs_at_hist_helper(page, count, rc,
996 &imp->imp_at.iat_service_estimate[i]);
999 LPROCFS_CLIMP_EXIT(obd);
1003 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1004 int count, int *eof, void *data)
1006 struct obd_device *obd = data;
1010 LPROCFS_CLIMP_CHECK(obd);
1011 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1012 ret = snprintf(page, count, "flags="LPX64"\n", flags);
1013 ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1014 ret += snprintf(page + ret, count - ret, "\n");
1015 LPROCFS_CLIMP_EXIT(obd);
1018 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1020 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1021 int *eof, void *data)
1023 struct obd_device *obd = data;
1025 LASSERT(obd != NULL);
1027 return snprintf(page, count, "%u\n", obd->obd_num_exports);
1030 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1031 int *eof, void *data)
1033 struct obd_type *class = (struct obd_type*) data;
1035 LASSERT(class != NULL);
1037 return snprintf(page, count, "%d\n", class->typ_refcnt);
1040 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1044 LASSERT(obd != NULL);
1045 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1046 LASSERT(obd->obd_type->typ_procroot != NULL);
1048 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1049 obd->obd_type->typ_procroot,
1051 if (IS_ERR(obd->obd_proc_entry)) {
1052 rc = PTR_ERR(obd->obd_proc_entry);
1053 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1054 obd->obd_proc_entry = NULL;
1059 int lprocfs_obd_cleanup(struct obd_device *obd)
1063 if (obd->obd_proc_exports_entry) {
1064 /* Should be no exports left */
1065 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1066 lprocfs_remove(&obd->obd_proc_exports_entry);
1067 obd->obd_proc_exports_entry = NULL;
1069 if (obd->obd_proc_entry) {
1070 lprocfs_remove(&obd->obd_proc_entry);
1071 obd->obd_proc_entry = NULL;
1076 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1078 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1079 client_stat->nid_proc, client_stat->nid_stats,
1080 client_stat->nid_brw_stats);
1082 LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
1083 "count %d\n", atomic_read(&client_stat->nid_exp_ref_count));
1085 hlist_del_init(&client_stat->nid_hash);
1087 if (client_stat->nid_proc)
1088 lprocfs_remove(&client_stat->nid_proc);
1090 if (client_stat->nid_stats)
1091 lprocfs_free_stats(&client_stat->nid_stats);
1093 if (client_stat->nid_brw_stats)
1094 OBD_FREE_PTR(client_stat->nid_brw_stats);
1096 if (client_stat->nid_ldlm_stats)
1097 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1099 OBD_FREE_PTR(client_stat);
1104 void lprocfs_free_per_client_stats(struct obd_device *obd)
1106 struct nid_stat *stat;
1109 /* we need extra list - because hash_exit called to early */
1110 /* not need locking because all clients is died */
1111 while(!list_empty(&obd->obd_nid_stats)) {
1112 stat = list_entry(obd->obd_nid_stats.next,
1113 struct nid_stat, nid_list);
1114 list_del_init(&stat->nid_list);
1115 lprocfs_free_client_stats(stat);
1121 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1122 enum lprocfs_stats_flags flags)
1124 struct lprocfs_stats *stats;
1125 unsigned int percpusize;
1127 unsigned int num_cpu;
1132 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1135 num_cpu = num_possible_cpus();
1137 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1141 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
1142 stats->ls_flags = flags;
1143 spin_lock_init(&stats->ls_lock);
1144 /* Use this lock only if there are no percpu areas */
1146 stats->ls_flags = 0;
1149 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1151 percpusize = L1_CACHE_ALIGN(percpusize);
1153 for (i = 0; i < num_cpu; i++) {
1154 OBD_ALLOC(stats->ls_percpu[i], percpusize);
1155 if (stats->ls_percpu[i] == NULL) {
1156 for (j = 0; j < i; j++) {
1157 OBD_FREE(stats->ls_percpu[j], percpusize);
1158 stats->ls_percpu[j] = NULL;
1163 if (stats->ls_percpu[0] == NULL) {
1164 OBD_FREE(stats, offsetof(typeof(*stats),
1165 ls_percpu[num_cpu]));
1169 stats->ls_num = num;
1173 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1175 struct lprocfs_stats *stats = *statsh;
1176 unsigned int num_cpu;
1177 unsigned int percpusize;
1180 if (stats == NULL || stats->ls_num == 0)
1184 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1187 num_cpu = num_possible_cpus();
1189 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1191 percpusize = L1_CACHE_ALIGN(percpusize);
1192 for (i = 0; i < num_cpu; i++)
1193 OBD_FREE(stats->ls_percpu[i], percpusize);
1194 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1197 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1199 struct lprocfs_counter *percpu_cntr;
1201 unsigned int num_cpu;
1203 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1205 for (i = 0; i < num_cpu; i++) {
1206 for (j = 0; j < stats->ls_num; j++) {
1207 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1208 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1209 percpu_cntr->lc_count = 0;
1210 percpu_cntr->lc_sum = 0;
1211 percpu_cntr->lc_min = LC_MIN_INIT;
1212 percpu_cntr->lc_max = 0;
1213 percpu_cntr->lc_sumsquare = 0;
1214 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1218 lprocfs_stats_unlock(stats);
1221 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1222 size_t len, loff_t *off)
1224 struct seq_file *seq = file->private_data;
1225 struct lprocfs_stats *stats = seq->private;
1227 lprocfs_clear_stats(stats);
1232 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1234 struct lprocfs_stats *stats = p->private;
1235 /* return 1st cpu location */
1236 return (*pos >= stats->ls_num) ? NULL :
1237 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1240 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1244 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1246 struct lprocfs_stats *stats = p->private;
1248 return (*pos >= stats->ls_num) ? NULL :
1249 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1252 /* seq file export of one lprocfs counter */
1253 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1255 struct lprocfs_stats *stats = p->private;
1256 struct lprocfs_counter *cntr = v;
1257 struct lprocfs_counter ret;
1260 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1262 do_gettimeofday(&now);
1263 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1264 "snapshot_time", now.tv_sec, now.tv_usec);
1268 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1270 lprocfs_stats_collect(stats, idx, &ret);
1272 if (ret.lc_count == 0)
1275 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1276 ret.lc_count, cntr->lc_units);
1281 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1282 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1283 ret.lc_min, ret.lc_max, ret.lc_sum);
1286 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1287 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1291 rc = seq_printf(p, "\n");
1293 return (rc < 0) ? rc : 0;
1296 struct seq_operations lprocfs_stats_seq_sops = {
1297 start: lprocfs_stats_seq_start,
1298 stop: lprocfs_stats_seq_stop,
1299 next: lprocfs_stats_seq_next,
1300 show: lprocfs_stats_seq_show,
1303 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1305 struct proc_dir_entry *dp = PDE(inode);
1306 struct seq_file *seq;
1309 LPROCFS_ENTRY_AND_CHECK(dp);
1310 rc = seq_open(file, &lprocfs_stats_seq_sops);
1315 seq = file->private_data;
1316 seq->private = dp->data;
1320 struct file_operations lprocfs_stats_seq_fops = {
1321 .owner = THIS_MODULE,
1322 .open = lprocfs_stats_seq_open,
1324 .write = lprocfs_stats_seq_write,
1325 .llseek = seq_lseek,
1326 .release = lprocfs_seq_release,
1329 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1330 struct lprocfs_stats *stats)
1332 struct proc_dir_entry *entry;
1333 LASSERT(root != NULL);
1335 entry = create_proc_entry(name, 0644, root);
1338 entry->proc_fops = &lprocfs_stats_seq_fops;
1339 entry->data = stats;
1343 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1344 unsigned conf, const char *name, const char *units)
1346 struct lprocfs_counter *c;
1348 unsigned int num_cpu;
1350 LASSERT(stats != NULL);
1352 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1354 for (i = 0; i < num_cpu; i++) {
1355 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1356 c->lc_config = conf;
1359 c->lc_min = LC_MIN_INIT;
1362 c->lc_units = units;
1365 lprocfs_stats_unlock(stats);
1367 EXPORT_SYMBOL(lprocfs_counter_init);
1369 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1371 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1372 LASSERT(coffset < stats->ls_num); \
1373 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1376 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1378 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1379 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1380 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1381 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1382 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1383 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1384 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1385 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1386 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1387 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1388 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1389 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1390 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1391 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1392 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1393 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1394 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1395 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1396 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1397 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1398 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1399 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1400 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1401 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1402 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1403 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1404 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1405 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1406 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1407 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1408 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1409 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1410 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1411 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1412 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1413 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1414 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1415 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1416 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1417 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1418 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1419 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1420 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1421 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1422 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1423 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1424 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1425 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1426 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1427 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1428 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1429 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1430 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1431 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1432 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1433 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1434 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1435 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1436 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1437 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1438 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1439 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1440 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1441 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1442 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1443 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1444 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1445 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1446 LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1449 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1451 struct lprocfs_stats *stats;
1452 unsigned int num_stats;
1455 LASSERT(obd->obd_stats == NULL);
1456 LASSERT(obd->obd_proc_entry != NULL);
1457 LASSERT(obd->obd_cntr_base == 0);
1459 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1460 num_private_stats - 1 /* o_owner */;
1461 stats = lprocfs_alloc_stats(num_stats, 0);
1465 lprocfs_init_ops_stats(num_private_stats, stats);
1467 for (i = num_private_stats; i < num_stats; i++) {
1468 /* If this LBUGs, it is likely that an obd
1469 * operation was added to struct obd_ops in
1470 * <obd.h>, and that the corresponding line item
1471 * LPROCFS_OBD_OP_INIT(.., .., opname)
1472 * is missing from the list above. */
1473 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1474 "Missing obd_stat initializer obd_op "
1475 "operation at offset %d.\n", i - num_private_stats);
1477 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1479 lprocfs_free_stats(&stats);
1481 obd->obd_stats = stats;
1482 obd->obd_cntr_base = num_private_stats;
1487 void lprocfs_free_obd_stats(struct obd_device *obd)
1490 lprocfs_free_stats(&obd->obd_stats);
1493 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1495 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1496 LASSERT(coffset < stats->ls_num); \
1497 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1500 int lprocfs_alloc_md_stats(struct obd_device *obd,
1501 unsigned num_private_stats)
1503 struct lprocfs_stats *stats;
1504 unsigned int num_stats;
1507 LASSERT(obd->md_stats == NULL);
1508 LASSERT(obd->obd_proc_entry != NULL);
1509 LASSERT(obd->md_cntr_base == 0);
1511 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1513 stats = lprocfs_alloc_stats(num_stats, 0);
1517 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1518 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1519 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1520 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1521 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1522 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1523 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1524 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1525 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1526 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1527 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1528 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1529 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1530 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1531 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1532 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1533 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1534 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1535 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1536 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1537 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1538 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1539 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1540 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1541 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1542 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1543 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1544 LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1545 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1546 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1547 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1549 for (i = num_private_stats; i < num_stats; i++) {
1550 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1551 CERROR("Missing md_stat initializer md_op "
1552 "operation at offset %d. Aborting.\n",
1553 i - num_private_stats);
1557 rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1559 lprocfs_free_stats(&stats);
1561 obd->md_stats = stats;
1562 obd->md_cntr_base = num_private_stats;
1567 void lprocfs_free_md_stats(struct obd_device *obd)
1569 struct lprocfs_stats *stats = obd->md_stats;
1571 if (stats != NULL) {
1572 obd->md_stats = NULL;
1573 obd->md_cntr_base = 0;
1574 lprocfs_free_stats(&stats);
1578 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1580 lprocfs_counter_init(ldlm_stats,
1581 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1582 0, "ldlm_enqueue", "reqs");
1583 lprocfs_counter_init(ldlm_stats,
1584 LDLM_CONVERT - LDLM_FIRST_OPC,
1585 0, "ldlm_convert", "reqs");
1586 lprocfs_counter_init(ldlm_stats,
1587 LDLM_CANCEL - LDLM_FIRST_OPC,
1588 0, "ldlm_cancel", "reqs");
1589 lprocfs_counter_init(ldlm_stats,
1590 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1591 0, "ldlm_bl_callback", "reqs");
1592 lprocfs_counter_init(ldlm_stats,
1593 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1594 0, "ldlm_cp_callback", "reqs");
1595 lprocfs_counter_init(ldlm_stats,
1596 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1597 0, "ldlm_gl_callback", "reqs");
1600 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1601 int *eof, void *data)
1603 struct obd_export *exp = data;
1604 LASSERT(exp != NULL);
1606 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1609 struct exp_uuid_cb_data {
1617 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1618 int count, int *eof, int *len)
1620 cb_data->page = page;
1621 cb_data->count = count;
1626 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1628 struct obd_export *exp = (struct obd_export *)obj;
1629 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1631 if (exp->exp_nid_stats)
1632 *data->len += snprintf((data->page + *data->len),
1633 data->count, "%s\n",
1634 obd_uuid2str(&exp->exp_client_uuid));
1637 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1638 int *eof, void *data)
1640 struct nid_stat *stats = (struct nid_stat *)data;
1641 struct exp_uuid_cb_data cb_data;
1642 struct obd_device *obd = stats->nid_obd;
1647 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1648 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1649 lprocfs_exp_print_uuid, &cb_data);
1650 return (*cb_data.len);
1653 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1655 struct exp_uuid_cb_data *data = cb_data;
1656 struct obd_export *exp = obj;
1659 lh = exp->exp_lock_hash;
1662 *data->len += lustre_hash_debug_header(data->page,
1665 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1670 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1671 int *eof, void *data)
1673 struct nid_stat *stats = (struct nid_stat *)data;
1674 struct exp_uuid_cb_data cb_data;
1675 struct obd_device *obd = stats->nid_obd;
1680 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1682 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1683 lprocfs_exp_print_hash, &cb_data);
1684 return (*cb_data.len);
1687 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1688 int count, int *eof, void *data)
1691 return snprintf(page, count, "%s\n",
1692 "Write into this file to clear all nid stats and "
1693 "stale nid entries");
1695 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1697 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1699 struct nid_stat *stat = obj;
1702 /* object has only hash + iterate_all references.
1703 * add/delete blocked by hash bucket lock */
1704 CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
1705 if (atomic_read(&stat->nid_exp_ref_count) == 2) {
1706 hlist_del_init(&stat->nid_hash);
1707 nidstat_putref(stat);
1708 spin_lock(&stat->nid_obd->obd_nid_lock);
1709 list_move(&stat->nid_list, data);
1710 spin_unlock(&stat->nid_obd->obd_nid_lock);
1714 /* we has reference to object - only clear data*/
1715 if (stat->nid_stats)
1716 lprocfs_clear_stats(stat->nid_stats);
1718 if (stat->nid_brw_stats) {
1719 for (i = 0; i < BRW_LAST; i++)
1720 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1726 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1727 unsigned long count, void *data)
1729 struct obd_device *obd = (struct obd_device *)data;
1730 struct nid_stat *client_stat;
1731 CFS_LIST_HEAD(free_list);
1733 lustre_hash_for_each(obd->obd_nid_stats_hash,
1734 lprocfs_nid_stats_clear_write_cb, &free_list);
1736 while (!list_empty(&free_list)) {
1737 client_stat = list_entry(free_list.next, struct nid_stat,
1739 list_del_init(&client_stat->nid_list);
1740 lprocfs_free_client_stats(client_stat);
1745 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1747 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1749 struct nid_stat *new_stat, *old_stat;
1750 struct obd_device *obd = NULL;
1751 cfs_proc_dir_entry_t *entry;
1757 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1758 !exp->exp_obd->obd_nid_stats_hash)
1761 /* not test against zero because eric say:
1762 * You may only test nid against another nid, or LNET_NID_ANY.
1763 * Anything else is nonsense.*/
1764 if (!nid || *nid == LNET_NID_ANY)
1769 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1771 OBD_ALLOC_PTR(new_stat);
1772 if (new_stat == NULL)
1775 new_stat->nid = *nid;
1776 new_stat->nid_obd = exp->exp_obd;
1777 atomic_set(&new_stat->nid_exp_ref_count, 0);
1779 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1780 nid, &new_stat->nid_hash);
1781 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1782 old_stat, libcfs_nid2str(*nid),
1783 atomic_read(&new_stat->nid_exp_ref_count));
1785 /* Return -EALREADY here so that we know that the /proc
1786 * entry already has been created */
1787 if (old_stat != new_stat) {
1788 spin_lock(&obd->obd_nid_lock);
1789 if (exp->exp_nid_stats != old_stat) {
1790 if (exp->exp_nid_stats)
1791 nidstat_putref(exp->exp_nid_stats);
1792 exp->exp_nid_stats = old_stat;
1794 /* lustre_hash_findadd_unique() has added
1795 * old_stat's refcount */
1796 nidstat_putref(old_stat);
1799 spin_unlock(&obd->obd_nid_lock);
1801 GOTO(destroy_new, rc = -EALREADY);
1803 /* not found - create */
1804 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1805 obd->obd_proc_exports_entry,
1807 if (new_stat->nid_proc == NULL) {
1808 CERROR("Error making export directory for nid %s\n",
1809 libcfs_nid2str(*nid));
1810 GOTO(destroy_new_ns, rc = -ENOMEM);
1813 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1814 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1815 if (IS_ERR(entry)) {
1816 CWARN("Error adding the NID stats file\n");
1817 rc = PTR_ERR(entry);
1818 GOTO(destroy_new_ns, rc);
1821 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1822 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1823 if (IS_ERR(entry)) {
1824 CWARN("Error adding the hash file\n");
1825 rc = PTR_ERR(entry);
1826 GOTO(destroy_new_ns, rc);
1829 if (exp->exp_nid_stats)
1830 nidstat_putref(exp->exp_nid_stats);
1831 nidstat_getref(new_stat);
1832 exp->exp_nid_stats = new_stat;
1834 /* protect competitive add to list, not need locking on destroy */
1835 spin_lock(&obd->obd_nid_lock);
1836 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1837 spin_unlock(&obd->obd_nid_lock);
1842 if (new_stat->nid_proc != NULL)
1843 lprocfs_remove(&new_stat->nid_proc);
1844 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1847 OBD_FREE_PTR(new_stat);
1851 int lprocfs_exp_cleanup(struct obd_export *exp)
1853 struct nid_stat *stat = exp->exp_nid_stats;
1855 if(!stat || !exp->exp_obd)
1858 nidstat_putref(exp->exp_nid_stats);
1859 exp->exp_nid_stats = NULL;
1860 lprocfs_free_md_stats(exp->exp_obd);
1865 int lprocfs_write_helper(const char *buffer, unsigned long count,
1868 return lprocfs_write_frac_helper(buffer, count, val, 1);
1871 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1874 char kernbuf[20], *end, *pbuf;
1876 if (count > (sizeof(kernbuf) - 1))
1879 if (copy_from_user(kernbuf, buffer, count))
1882 kernbuf[count] = '\0';
1889 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1893 if (end != NULL && *end == '.') {
1894 int temp_val, pow = 1;
1898 if (strlen(pbuf) > 5)
1899 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1901 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1904 for (i = 0; i < (end - pbuf); i++)
1907 *val += temp_val / pow;
1913 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1916 long decimal_val, frac_val;
1922 decimal_val = val / mult;
1923 prtn = snprintf(buffer, count, "%ld", decimal_val);
1924 frac_val = val % mult;
1926 if (prtn < (count - 4) && frac_val > 0) {
1928 int i, temp_mult = 1, frac_bits = 0;
1930 temp_frac = frac_val * 10;
1931 buffer[prtn++] = '.';
1932 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1933 /* only reserved 2 bits fraction */
1934 buffer[prtn++] ='0';
1939 * Need to think these cases :
1940 * 1. #echo x.00 > /proc/xxx output result : x
1941 * 2. #echo x.0x > /proc/xxx output result : x.0x
1942 * 3. #echo x.x0 > /proc/xxx output result : x.x
1943 * 4. #echo x.xx > /proc/xxx output result : x.xx
1944 * Only reserved 2 bits fraction.
1946 for (i = 0; i < (5 - prtn); i++)
1949 frac_bits = min((int)count - prtn, 3 - frac_bits);
1950 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1951 frac_val * temp_mult / mult);
1954 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1956 if (buffer[prtn] == '.') {
1963 buffer[prtn++] ='\n';
1967 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1969 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1972 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1973 __u64 *val, int mult)
1975 char kernbuf[22], *end, *pbuf;
1976 __u64 whole, frac = 0, units;
1977 unsigned frac_d = 1;
1979 if (count > (sizeof(kernbuf) - 1))
1982 if (copy_from_user(kernbuf, buffer, count))
1985 kernbuf[count] = '\0';
1992 whole = simple_strtoull(pbuf, &end, 10);
1996 if (end != NULL && *end == '.') {
2000 /* need to limit frac_d to a __u32 */
2001 if (strlen(pbuf) > 10)
2004 frac = simple_strtoull(pbuf, &end, 10);
2005 /* count decimal places */
2006 for (i = 0; i < (end - pbuf); i++)
2023 /* Specified units override the multiplier */
2025 mult = mult < 0 ? -units : units;
2028 do_div(frac, frac_d);
2029 *val = whole * mult + frac;
2033 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2034 struct file_operations *seq_fops, void *data)
2036 struct proc_dir_entry *entry;
2039 entry = create_proc_entry(name, mode, parent);
2042 entry->proc_fops = seq_fops;
2047 EXPORT_SYMBOL(lprocfs_seq_create);
2049 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2051 struct file_operations *seq_fops,
2054 return (lprocfs_seq_create(dev->obd_proc_entry, name,
2055 mode, seq_fops, data));
2057 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2059 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2061 if (value >= OBD_HIST_MAX)
2062 value = OBD_HIST_MAX - 1;
2064 spin_lock(&oh->oh_lock);
2065 oh->oh_buckets[value]++;
2066 spin_unlock(&oh->oh_lock);
2068 EXPORT_SYMBOL(lprocfs_oh_tally);
2070 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2074 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2077 lprocfs_oh_tally(oh, val);
2079 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2081 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2083 unsigned long ret = 0;
2086 for (i = 0; i < OBD_HIST_MAX; i++)
2087 ret += oh->oh_buckets[i];
2090 EXPORT_SYMBOL(lprocfs_oh_sum);
2092 void lprocfs_oh_clear(struct obd_histogram *oh)
2094 spin_lock(&oh->oh_lock);
2095 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2096 spin_unlock(&oh->oh_lock);
2098 EXPORT_SYMBOL(lprocfs_oh_clear);
2100 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2101 int count, int *eof, void *data)
2103 struct obd_device *obd = data;
2109 c += lustre_hash_debug_header(page, count);
2110 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2111 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2112 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2116 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2118 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2119 int count, int *eof, void *data)
2121 struct obd_device *obd = data;
2124 LASSERT(obd != NULL);
2125 LASSERT(count >= 0);
2127 /* Set start of user data returned to
2128 page + off since the user may have
2129 requested to read much smaller than
2130 what we need to read */
2131 *start = page + off;
2133 /* We know we are allocated a page here.
2134 Also we know that this function will
2135 not need to write more than a page
2136 so we can truncate at CFS_PAGE_SIZE. */
2137 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2139 /* Initialize the page */
2140 memset(page, 0, size);
2142 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2144 if (obd->obd_max_recoverable_clients == 0) {
2145 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2151 /* sampled unlocked, but really... */
2152 if (obd->obd_recovering == 0) {
2153 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2155 if (lprocfs_obd_snprintf(&page, size, &len,
2156 "recovery_start: %lu\n",
2157 obd->obd_recovery_start) <= 0)
2159 if (lprocfs_obd_snprintf(&page, size, &len,
2160 "recovery_duration: %lu\n",
2161 obd->obd_recovery_end -
2162 obd->obd_recovery_start) <= 0)
2164 /* Number of clients that have completed recovery */
2165 if (lprocfs_obd_snprintf(&page, size, &len,
2166 "completed_clients: %d/%d\n",
2167 obd->obd_max_recoverable_clients -
2168 obd->obd_stale_clients,
2169 obd->obd_max_recoverable_clients) <= 0)
2171 if (lprocfs_obd_snprintf(&page, size, &len,
2172 "replayed_requests: %d\n",
2173 obd->obd_replayed_requests) <= 0)
2175 if (lprocfs_obd_snprintf(&page, size, &len,
2176 "last_transno: "LPD64"\n",
2177 obd->obd_next_recovery_transno - 1)<=0)
2179 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2180 obd->obd_version_recov ? "ON" : "OFF")<=0)
2185 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2187 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2188 obd->obd_recovery_start) <= 0)
2190 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2191 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2192 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2194 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2195 obd->obd_connected_clients,
2196 obd->obd_max_recoverable_clients) <= 0)
2198 /* Number of clients that have completed recovery */
2199 if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2200 atomic_read(&obd->obd_req_replay_clients))<= 0)
2202 if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2203 atomic_read(&obd->obd_lock_replay_clients))<=0)
2205 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2206 obd->obd_connected_clients -
2207 atomic_read(&obd->obd_lock_replay_clients))<=0)
2209 if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2210 obd->obd_stale_clients) <= 0)
2212 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2213 obd->obd_replayed_requests) <= 0)
2215 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2216 obd->obd_requests_queued_for_recovery) <= 0)
2219 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2220 obd->obd_next_recovery_transno) <= 0)
2226 return min(count, len - (int)off);
2228 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2230 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2231 int count, int *eof, void *data)
2233 struct obd_device *obd = data;
2234 LASSERT(obd != NULL);
2236 return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2238 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2240 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2241 unsigned long count, void *data)
2243 struct obd_device *obd = data;
2245 LASSERT(obd != NULL);
2247 rc = lprocfs_write_helper(buffer, count, &val);
2251 obd->obd_recovery_max_time = val;
2254 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2257 EXPORT_SYMBOL(lprocfs_register);
2258 EXPORT_SYMBOL(lprocfs_srch);
2259 EXPORT_SYMBOL(lprocfs_remove);
2260 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2261 EXPORT_SYMBOL(lprocfs_add_vars);
2262 EXPORT_SYMBOL(lprocfs_obd_setup);
2263 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2264 EXPORT_SYMBOL(lprocfs_add_simple);
2265 EXPORT_SYMBOL(lprocfs_add_symlink);
2266 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2267 EXPORT_SYMBOL(lprocfs_alloc_stats);
2268 EXPORT_SYMBOL(lprocfs_free_stats);
2269 EXPORT_SYMBOL(lprocfs_clear_stats);
2270 EXPORT_SYMBOL(lprocfs_register_stats);
2271 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2272 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2273 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2274 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2275 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2276 EXPORT_SYMBOL(lprocfs_exp_setup);
2277 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2279 EXPORT_SYMBOL(lprocfs_rd_u64);
2280 EXPORT_SYMBOL(lprocfs_rd_atomic);
2281 EXPORT_SYMBOL(lprocfs_wr_atomic);
2282 EXPORT_SYMBOL(lprocfs_rd_uint);
2283 EXPORT_SYMBOL(lprocfs_wr_uint);
2284 EXPORT_SYMBOL(lprocfs_rd_uuid);
2285 EXPORT_SYMBOL(lprocfs_rd_name);
2286 EXPORT_SYMBOL(lprocfs_rd_fstype);
2287 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2288 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2289 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2290 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2291 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2292 EXPORT_SYMBOL(lprocfs_rd_import);
2293 EXPORT_SYMBOL(lprocfs_rd_state);
2294 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2295 EXPORT_SYMBOL(lprocfs_rd_blksize);
2296 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2297 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2298 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2299 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2300 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2301 EXPORT_SYMBOL(lprocfs_rd_quota_resend_count);
2302 EXPORT_SYMBOL(lprocfs_wr_quota_resend_count);
2304 EXPORT_SYMBOL(lprocfs_write_helper);
2305 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2306 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2307 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2308 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2309 EXPORT_SYMBOL(lprocfs_stats_collect);