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>
56 #define MAX_STRING_SIZE 128
58 /* for bug 10866, global variable */
59 DECLARE_RWSEM(_lprocfs_lock);
60 EXPORT_SYMBOL(_lprocfs_lock);
62 int lprocfs_seq_release(struct inode *inode, struct file *file)
65 return seq_release(inode, file);
67 EXPORT_SYMBOL(lprocfs_seq_release);
69 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
72 struct proc_dir_entry *temp;
79 while (temp != NULL) {
80 if (strcmp(temp->name, name) == 0) {
91 /* lprocfs API calls */
93 /* Function that emulates snprintf but also has the side effect of advancing
94 the page pointer for the next write into the buffer, incrementing the total
95 length written to the buffer, and decrementing the size left in the
97 static int lprocfs_obd_snprintf(char **page, int end, int *len,
98 const char *format, ...)
106 va_start(list, format);
107 n = vsnprintf(*page, end - *len, format, list);
110 *page += n; *len += n;
114 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
116 read_proc_t *read_proc,
117 write_proc_t *write_proc,
119 struct file_operations *fops)
121 cfs_proc_dir_entry_t *proc;
124 if (root == NULL || name == NULL)
125 return ERR_PTR(-EINVAL);
132 proc = create_proc_entry(name, mode, root);
134 CERROR("LprocFS: No memory to create /proc entry %s", name);
135 return ERR_PTR(-ENOMEM);
137 proc->read_proc = read_proc;
138 proc->write_proc = write_proc;
141 proc->proc_fops = fops;
145 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf, size_t size,
148 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
149 char *page, *start = NULL;
150 int rc = 0, eof = 1, count;
152 if (*ppos >= PAGE_SIZE)
155 page = (char *)__get_free_page(GFP_KERNEL);
160 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
161 if (!LPROCFS_CHECK_DELETED(dp) && dp->read_proc)
162 rc = dp->read_proc(page, &start, *ppos, PAGE_SIZE,
168 /* for lustre proc read, the read count must be less than PAGE_SIZE */
177 start = page + *ppos;
178 } else if (start < page) {
182 count = (rc < size) ? rc : size;
183 if (copy_to_user(buf, start, count)) {
190 free_page((unsigned long)page);
194 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
195 size_t size, loff_t *ppos)
197 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
201 if (!LPROCFS_CHECK_DELETED(dp) && dp->write_proc)
202 rc = dp->write_proc(f, buf, size, dp->data);
207 static struct file_operations lprocfs_generic_fops = {
208 .owner = THIS_MODULE,
209 .read = lprocfs_fops_read,
210 .write = lprocfs_fops_write,
213 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
215 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
216 struct obd_device *obd = dp->data;
218 atomic_inc(&obd->obd_evict_inprogress);
223 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
225 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
226 struct obd_device *obd = dp->data;
228 atomic_dec(&obd->obd_evict_inprogress);
229 wake_up(&obd->obd_evict_inprogress_waitq);
234 struct file_operations lprocfs_evict_client_fops = {
235 .owner = THIS_MODULE,
236 .read = lprocfs_fops_read,
237 .write = lprocfs_fops_write,
238 .open = lprocfs_evict_client_open,
239 .release = lprocfs_evict_client_release,
241 EXPORT_SYMBOL(lprocfs_evict_client_fops);
246 * \param root [in] The parent proc entry on which new entry will be added.
247 * \param list [in] Array of proc entries to be added.
248 * \param data [in] The argument to be passed when entries read/write routines
249 * are called through /proc file.
251 * \retval 0 on success
254 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
257 if (root == NULL || list == NULL)
260 while (list->name != NULL) {
261 struct proc_dir_entry *cur_root, *proc;
262 char *pathcopy, *cur, *next, pathbuf[64];
263 int pathsize = strlen(list->name) + 1;
268 /* need copy of path for strsep */
269 if (strlen(list->name) > sizeof(pathbuf) - 1) {
270 OBD_ALLOC(pathcopy, pathsize);
271 if (pathcopy == NULL)
278 strcpy(pathcopy, list->name);
280 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
281 if (*cur =='\0') /* skip double/trailing "/" */
284 proc = lprocfs_srch(cur_root, cur);
285 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
286 cur_root->name, cur, next,
287 (proc ? "exists" : "new"));
289 cur_root = (proc ? proc :
290 proc_mkdir(cur, cur_root));
291 } else if (proc == NULL) {
293 if (list->proc_mode != 0000) {
294 mode = list->proc_mode;
298 if (list->write_fptr)
301 proc = create_proc_entry(cur, mode, cur_root);
305 if (pathcopy != pathbuf)
306 OBD_FREE(pathcopy, pathsize);
308 if (cur_root == NULL || proc == NULL) {
309 CERROR("LprocFS: No memory to create /proc entry %s",
315 proc->proc_fops = list->fops;
317 proc->proc_fops = &lprocfs_generic_fops;
318 proc->read_proc = list->read_fptr;
319 proc->write_proc = list->write_fptr;
320 proc->data = (list->data ? list->data : data);
326 void lprocfs_remove(struct proc_dir_entry **rooth)
328 struct proc_dir_entry *root = *rooth;
329 struct proc_dir_entry *temp = root;
330 struct proc_dir_entry *rm_entry;
331 struct proc_dir_entry *parent;
337 parent = root->parent;
338 LASSERT(parent != NULL);
339 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
342 while (temp->subdir != NULL)
348 /* Memory corruption once caused this to fail, and
349 without this LASSERT we would loop here forever. */
350 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
351 "0x%p %s/%s len %d\n", rm_entry, temp->name,
352 rm_entry->name, (int)strlen(rm_entry->name));
354 #ifdef HAVE_PROCFS_USERS
355 /* if procfs uses user count to synchronize deletion of
356 * proc entry, there is no protection for rm_entry->data,
357 * then lprocfs_fops_read and lprocfs_fops_write maybe
358 * call proc_dir_entry->read_proc (or write_proc) with
359 * proc_dir_entry->data == NULL, then cause kernel Oops.
360 * see bug19706 for detailed information */
362 /* procfs won't free rm_entry->data if it isn't a LINK,
363 * and Lustre won't use rm_entry->data if it is a LINK */
364 if (S_ISLNK(rm_entry->mode))
365 rm_entry->data = NULL;
367 /* Now, the rm_entry->deleted flags is protected
368 * by _lprocfs_lock. */
369 rm_entry->data = NULL;
371 remove_proc_entry(rm_entry->name, temp);
375 LPROCFS_WRITE_EXIT();
378 struct proc_dir_entry *lprocfs_register(const char *name,
379 struct proc_dir_entry *parent,
380 struct lprocfs_vars *list, void *data)
382 struct proc_dir_entry *newchild;
384 newchild = lprocfs_srch(parent, name);
385 if (newchild != NULL) {
386 CERROR(" Lproc: Attempting to register %s more than once \n",
388 return ERR_PTR(-EALREADY);
391 newchild = proc_mkdir(name, parent);
392 if (newchild != NULL && list != NULL) {
393 int rc = lprocfs_add_vars(newchild, list, data);
395 lprocfs_remove(&newchild);
402 /* Generic callbacks */
403 int lprocfs_rd_uint(char *page, char **start, off_t off,
404 int count, int *eof, void *data)
406 unsigned int *temp = (unsigned int *)data;
407 return snprintf(page, count, "%u\n", *temp);
410 int lprocfs_wr_uint(struct file *file, const char *buffer,
411 unsigned long count, void *data)
414 char dummy[MAX_STRING_SIZE + 1] = { '\0' }, *end;
417 if (count >= sizeof(dummy) || count == 0)
420 if (copy_from_user(dummy, buffer, count))
423 tmp = simple_strtoul(dummy, &end, 0);
427 *p = (unsigned int)tmp;
431 int lprocfs_rd_u64(char *page, char **start, off_t off,
432 int count, int *eof, void *data)
434 LASSERT(data != NULL);
436 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
439 int lprocfs_rd_atomic(char *page, char **start, off_t off,
440 int count, int *eof, void *data)
442 atomic_t *atom = (atomic_t *)data;
443 LASSERT(atom != NULL);
445 return snprintf(page, count, "%d\n", atomic_read(atom));
448 int lprocfs_wr_atomic(struct file *file, const char *buffer,
449 unsigned long count, void *data)
451 atomic_t *atm = data;
455 rc = lprocfs_write_helper(buffer, count, &val);
462 atomic_set(atm, val);
466 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
467 int *eof, void *data)
469 struct obd_device *obd = (struct obd_device*)data;
471 LASSERT(obd != NULL);
473 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
476 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
477 int *eof, void* data)
479 struct obd_device *dev = (struct obd_device *)data;
481 LASSERT(dev != NULL);
482 LASSERT(dev->obd_name != NULL);
484 return snprintf(page, count, "%s\n", dev->obd_name);
487 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
490 struct obd_device *obd = (struct obd_device *)data;
492 LASSERT(obd != NULL);
493 LASSERT(obd->obd_fsops != NULL);
494 LASSERT(obd->obd_fsops->fs_type != NULL);
495 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
498 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
499 int *eof, void *data)
501 struct obd_statfs osfs;
502 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
506 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
511 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
512 int *eof, void *data)
514 struct obd_statfs osfs;
515 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
518 __u32 blk_size = osfs.os_bsize >> 10;
519 __u64 result = osfs.os_blocks;
521 while (blk_size >>= 1)
525 rc = snprintf(page, count, LPU64"\n", result);
530 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
531 int *eof, void *data)
533 struct obd_statfs osfs;
534 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
537 __u32 blk_size = osfs.os_bsize >> 10;
538 __u64 result = osfs.os_bfree;
540 while (blk_size >>= 1)
544 rc = snprintf(page, count, LPU64"\n", result);
549 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
550 int *eof, void *data)
552 struct obd_statfs osfs;
553 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
556 __u32 blk_size = osfs.os_bsize >> 10;
557 __u64 result = osfs.os_bavail;
559 while (blk_size >>= 1)
563 rc = snprintf(page, count, LPU64"\n", result);
568 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
569 int *eof, void *data)
571 struct obd_statfs osfs;
572 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
576 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
582 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
583 int *eof, void *data)
585 struct obd_statfs osfs;
586 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
590 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
595 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
596 int *eof, void *data)
598 struct obd_device *obd = (struct obd_device *)data;
599 struct obd_import *imp;
600 char *imp_state_name = NULL;
603 LASSERT(obd != NULL);
604 LPROCFS_CLIMP_CHECK(obd);
605 imp = obd->u.cli.cl_import;
606 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
608 rc = snprintf(page, count, "%s\t%s%s\n",
609 obd2cli_tgt(obd), imp_state_name,
610 imp->imp_deactive ? "\tDEACTIVATED" : "");
612 LPROCFS_CLIMP_EXIT(obd);
616 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
617 int *eof, void *data)
619 struct obd_device *obd = (struct obd_device*)data;
620 struct ptlrpc_connection *conn;
623 LASSERT(obd != NULL);
624 LPROCFS_CLIMP_CHECK(obd);
625 conn = obd->u.cli.cl_import->imp_connection;
626 LASSERT(conn != NULL);
628 rc = snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
630 LPROCFS_CLIMP_EXIT(obd);
634 /** add up per-cpu counters */
635 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
636 struct lprocfs_counter *cnt)
638 unsigned int num_cpu;
639 struct lprocfs_counter t;
640 struct lprocfs_counter *percpu_cntr;
643 memset(cnt, 0, sizeof(*cnt));
646 /* set count to 1 to avoid divide-by-zero errs in callers */
651 cnt->lc_min = LC_MIN_INIT;
653 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
656 num_cpu = num_possible_cpus();
658 for (i = 0; i < num_cpu; i++) {
659 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[idx];
662 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
663 t.lc_count = percpu_cntr->lc_count;
664 t.lc_sum = percpu_cntr->lc_sum;
665 t.lc_min = percpu_cntr->lc_min;
666 t.lc_max = percpu_cntr->lc_max;
667 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
668 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
669 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
670 cnt->lc_count += t.lc_count;
671 cnt->lc_sum += t.lc_sum;
672 if (t.lc_min < cnt->lc_min)
673 cnt->lc_min = t.lc_min;
674 if (t.lc_max > cnt->lc_max)
675 cnt->lc_max = t.lc_max;
676 cnt->lc_sumsquare += t.lc_sumsquare;
679 cnt->lc_units = stats->ls_percpu[0]->lp_cntr[idx].lc_units;
683 * Append a space separated list of current set flags to str.
685 #define flag2str(flag) \
686 if (imp->imp_##flag && max - len > 0) \
687 len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
688 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
692 if (imp->imp_obd->obd_no_recov)
693 len += snprintf(str, max - len, " no_recov");
697 flag2str(replayable);
700 flag2str(last_recon);
705 static const char *obd_connect_names[] = {
732 "mds_mds_connection",
735 "alt_checksum_algorithm",
744 static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
749 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
751 ret += snprintf(page + ret, count - ret, "%s%s",
752 ret ? sep : "", obd_connect_names[i]);
754 if (flags & ~(mask - 1))
755 ret += snprintf(page + ret, count - ret,
756 "%sunknown flags "LPX64,
757 ret ? sep : "", flags & ~(mask - 1));
761 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
762 int *eof, void *data)
764 struct lprocfs_counter ret;
765 struct obd_device *obd = (struct obd_device *)data;
766 struct obd_import *imp;
769 LASSERT(obd != NULL);
770 LPROCFS_CLIMP_CHECK(obd);
771 imp = obd->u.cli.cl_import;
774 i = snprintf(page, count,
778 " current_connection: %s\n"
783 imp->imp_connection->c_remote_uuid.uuid,
784 ptlrpc_import_state_name(imp->imp_state));
785 i += obd_connect_flags2str(page + i, count - i,
786 imp->imp_connect_data.ocd_connect_flags,
788 i += snprintf(page + i, count - i,
791 i += obd_import_flags2str(imp, page + i, count - i);
793 i += snprintf(page + i, count - i,
796 " connection_attempts: %u\n"
798 " in-progress_invalidations: %u\n",
801 atomic_read(&imp->imp_inval_count));
803 lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
804 do_div(ret.lc_sum, ret.lc_count);
805 i += snprintf(page + i, count - i,
808 " unregistering: %u\n"
810 " avg_waittime: "LPU64" %s\n",
811 atomic_read(&imp->imp_inflight),
812 atomic_read(&imp->imp_unregistering),
813 atomic_read(&imp->imp_timeouts),
814 ret.lc_sum, ret.lc_units);
817 for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
818 if (imp->imp_at.iat_portal[j] == 0)
820 k = max_t(unsigned int, k,
821 at_get(&imp->imp_at.iat_service_estimate[j]));
823 i += snprintf(page + i, count - i,
824 " service_estimates:\n"
825 " services: %u sec\n"
826 " network: %u sec\n",
828 at_get(&imp->imp_at.iat_net_latency));
830 i += snprintf(page + i, count - i,
832 " last_replay: "LPU64"\n"
833 " peer_committed: "LPU64"\n"
834 " last_checked: "LPU64"\n",
835 imp->imp_last_replay_transno,
836 imp->imp_peer_committed_transno,
837 imp->imp_last_transno_checked);
840 for (rw = 0; rw <= 1; rw++) {
841 lprocfs_stats_collect(obd->obd_svc_stats,
842 PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
844 if (ret.lc_sum > 0) {
845 do_div(ret.lc_sum, ret.lc_count);
846 i += snprintf(page + i, count - i,
847 " %s_data_averages:\n"
848 " bytes_per_rpc: "LPU64"\n",
849 rw ? "write" : "read",
853 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
854 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
855 if (ret.lc_sum > 0) {
856 do_div(ret.lc_sum, ret.lc_count);
857 i += snprintf(page + i, count - i,
858 " %s_per_rpc: "LPU64"\n",
859 ret.lc_units, ret.lc_sum);
862 i += snprintf(page + i, count - i,
863 " MB_per_sec: %u.%.02u\n",
864 k / j, (100 * k / j) % 100);
868 LPROCFS_CLIMP_EXIT(obd);
872 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
873 int *eof, void *data)
875 struct obd_device *obd = (struct obd_device *)data;
876 struct obd_import *imp;
879 LASSERT(obd != NULL);
880 LPROCFS_CLIMP_CHECK(obd);
881 imp = obd->u.cli.cl_import;
884 i = snprintf(page, count, "current_state: %s\n",
885 ptlrpc_import_state_name(imp->imp_state));
886 i += snprintf(page + i, count - i,
888 k = imp->imp_state_hist_idx;
889 for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
890 struct import_state_hist *ish =
891 &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
892 if (ish->ish_state == 0)
894 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
896 ptlrpc_import_state_name(ish->ish_state));
899 LPROCFS_CLIMP_EXIT(obd);
903 int lprocfs_at_hist_helper(char *page, int count, int rc,
904 struct adaptive_timeout *at)
907 for (i = 0; i < AT_BINS; i++)
908 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
909 rc += snprintf(page + rc, count - rc, "\n");
913 int lprocfs_rd_quota_resend_count(char *page, char **start, off_t off,
914 int count, int *eof, void *data)
916 struct obd_device *obd = data;
918 return snprintf(page, count, "%u\n",
919 atomic_read(&obd->u.cli.cl_quota_resends));
922 int lprocfs_wr_quota_resend_count(struct file *file, const char *buffer,
923 unsigned long count, void *data)
925 struct obd_device *obd = data;
928 rc = lprocfs_write_helper(buffer, count, &val);
935 atomic_set(&obd->u.cli.cl_quota_resends, val);
940 /* See also ptlrpc_lprocfs_rd_timeouts */
941 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
942 int *eof, void *data)
944 struct obd_device *obd = (struct obd_device *)data;
945 struct obd_import *imp;
946 unsigned int cur, worst;
951 LASSERT(obd != NULL);
952 LPROCFS_CLIMP_CHECK(obd);
953 imp = obd->u.cli.cl_import;
956 now = cfs_time_current_sec();
958 /* Some network health info for kicks */
959 s2dhms(&ts, now - imp->imp_last_reply_time);
960 rc += snprintf(page + rc, count - rc,
961 "%-10s : %ld, "DHMS_FMT" ago\n",
962 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
964 cur = at_get(&imp->imp_at.iat_net_latency);
965 worst = imp->imp_at.iat_net_latency.at_worst_ever;
966 worstt = imp->imp_at.iat_net_latency.at_worst_time;
967 s2dhms(&ts, now - worstt);
968 rc += snprintf(page + rc, count - rc,
969 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
970 "network", cur, worst, worstt, DHMS_VARS(&ts));
971 rc = lprocfs_at_hist_helper(page, count, rc,
972 &imp->imp_at.iat_net_latency);
974 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
975 if (imp->imp_at.iat_portal[i] == 0)
977 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
978 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
979 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
980 s2dhms(&ts, now - worstt);
981 rc += snprintf(page + rc, count - rc,
982 "portal %-2d : cur %3u worst %3u (at %ld, "
983 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
984 cur, worst, worstt, DHMS_VARS(&ts));
985 rc = lprocfs_at_hist_helper(page, count, rc,
986 &imp->imp_at.iat_service_estimate[i]);
989 LPROCFS_CLIMP_EXIT(obd);
993 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
994 int count, int *eof, void *data)
996 struct obd_device *obd = data;
1000 LPROCFS_CLIMP_CHECK(obd);
1001 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1002 ret = snprintf(page, count, "flags="LPX64"\n", flags);
1003 ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1004 ret += snprintf(page + ret, count - ret, "\n");
1005 LPROCFS_CLIMP_EXIT(obd);
1008 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1010 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1011 int *eof, void *data)
1013 struct obd_device *obd = (struct obd_device*)data;
1015 LASSERT(obd != NULL);
1017 return snprintf(page, count, "%u\n", obd->obd_num_exports);
1020 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1021 int *eof, void *data)
1023 struct obd_type *class = (struct obd_type*) data;
1025 LASSERT(class != NULL);
1027 return snprintf(page, count, "%d\n", class->typ_refcnt);
1030 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1034 LASSERT(obd != NULL);
1035 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1036 LASSERT(obd->obd_type->typ_procroot != NULL);
1038 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1039 obd->obd_type->typ_procroot,
1041 if (IS_ERR(obd->obd_proc_entry)) {
1042 rc = PTR_ERR(obd->obd_proc_entry);
1043 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1044 obd->obd_proc_entry = NULL;
1049 int lprocfs_obd_cleanup(struct obd_device *obd)
1053 if (obd->obd_proc_exports_entry) {
1054 /* Should be no exports left */
1055 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1056 lprocfs_remove(&obd->obd_proc_exports_entry);
1058 lprocfs_remove(&obd->obd_proc_entry);
1062 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1064 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1065 client_stat->nid_proc, client_stat->nid_stats,
1066 client_stat->nid_brw_stats);
1068 LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
1069 "count %d\n", atomic_read(&client_stat->nid_exp_ref_count));
1071 hlist_del_init(&client_stat->nid_hash);
1073 if (client_stat->nid_proc)
1074 lprocfs_remove(&client_stat->nid_proc);
1076 if (client_stat->nid_stats)
1077 lprocfs_free_stats(&client_stat->nid_stats);
1079 if (client_stat->nid_brw_stats)
1080 OBD_FREE_PTR(client_stat->nid_brw_stats);
1082 if (client_stat->nid_ldlm_stats)
1083 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1085 OBD_FREE_PTR(client_stat);
1090 void lprocfs_free_per_client_stats(struct obd_device *obd)
1092 struct nid_stat *stat;
1095 /* we need extra list - because hash_exit called to early */
1096 /* not need locking because all clients is died */
1097 while(!list_empty(&obd->obd_nid_stats)) {
1098 stat = list_entry(obd->obd_nid_stats.next,
1099 struct nid_stat, nid_list);
1100 list_del_init(&stat->nid_list);
1101 lprocfs_free_client_stats(stat);
1107 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1108 enum lprocfs_stats_flags flags)
1110 struct lprocfs_stats *stats;
1111 unsigned int percpusize;
1113 unsigned int num_cpu;
1118 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1121 num_cpu = num_possible_cpus();
1123 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1127 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
1128 stats->ls_flags = flags;
1129 spin_lock_init(&stats->ls_lock);
1130 /* Use this lock only if there are no percpu areas */
1132 stats->ls_flags = 0;
1135 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1137 percpusize = L1_CACHE_ALIGN(percpusize);
1139 for (i = 0; i < num_cpu; i++) {
1140 OBD_ALLOC(stats->ls_percpu[i], percpusize);
1141 if (stats->ls_percpu[i] == NULL) {
1142 for (j = 0; j < i; j++) {
1143 OBD_FREE(stats->ls_percpu[j], percpusize);
1144 stats->ls_percpu[j] = NULL;
1149 if (stats->ls_percpu[0] == NULL) {
1150 OBD_FREE(stats, offsetof(typeof(*stats),
1151 ls_percpu[num_cpu]));
1155 stats->ls_num = num;
1159 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1161 struct lprocfs_stats *stats = *statsh;
1162 unsigned int num_cpu;
1163 unsigned int percpusize;
1166 if (!stats || (stats->ls_num == 0))
1169 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1172 num_cpu = num_possible_cpus();
1174 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1176 percpusize = L1_CACHE_ALIGN(percpusize);
1177 for (i = 0; i < num_cpu; i++)
1178 OBD_FREE(stats->ls_percpu[i], percpusize);
1179 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1182 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1184 struct lprocfs_counter *percpu_cntr;
1186 unsigned int num_cpu;
1188 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1190 for (i = 0; i < num_cpu; i++) {
1191 for (j = 0; j < stats->ls_num; j++) {
1192 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1193 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1194 percpu_cntr->lc_count = 0;
1195 percpu_cntr->lc_sum = 0;
1196 percpu_cntr->lc_min = LC_MIN_INIT;
1197 percpu_cntr->lc_max = 0;
1198 percpu_cntr->lc_sumsquare = 0;
1199 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1203 lprocfs_stats_unlock(stats);
1206 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1207 size_t len, loff_t *off)
1209 struct seq_file *seq = file->private_data;
1210 struct lprocfs_stats *stats = seq->private;
1212 lprocfs_clear_stats(stats);
1217 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1219 struct lprocfs_stats *stats = p->private;
1220 /* return 1st cpu location */
1221 return (*pos >= stats->ls_num) ? NULL :
1222 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1225 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1229 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1231 struct lprocfs_stats *stats = p->private;
1233 return (*pos >= stats->ls_num) ? NULL :
1234 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1237 /* seq file export of one lprocfs counter */
1238 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1240 struct lprocfs_stats *stats = p->private;
1241 struct lprocfs_counter *cntr = v;
1242 struct lprocfs_counter ret;
1245 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1247 do_gettimeofday(&now);
1248 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1249 "snapshot_time", now.tv_sec, now.tv_usec);
1253 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1255 lprocfs_stats_collect(stats, idx, &ret);
1257 if (ret.lc_count == 0)
1260 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1261 ret.lc_count, cntr->lc_units);
1266 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1267 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1268 ret.lc_min, ret.lc_max, ret.lc_sum);
1271 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1272 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1276 rc = seq_printf(p, "\n");
1278 return (rc < 0) ? rc : 0;
1281 struct seq_operations lprocfs_stats_seq_sops = {
1282 start: lprocfs_stats_seq_start,
1283 stop: lprocfs_stats_seq_stop,
1284 next: lprocfs_stats_seq_next,
1285 show: lprocfs_stats_seq_show,
1288 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1290 struct proc_dir_entry *dp = PDE(inode);
1291 struct seq_file *seq;
1294 LPROCFS_ENTRY_AND_CHECK(dp);
1295 rc = seq_open(file, &lprocfs_stats_seq_sops);
1301 seq = file->private_data;
1302 seq->private = dp->data;
1306 struct file_operations lprocfs_stats_seq_fops = {
1307 .owner = THIS_MODULE,
1308 .open = lprocfs_stats_seq_open,
1310 .write = lprocfs_stats_seq_write,
1311 .llseek = seq_lseek,
1312 .release = lprocfs_seq_release,
1315 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1316 struct lprocfs_stats *stats)
1318 struct proc_dir_entry *entry;
1319 LASSERT(root != NULL);
1321 entry = create_proc_entry(name, 0644, root);
1324 entry->proc_fops = &lprocfs_stats_seq_fops;
1325 entry->data = (void *)stats;
1329 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1330 unsigned conf, const char *name, const char *units)
1332 struct lprocfs_counter *c;
1334 unsigned int num_cpu;
1336 LASSERT(stats != NULL);
1338 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1340 for (i = 0; i < num_cpu; i++) {
1341 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1342 c->lc_config = conf;
1345 c->lc_min = LC_MIN_INIT;
1348 c->lc_units = units;
1351 lprocfs_stats_unlock(stats);
1353 EXPORT_SYMBOL(lprocfs_counter_init);
1355 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1357 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1358 LASSERT(coffset < stats->ls_num); \
1359 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1362 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1364 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1365 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1366 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1367 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1368 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1369 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1370 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1371 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1372 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1373 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1374 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1375 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1376 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1377 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1378 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1379 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1380 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1381 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1382 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1383 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1384 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1385 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1386 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1387 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1388 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1389 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1390 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1391 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1392 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1393 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1394 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1395 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1396 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1397 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1398 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_lock);
1399 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1400 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1401 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1402 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1403 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1404 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1405 LPROCFS_OBD_OP_INIT(num_private_stats, stats, update_lvb);
1406 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1407 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1408 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1409 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1410 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1411 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1412 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1413 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1414 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1415 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1416 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1417 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1418 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1419 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1420 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1421 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1422 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1423 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1424 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1425 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1426 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1427 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1428 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1429 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1430 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1431 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1432 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1433 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1434 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1435 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1436 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1437 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1438 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1439 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1440 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1441 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1442 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1443 LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1446 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1448 lprocfs_counter_init(ldlm_stats,
1449 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1450 0, "ldlm_enqueue", "reqs");
1451 lprocfs_counter_init(ldlm_stats,
1452 LDLM_CONVERT - LDLM_FIRST_OPC,
1453 0, "ldlm_convert", "reqs");
1454 lprocfs_counter_init(ldlm_stats,
1455 LDLM_CANCEL - LDLM_FIRST_OPC,
1456 0, "ldlm_cancel", "reqs");
1457 lprocfs_counter_init(ldlm_stats,
1458 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1459 0, "ldlm_bl_callback", "reqs");
1460 lprocfs_counter_init(ldlm_stats,
1461 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1462 0, "ldlm_cp_callback", "reqs");
1463 lprocfs_counter_init(ldlm_stats,
1464 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1465 0, "ldlm_gl_callback", "reqs");
1468 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1470 struct lprocfs_stats *stats;
1471 unsigned int num_stats;
1474 LASSERT(obd->obd_stats == NULL);
1475 LASSERT(obd->obd_proc_entry != NULL);
1476 LASSERT(obd->obd_cntr_base == 0);
1478 num_stats = ((int)sizeof(*obd->obd_type->typ_ops) / sizeof(void *)) +
1479 num_private_stats - 1 /* o_owner */;
1480 stats = lprocfs_alloc_stats(num_stats, 0);
1484 lprocfs_init_ops_stats(num_private_stats, stats);
1486 for (i = num_private_stats; i < num_stats; i++) {
1487 /* If this LBUGs, it is likely that an obd
1488 * operation was added to struct obd_ops in
1489 * <obd.h>, and that the corresponding line item
1490 * LPROCFS_OBD_OP_INIT(.., .., opname)
1491 * is missing from the list above. */
1492 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1493 "Missing obd_stat initializer obd_op "
1494 "operation at offset %d.\n", i - num_private_stats);
1496 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1498 lprocfs_free_stats(&stats);
1500 obd->obd_stats = stats;
1501 obd->obd_cntr_base = num_private_stats;
1506 void lprocfs_free_obd_stats(struct obd_device *obd)
1509 lprocfs_free_stats(&obd->obd_stats);
1512 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1513 int *eof, void *data)
1515 struct obd_export *exp = (struct obd_export*)data;
1516 LASSERT(exp != NULL);
1518 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1521 struct exp_uuid_cb_data {
1529 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1530 int count, int *eof, int *len)
1532 cb_data->page = page;
1533 cb_data->count = count;
1538 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1540 struct obd_export *exp = (struct obd_export *)obj;
1541 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1543 if (exp->exp_nid_stats)
1544 *data->len += snprintf((data->page + *data->len),
1545 data->count, "%s\n",
1546 obd_uuid2str(&exp->exp_client_uuid));
1549 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1550 int *eof, void *data)
1552 struct nid_stat *stats = (struct nid_stat *)data;
1553 struct exp_uuid_cb_data cb_data;
1554 struct obd_device *obd = stats->nid_obd;
1559 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1560 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1561 lprocfs_exp_print_uuid, &cb_data);
1562 return (*cb_data.len);
1565 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1567 struct obd_export *exp = (struct obd_export *)obj;
1568 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1571 lh = exp->exp_lock_hash;
1574 *data->len += lustre_hash_debug_header(data->page,
1577 *data->len += lustre_hash_debug_str(lh, data->page +
1583 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1584 int *eof, void *data)
1586 struct nid_stat *stats = (struct nid_stat *)data;
1587 struct exp_uuid_cb_data cb_data;
1588 struct obd_device *obd = stats->nid_obd;
1593 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1594 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1595 lprocfs_exp_print_hash, &cb_data);
1596 return (*cb_data.len);
1599 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1600 int count, int *eof, void *data)
1603 return snprintf(page, count, "%s\n",
1604 "Write into this file to clear all nid stats and "
1605 "stale nid entries");
1607 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1609 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1611 struct nid_stat *stat = obj;
1614 /* object has only hash + iterate_all references.
1615 * add/delete blocked by hash bucket lock */
1616 CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
1617 if (atomic_read(&stat->nid_exp_ref_count) == 2) {
1618 hlist_del_init(&stat->nid_hash);
1619 nidstat_putref(stat);
1620 spin_lock(&stat->nid_obd->obd_nid_lock);
1621 list_move(&stat->nid_list, data);
1622 spin_unlock(&stat->nid_obd->obd_nid_lock);
1626 /* we has reference to object - only clear data*/
1627 if (stat->nid_stats)
1628 lprocfs_clear_stats(stat->nid_stats);
1630 if (stat->nid_brw_stats) {
1631 for (i = 0; i < BRW_LAST; i++)
1632 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1638 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1639 unsigned long count, void *data)
1641 struct obd_device *obd = (struct obd_device *)data;
1642 struct nid_stat *client_stat;
1643 CFS_LIST_HEAD(free_list);
1645 lustre_hash_for_each(obd->obd_nid_stats_hash,
1646 lprocfs_nid_stats_clear_write_cb, &free_list);
1648 while (!list_empty(&free_list)) {
1649 client_stat = list_entry(free_list.next, struct nid_stat,
1651 list_del_init(&client_stat->nid_list);
1652 lprocfs_free_client_stats(client_stat);
1657 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1659 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
1663 struct nid_stat *new_stat, *old_stat;
1664 struct obd_device *obd;
1665 cfs_proc_dir_entry_t *entry;
1666 char *buffer = NULL;
1671 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1672 !exp->exp_obd->obd_nid_stats_hash)
1675 /* not test against zero because eric say:
1676 * You may only test nid against another nid, or LNET_NID_ANY.
1677 * Anything else is nonsense.*/
1678 if (!nid || *nid == LNET_NID_ANY)
1683 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1685 OBD_ALLOC_PTR(new_stat);
1686 if (new_stat == NULL)
1689 new_stat->nid = *nid;
1690 new_stat->nid_obd = exp->exp_obd;
1691 /* we need set default refcount to 1 to balance obd_disconnect() */
1692 atomic_set(&new_stat->nid_exp_ref_count, 1);
1694 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1695 nid, &new_stat->nid_hash);
1696 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1697 old_stat, libcfs_nid2str(*nid),
1698 atomic_read(&new_stat->nid_exp_ref_count));
1700 /* Return -EALREADY here so that we know that the /proc
1701 * entry already has been created */
1702 if (old_stat != new_stat) {
1703 /* if this reconnect to live export from diffrent nid, we need
1704 * to release old stats because disconnect will be never called.
1706 if (reconnect && exp->exp_nid_stats)
1707 nidstat_putref(exp->exp_nid_stats);
1709 exp->exp_nid_stats = old_stat;
1710 GOTO(destroy_new, rc = -EALREADY);
1713 /* not found - create */
1714 OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1716 GOTO(destroy_new_ns, rc = -ENOMEM);
1718 memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1719 new_stat->nid_proc = proc_mkdir(buffer, obd->obd_proc_exports_entry);
1720 OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1722 if (!new_stat->nid_proc) {
1723 CERROR("Error making export directory for"
1724 " nid %s\n", libcfs_nid2str(*nid));
1725 GOTO(destroy_new_ns, rc = -ENOMEM);
1728 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1729 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1730 if (IS_ERR(entry)) {
1731 CWARN("Error adding the uuid file\n");
1732 rc = PTR_ERR(entry);
1733 GOTO(destroy_new_ns, rc);
1736 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1737 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1738 if (IS_ERR(entry)) {
1739 CWARN("Error adding the hash file\n");
1740 rc = PTR_ERR(entry);
1741 GOTO(destroy_new_ns, rc);
1744 exp->exp_nid_stats = new_stat;
1746 /* protect competitive add to list, not need locking on destroy */
1747 spin_lock(&obd->obd_nid_lock);
1748 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1749 spin_unlock(&obd->obd_nid_lock);
1754 if (new_stat->nid_proc != NULL)
1755 lprocfs_remove(&new_stat->nid_proc);
1756 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1759 nidstat_putref(new_stat);
1760 OBD_FREE_PTR(new_stat);
1764 int lprocfs_exp_cleanup(struct obd_export *exp)
1766 struct nid_stat *stat = exp->exp_nid_stats;
1768 if(!stat || !exp->exp_obd)
1771 nidstat_putref(exp->exp_nid_stats);
1772 exp->exp_nid_stats = NULL;
1773 lprocfs_free_stats(&exp->exp_ops_stats);
1778 int lprocfs_write_helper(const char *buffer, unsigned long count,
1781 return lprocfs_write_frac_helper(buffer, count, val, 1);
1784 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1787 char kernbuf[20], *end, *pbuf;
1789 if (count > (sizeof(kernbuf) - 1))
1792 if (copy_from_user(kernbuf, buffer, count))
1795 kernbuf[count] = '\0';
1802 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1806 if (end != NULL && *end == '.') {
1807 int temp_val, pow = 1;
1811 if (strlen(pbuf) > 5)
1812 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1814 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1817 for (i = 0; i < (end - pbuf); i++)
1820 *val += temp_val / pow;
1826 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1829 long decimal_val, frac_val;
1835 decimal_val = val / mult;
1836 prtn = snprintf(buffer, count, "%ld", decimal_val);
1837 frac_val = val % mult;
1839 if (prtn < (count - 4) && frac_val > 0) {
1841 int i, temp_mult = 1, frac_bits = 0;
1843 temp_frac = frac_val * 10;
1844 buffer[prtn++] = '.';
1845 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1846 /*only reserved 2bits fraction*/
1847 buffer[prtn++] ='0';
1852 Need to think these cases :
1853 1. #echo x.00 > /proc/xxx output result : x
1854 2. #echo x.0x > /proc/xxx output result : x.0x
1855 3. #echo x.x0 > /proc/xxx output result : x.x
1856 4. #echo x.xx > /proc/xxx output result : x.xx
1857 Only reserved 2bits fraction.
1859 for (i = 0; i < (5 - prtn); i++)
1862 frac_bits = min((int)count - prtn, 3 - frac_bits);
1863 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1866 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1868 if (buffer[prtn] == '.') {
1875 buffer[prtn++] ='\n';
1879 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1881 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1884 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1885 __u64 *val, int mult)
1887 char kernbuf[22], *end, *pbuf;
1888 __u64 whole, frac = 0, units;
1889 unsigned frac_d = 1;
1891 if (count > (sizeof(kernbuf) - 1))
1894 if (copy_from_user(kernbuf, buffer, count))
1897 kernbuf[count] = '\0';
1904 whole = simple_strtoull(pbuf, &end, 10);
1908 if (end != NULL && *end == '.') {
1912 /* need to limit frac_d to a __u32 */
1913 if (strlen(pbuf) > 10)
1916 frac = simple_strtoull(pbuf, &end, 10);
1917 /* count decimal places */
1918 for (i = 0; i < (end - pbuf); i++)
1935 /* Specified units override the multiplier */
1937 mult = mult < 0 ? -units : units;
1940 do_div(frac, frac_d);
1941 *val = whole * mult + frac;
1945 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1946 char *name, mode_t mode,
1947 struct file_operations *seq_fops, void *data)
1949 struct proc_dir_entry *entry;
1952 entry = create_proc_entry(name, mode, parent);
1955 entry->proc_fops = seq_fops;
1960 EXPORT_SYMBOL(lprocfs_seq_create);
1962 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1964 struct file_operations *seq_fops,
1967 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1968 mode, seq_fops, data));
1970 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1972 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1974 if (value >= OBD_HIST_MAX)
1975 value = OBD_HIST_MAX - 1;
1977 spin_lock(&oh->oh_lock);
1978 oh->oh_buckets[value]++;
1979 spin_unlock(&oh->oh_lock);
1981 EXPORT_SYMBOL(lprocfs_oh_tally);
1983 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1987 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1990 lprocfs_oh_tally(oh, val);
1992 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1994 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1996 unsigned long ret = 0;
1999 for (i = 0; i < OBD_HIST_MAX; i++)
2000 ret += oh->oh_buckets[i];
2003 EXPORT_SYMBOL(lprocfs_oh_sum);
2005 void lprocfs_oh_clear(struct obd_histogram *oh)
2007 spin_lock(&oh->oh_lock);
2008 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2009 spin_unlock(&oh->oh_lock);
2011 EXPORT_SYMBOL(lprocfs_oh_clear);
2013 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2014 int count, int *eof, void *data)
2016 struct obd_device *obd = data;
2019 LASSERT(obd != NULL);
2020 LASSERT(count >= 0);
2022 /* Set start of user data returned to
2023 page + off since the user may have
2024 requested to read much smaller than
2025 what we need to read */
2026 *start = page + off;
2028 /* We know we are allocated a page here.
2029 Also we know that this function will
2030 not need to write more than a page
2031 so we can truncate at CFS_PAGE_SIZE. */
2032 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2034 /* Initialize the page */
2035 memset(page, 0, size);
2037 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2039 if (obd->obd_max_recoverable_clients == 0) {
2040 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2046 /* sampled unlocked, but really... */
2047 if (obd->obd_recovering == 0) {
2048 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2050 if (lprocfs_obd_snprintf(&page, size, &len,
2051 "recovery_start: %lu\n",
2052 obd->obd_recovery_start) <= 0)
2054 if (lprocfs_obd_snprintf(&page, size, &len,
2055 "recovery_duration: %lu\n",
2056 obd->obd_recovery_end -
2057 obd->obd_recovery_start) <= 0)
2059 if (lprocfs_obd_snprintf(&page, size, &len,
2060 "delayed_clients: %d/%d\n",
2061 obd->obd_delayed_clients,
2062 obd->obd_max_recoverable_clients) <= 0)
2064 /* Number of clients that have completed recovery */
2065 if (lprocfs_obd_snprintf(&page, size, &len,
2066 "completed_clients: %d/%d\n",
2067 obd->obd_max_recoverable_clients -
2068 obd->obd_recoverable_clients -
2069 obd->obd_delayed_clients -
2070 obd->obd_stale_clients,
2071 obd->obd_max_recoverable_clients) <= 0)
2073 if (lprocfs_obd_snprintf(&page, size, &len,
2074 "replayed_requests: %d\n",
2075 obd->obd_replayed_requests) <= 0)
2077 if (lprocfs_obd_snprintf(&page, size, &len,
2078 "last_transno: "LPD64"\n",
2079 obd->obd_next_recovery_transno - 1)<=0)
2084 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2086 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2087 obd->obd_recovery_start) <= 0)
2089 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2090 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2091 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2093 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2094 obd->obd_connected_clients,
2095 obd->obd_max_recoverable_clients) <= 0)
2097 if (lprocfs_obd_snprintf(&page, size, &len,"delayed_clients: %d/%d\n",
2098 obd->obd_delayed_clients,
2099 obd->obd_max_recoverable_clients) <= 0)
2101 /* Number of clients that have completed recovery */
2102 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2103 obd->obd_max_recoverable_clients -
2104 obd->obd_recoverable_clients -
2105 obd->obd_delayed_clients,
2106 obd->obd_max_recoverable_clients) <= 0)
2108 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2109 obd->obd_replayed_requests) <= 0)
2111 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2112 obd->obd_requests_queued_for_recovery) <= 0)
2114 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2115 obd->obd_next_recovery_transno) <= 0)
2121 return min(count, len - (int)off);
2123 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2125 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2126 int count, int *eof, void *data)
2128 struct obd_device *obd = data;
2134 c += lustre_hash_debug_header(page, count);
2135 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2136 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2137 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2141 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2143 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2144 int count, int *eof, void *data)
2146 struct obd_device *obd = (struct obd_device *)data;
2147 LASSERT(obd != NULL);
2149 return snprintf(page, count, "%d\n",
2150 obd->obd_recovery_timeout);
2152 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2154 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2155 unsigned long count, void *data)
2157 struct obd_device *obd = (struct obd_device *)data;
2159 LASSERT(obd != NULL);
2161 rc = lprocfs_write_helper(buffer, count, &val);
2165 obd->obd_recovery_timeout = val;
2168 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2170 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2171 int count, int *eof, void *data)
2173 struct obd_device *obd = (struct obd_device *)data;
2174 LASSERT(obd != NULL);
2176 return snprintf(page, count, "%lu\n",
2177 obd->obd_recovery_time_hard);
2179 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2181 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2182 unsigned long count, void *data)
2184 struct obd_device *obd = (struct obd_device *)data;
2186 LASSERT(obd != NULL);
2188 rc = lprocfs_write_helper(buffer, count, &val);
2192 obd->obd_recovery_time_hard = val;
2195 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2197 #ifdef HAVE_DELAYED_RECOVERY
2198 int lprocfs_obd_rd_stale_export_age(char *page, char **start, off_t off,
2199 int count, int *eof, void *data)
2201 struct obd_device *obd = (struct obd_device *)data;
2202 LASSERT(obd != NULL);
2204 return snprintf(page, count, "%u\n",
2205 obd->u.obt.obt_stale_export_age);
2207 EXPORT_SYMBOL(lprocfs_obd_rd_stale_export_age);
2209 int lprocfs_obd_wr_stale_export_age(struct file *file, const char *buffer,
2210 unsigned long count, void *data)
2212 struct obd_device *obd = (struct obd_device *)data;
2214 LASSERT(obd != NULL);
2216 rc = lprocfs_write_helper(buffer, count, &val);
2220 target_trans_table_recalc(obd, val);
2221 obd->u.obt.obt_stale_export_age = val;
2224 EXPORT_SYMBOL(lprocfs_obd_wr_stale_export_age);
2226 static int obd_stale_exports_seq_show(struct seq_file *seq, void *v)
2228 struct obd_device *obd = seq->private;
2229 struct obd_export *exp;
2231 spin_lock(&obd->obd_dev_lock);
2232 list_for_each_entry(exp, &obd->obd_delayed_exports,
2234 seq_printf(seq, "%s: %ld seconds ago%s\n",
2235 obd_uuid2str(&exp->exp_client_uuid),
2236 cfs_time_current_sec() - exp->exp_last_request_time,
2237 exp_expired(exp, obd->u.obt.obt_stale_export_age) ?
2240 spin_unlock(&obd->obd_dev_lock);
2244 LPROC_SEQ_FOPS_RO(obd_stale_exports);
2246 int lprocfs_obd_attach_stale_exports(struct obd_device *dev)
2248 return lprocfs_obd_seq_create(dev, "stale_exports", 0444,
2249 &obd_stale_exports_fops, dev);
2251 EXPORT_SYMBOL(lprocfs_obd_attach_stale_exports);
2253 int lprocfs_obd_wr_flush_stale_exports(struct file *file, const char *buffer,
2254 unsigned long count, void *data)
2256 struct obd_device *obd = (struct obd_device *)data;
2258 LASSERT(obd != NULL);
2260 rc = lprocfs_write_helper(buffer, count, &val);
2264 class_disconnect_expired_exports(obd);
2267 EXPORT_SYMBOL(lprocfs_obd_wr_flush_stale_exports);
2270 EXPORT_SYMBOL(lprocfs_register);
2271 EXPORT_SYMBOL(lprocfs_srch);
2272 EXPORT_SYMBOL(lprocfs_remove);
2273 EXPORT_SYMBOL(lprocfs_add_vars);
2274 EXPORT_SYMBOL(lprocfs_obd_setup);
2275 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2276 EXPORT_SYMBOL(lprocfs_add_simple);
2277 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2278 EXPORT_SYMBOL(lprocfs_alloc_stats);
2279 EXPORT_SYMBOL(lprocfs_free_stats);
2280 EXPORT_SYMBOL(lprocfs_clear_stats);
2281 EXPORT_SYMBOL(lprocfs_register_stats);
2282 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2283 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2284 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2285 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2286 EXPORT_SYMBOL(lprocfs_exp_setup);
2287 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2289 EXPORT_SYMBOL(lprocfs_rd_u64);
2290 EXPORT_SYMBOL(lprocfs_rd_atomic);
2291 EXPORT_SYMBOL(lprocfs_wr_atomic);
2292 EXPORT_SYMBOL(lprocfs_rd_uint);
2293 EXPORT_SYMBOL(lprocfs_wr_uint);
2294 EXPORT_SYMBOL(lprocfs_rd_uuid);
2295 EXPORT_SYMBOL(lprocfs_rd_name);
2296 EXPORT_SYMBOL(lprocfs_rd_fstype);
2297 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2298 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2299 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2300 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2301 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2302 EXPORT_SYMBOL(lprocfs_rd_import);
2303 EXPORT_SYMBOL(lprocfs_rd_state);
2304 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2305 EXPORT_SYMBOL(lprocfs_rd_blksize);
2306 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2307 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2308 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2309 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2310 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2311 EXPORT_SYMBOL(lprocfs_rd_quota_resend_count);
2312 EXPORT_SYMBOL(lprocfs_wr_quota_resend_count);
2314 EXPORT_SYMBOL(lprocfs_write_helper);
2315 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2316 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2317 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2318 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2319 EXPORT_SYMBOL(lprocfs_stats_collect);