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 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
115 read_proc_t *read_proc, write_proc_t *write_proc,
118 struct proc_dir_entry *proc;
121 if (root == NULL || name == NULL)
127 proc = create_proc_entry(name, mode, root);
129 CERROR("LprocFS: No memory to create /proc entry %s", name);
132 proc->read_proc = read_proc;
133 proc->write_proc = write_proc;
138 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
139 struct proc_dir_entry *parent, const char *dest)
141 struct proc_dir_entry *entry;
143 if (parent == NULL || dest == NULL)
146 entry = proc_symlink(name, parent, dest);
148 CERROR("LprocFS: Could not create symbolic link from %s to %s",
153 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
154 size_t size, loff_t *ppos)
156 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
157 char *page, *start = NULL;
158 int rc = 0, eof = 1, count;
160 if (*ppos >= CFS_PAGE_SIZE)
163 page = (char *)__get_free_page(GFP_KERNEL);
168 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
169 if (!dp->deleted && dp->read_proc)
170 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
176 /* for lustre proc read, the read count must be less than PAGE_SIZE */
185 start = page + *ppos;
186 } else if (start < page) {
190 count = (rc < size) ? rc : size;
191 if (copy_to_user(buf, start, count)) {
198 free_page((unsigned long)page);
202 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
204 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
208 if (!dp->deleted && dp->write_proc)
209 rc = dp->write_proc(f, buf, size, dp->data);
214 static struct file_operations lprocfs_generic_fops = {
215 .owner = THIS_MODULE,
216 .read = lprocfs_fops_read,
217 .write = lprocfs_fops_write,
220 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
222 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
223 struct obd_device *obd = dp->data;
225 atomic_inc(&obd->obd_evict_inprogress);
230 int lprocfs_evict_client_release(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_dec(&obd->obd_evict_inprogress);
236 wake_up(&obd->obd_evict_inprogress_waitq);
241 struct file_operations lprocfs_evict_client_fops = {
242 .owner = THIS_MODULE,
243 .read = lprocfs_fops_read,
244 .write = lprocfs_fops_write,
245 .open = lprocfs_evict_client_open,
246 .release = lprocfs_evict_client_release,
248 EXPORT_SYMBOL(lprocfs_evict_client_fops);
250 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
253 if (root == NULL || list == NULL)
256 while (list->name != NULL) {
257 struct proc_dir_entry *cur_root, *proc;
258 char *pathcopy, *cur, *next, pathbuf[64];
259 int pathsize = strlen(list->name) + 1;
264 /* need copy of path for strsep */
265 if (strlen(list->name) > sizeof(pathbuf) - 1) {
266 OBD_ALLOC(pathcopy, pathsize);
267 if (pathcopy == NULL)
274 strcpy(pathcopy, list->name);
276 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
277 if (*cur =='\0') /* skip double/trailing "/" */
280 proc = lprocfs_srch(cur_root, cur);
281 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
282 cur_root->name, cur, next,
283 (proc ? "exists" : "new"));
285 cur_root = (proc ? proc :
286 proc_mkdir(cur, cur_root));
287 } else if (proc == NULL) {
291 if (list->write_fptr)
293 proc = create_proc_entry(cur, mode, cur_root);
297 if (pathcopy != pathbuf)
298 OBD_FREE(pathcopy, pathsize);
300 if (cur_root == NULL || proc == NULL) {
301 CERROR("LprocFS: No memory to create /proc entry %s",
307 proc->proc_fops = list->fops;
309 proc->proc_fops = &lprocfs_generic_fops;
310 proc->read_proc = list->read_fptr;
311 proc->write_proc = list->write_fptr;
312 proc->data = (list->data ? list->data : data);
318 void lprocfs_remove(struct proc_dir_entry **rooth)
320 struct proc_dir_entry *root = *rooth;
321 struct proc_dir_entry *temp = root;
322 struct proc_dir_entry *rm_entry;
323 struct proc_dir_entry *parent;
329 parent = root->parent;
330 LASSERT(parent != NULL);
331 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
334 while (temp->subdir != NULL)
340 /* Memory corruption once caused this to fail, and
341 without this LASSERT we would loop here forever. */
342 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
343 "0x%p %s/%s len %d\n", rm_entry, temp->name,
344 rm_entry->name, (int)strlen(rm_entry->name));
346 /* Now, the rm_entry->deleted flags is protected
347 * by _lprocfs_lock. */
348 rm_entry->data = NULL;
349 remove_proc_entry(rm_entry->name, temp);
353 LPROCFS_WRITE_EXIT();
356 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
358 LASSERT(parent != NULL);
359 remove_proc_entry(name, parent);
362 struct proc_dir_entry *lprocfs_register(const char *name,
363 struct proc_dir_entry *parent,
364 struct lprocfs_vars *list, void *data)
366 struct proc_dir_entry *newchild;
368 newchild = lprocfs_srch(parent, name);
369 if (newchild != NULL) {
370 CERROR(" Lproc: Attempting to register %s more than once \n",
372 return ERR_PTR(-EALREADY);
375 newchild = proc_mkdir(name, parent);
376 if (newchild != NULL && list != NULL) {
377 int rc = lprocfs_add_vars(newchild, list, data);
379 lprocfs_remove(&newchild);
386 /* Generic callbacks */
387 int lprocfs_rd_uint(char *page, char **start, off_t off,
388 int count, int *eof, void *data)
390 unsigned int *temp = (unsigned int *)data;
391 return snprintf(page, count, "%u\n", *temp);
394 int lprocfs_wr_uint(struct file *file, const char *buffer,
395 unsigned long count, void *data)
398 char dummy[MAX_STRING_SIZE + 1], *end;
401 dummy[MAX_STRING_SIZE] = '\0';
402 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
405 tmp = simple_strtoul(dummy, &end, 0);
409 *p = (unsigned int)tmp;
413 int lprocfs_rd_u64(char *page, char **start, off_t off,
414 int count, int *eof, void *data)
416 LASSERT(data != NULL);
418 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
421 int lprocfs_rd_atomic(char *page, char **start, off_t off,
422 int count, int *eof, void *data)
424 atomic_t *atom = (atomic_t *)data;
425 LASSERT(atom != NULL);
427 return snprintf(page, count, "%d\n", atomic_read(atom));
430 int lprocfs_wr_atomic(struct file *file, const char *buffer,
431 unsigned long count, void *data)
433 atomic_t *atm = data;
437 rc = lprocfs_write_helper(buffer, count, &val);
444 atomic_set(atm, val);
448 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
449 int *eof, void *data)
451 struct obd_device *obd = (struct obd_device*)data;
453 LASSERT(obd != NULL);
455 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
458 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
459 int *eof, void* data)
461 struct obd_device *dev = (struct obd_device *)data;
463 LASSERT(dev != NULL);
464 LASSERT(dev->obd_name != NULL);
466 return snprintf(page, count, "%s\n", dev->obd_name);
469 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
472 struct obd_device *obd = (struct obd_device *)data;
474 LASSERT(obd != NULL);
475 LASSERT(obd->obd_fsops != NULL);
476 LASSERT(obd->obd_fsops->fs_type != NULL);
477 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
480 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
481 int *eof, void *data)
483 struct obd_statfs osfs;
484 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
488 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
493 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
494 int *eof, void *data)
496 struct obd_statfs osfs;
497 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
500 __u32 blk_size = osfs.os_bsize >> 10;
501 __u64 result = osfs.os_blocks;
503 while (blk_size >>= 1)
507 rc = snprintf(page, count, LPU64"\n", result);
512 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
513 int *eof, void *data)
515 struct obd_statfs osfs;
516 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
519 __u32 blk_size = osfs.os_bsize >> 10;
520 __u64 result = osfs.os_bfree;
522 while (blk_size >>= 1)
526 rc = snprintf(page, count, LPU64"\n", result);
531 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
532 int *eof, void *data)
534 struct obd_statfs osfs;
535 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
538 __u32 blk_size = osfs.os_bsize >> 10;
539 __u64 result = osfs.os_bavail;
541 while (blk_size >>= 1)
545 rc = snprintf(page, count, LPU64"\n", result);
550 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
551 int *eof, void *data)
553 struct obd_statfs osfs;
554 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
558 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
564 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
565 int *eof, void *data)
567 struct obd_statfs osfs;
568 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
572 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
577 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
578 int *eof, void *data)
580 struct obd_device *obd = (struct obd_device *)data;
581 struct obd_import *imp;
582 char *imp_state_name = NULL;
585 LASSERT(obd != NULL);
586 LPROCFS_CLIMP_CHECK(obd);
587 imp = obd->u.cli.cl_import;
588 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
590 rc = snprintf(page, count, "%s\t%s%s\n",
591 obd2cli_tgt(obd), imp_state_name,
592 imp->imp_deactive ? "\tDEACTIVATED" : "");
594 LPROCFS_CLIMP_EXIT(obd);
598 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
599 int *eof, void *data)
601 struct obd_device *obd = (struct obd_device*)data;
602 struct ptlrpc_connection *conn;
605 LASSERT(obd != NULL);
607 LPROCFS_CLIMP_CHECK(obd);
608 conn = obd->u.cli.cl_import->imp_connection;
609 LASSERT(conn != NULL);
611 if (obd->u.cli.cl_import) {
612 rc = snprintf(page, count, "%s\n",
613 conn->c_remote_uuid.uuid);
615 rc = snprintf(page, count, "%s\n", "<none>");
618 LPROCFS_CLIMP_EXIT(obd);
622 int lprocfs_at_hist_helper(char *page, int count, int rc,
623 struct adaptive_timeout *at)
626 for (i = 0; i < AT_BINS; i++)
627 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
628 rc += snprintf(page + rc, count - rc, "\n");
632 /* See also ptlrpc_lprocfs_rd_timeouts */
633 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
634 int *eof, void *data)
636 struct obd_device *obd = (struct obd_device *)data;
637 struct obd_import *imp;
638 unsigned int cur, worst;
643 LASSERT(obd != NULL);
644 LPROCFS_CLIMP_CHECK(obd);
645 imp = obd->u.cli.cl_import;
648 now = cfs_time_current_sec();
650 /* Some network health info for kicks */
651 s2dhms(&ts, now - imp->imp_last_reply_time);
652 rc += snprintf(page + rc, count - rc,
653 "%-10s : %ld, "DHMS_FMT" ago\n",
654 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
657 cur = at_get(&imp->imp_at.iat_net_latency);
658 worst = imp->imp_at.iat_net_latency.at_worst_ever;
659 worstt = imp->imp_at.iat_net_latency.at_worst_time;
660 s2dhms(&ts, now - worstt);
661 rc += snprintf(page + rc, count - rc,
662 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
663 "network", cur, worst, worstt, DHMS_VARS(&ts));
664 rc = lprocfs_at_hist_helper(page, count, rc,
665 &imp->imp_at.iat_net_latency);
667 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
668 if (imp->imp_at.iat_portal[i] == 0)
670 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
671 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
672 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
673 s2dhms(&ts, now - worstt);
674 rc += snprintf(page + rc, count - rc,
675 "portal %-2d : cur %3u worst %3u (at %ld, "
676 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
677 cur, worst, worstt, DHMS_VARS(&ts));
678 rc = lprocfs_at_hist_helper(page, count, rc,
679 &imp->imp_at.iat_service_estimate[i]);
682 LPROCFS_CLIMP_EXIT(obd);
686 static const char *obd_connect_names[] = {
713 "mds_mds_connection",
716 "alt_checksum_algorithm",
721 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
722 int count, int *eof, void *data)
724 struct obd_device *obd = data;
725 __u64 mask = 1, flags;
728 LPROCFS_CLIMP_CHECK(obd);
729 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
730 ret = snprintf(page, count, "flags="LPX64"\n", flags);
731 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
733 ret += snprintf(page + ret, count - ret, "%s\n",
734 obd_connect_names[i]);
736 if (flags & ~(mask - 1))
737 ret += snprintf(page + ret, count - ret,
738 "unknown flags "LPX64"\n", flags & ~(mask - 1));
740 LPROCFS_CLIMP_EXIT(obd);
743 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
745 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
746 int *eof, void *data)
748 struct obd_device *obd = (struct obd_device*)data;
750 LASSERT(obd != NULL);
752 return snprintf(page, count, "%u\n", obd->obd_num_exports);
755 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
756 int *eof, void *data)
758 struct obd_type *class = (struct obd_type*) data;
760 LASSERT(class != NULL);
762 return snprintf(page, count, "%d\n", class->typ_refcnt);
765 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
769 LASSERT(obd != NULL);
770 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
771 LASSERT(obd->obd_type->typ_procroot != NULL);
773 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
774 obd->obd_type->typ_procroot,
776 if (IS_ERR(obd->obd_proc_entry)) {
777 rc = PTR_ERR(obd->obd_proc_entry);
778 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
779 obd->obd_proc_entry = NULL;
784 int lprocfs_obd_cleanup(struct obd_device *obd)
788 if (obd->obd_proc_exports_entry) {
789 /* Should be no exports left */
790 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
791 lprocfs_remove(&obd->obd_proc_exports_entry);
793 lprocfs_remove(&obd->obd_proc_entry);
797 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
799 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
800 client_stat->nid_proc, client_stat->nid_stats,
801 client_stat->nid_brw_stats);
803 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
804 client_stat->nid_exp_ref_count);
806 hlist_del_init(&client_stat->nid_hash);
808 if (client_stat->nid_proc)
809 lprocfs_remove(&client_stat->nid_proc);
811 if (client_stat->nid_stats)
812 lprocfs_free_stats(&client_stat->nid_stats);
814 if (client_stat->nid_brw_stats)
815 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
817 OBD_FREE(client_stat, sizeof(*client_stat));
822 void lprocfs_free_per_client_stats(struct obd_device *obd)
824 struct nid_stat *stat;
827 /* we need extra list - because hash_exit called to early */
828 /* not need locking because all clients is died */
829 while(!list_empty(&obd->obd_nid_stats)) {
830 stat = list_entry(obd->obd_nid_stats.next,
831 struct nid_stat, nid_list);
832 list_del_init(&stat->nid_list);
833 lprocfs_free_client_stats(stat);
839 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
840 enum lprocfs_stats_flags flags)
842 struct lprocfs_stats *stats;
843 unsigned int percpusize;
845 unsigned int num_cpu;
850 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
853 num_cpu = num_possible_cpus();
855 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
859 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
860 stats->ls_flags = flags;
861 spin_lock_init(&stats->ls_lock);
862 /* Use this lock only if there are no percpu areas */
867 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
869 percpusize = L1_CACHE_ALIGN(percpusize);
871 for (i = 0; i < num_cpu; i++) {
872 OBD_ALLOC(stats->ls_percpu[i], percpusize);
873 if (stats->ls_percpu[i] == NULL) {
874 for (j = 0; j < i; j++) {
875 OBD_FREE(stats->ls_percpu[j], percpusize);
876 stats->ls_percpu[j] = NULL;
881 if (stats->ls_percpu[0] == NULL) {
882 OBD_FREE(stats, offsetof(typeof(*stats),
883 ls_percpu[num_cpu]));
891 void lprocfs_free_stats(struct lprocfs_stats **statsh)
893 struct lprocfs_stats *stats = *statsh;
894 unsigned int num_cpu;
895 unsigned int percpusize;
898 if (stats == NULL || stats->ls_num == 0)
902 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
905 num_cpu = num_possible_cpus();
907 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
909 percpusize = L1_CACHE_ALIGN(percpusize);
910 for (i = 0; i < num_cpu; i++)
911 OBD_FREE(stats->ls_percpu[i], percpusize);
912 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
915 void lprocfs_clear_stats(struct lprocfs_stats *stats)
917 struct lprocfs_counter *percpu_cntr;
919 unsigned int num_cpu;
921 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
923 for (i = 0; i < num_cpu; i++) {
924 for (j = 0; j < stats->ls_num; j++) {
925 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
926 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
927 percpu_cntr->lc_count = 0;
928 percpu_cntr->lc_sum = 0;
929 percpu_cntr->lc_min = LC_MIN_INIT;
930 percpu_cntr->lc_max = 0;
931 percpu_cntr->lc_sumsquare = 0;
932 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
936 lprocfs_stats_unlock(stats);
939 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
940 size_t len, loff_t *off)
942 struct seq_file *seq = file->private_data;
943 struct lprocfs_stats *stats = seq->private;
945 lprocfs_clear_stats(stats);
950 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
952 struct lprocfs_stats *stats = p->private;
953 /* return 1st cpu location */
954 return (*pos >= stats->ls_num) ? NULL :
955 &(stats->ls_percpu[0]->lp_cntr[*pos]);
958 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
962 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
964 struct lprocfs_stats *stats = p->private;
966 return (*pos >= stats->ls_num) ? NULL :
967 &(stats->ls_percpu[0]->lp_cntr[*pos]);
970 /* seq file export of one lprocfs counter */
971 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
973 struct lprocfs_stats *stats = p->private;
974 struct lprocfs_counter *cntr = v;
975 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
977 unsigned int num_cpu;
979 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
981 do_gettimeofday(&now);
982 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
983 "snapshot_time", now.tv_sec, now.tv_usec);
987 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
989 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
992 num_cpu = num_possible_cpus();
994 for (i = 0; i < num_cpu; i++) {
995 struct lprocfs_counter *percpu_cntr =
996 &(stats->ls_percpu[i])->lp_cntr[idx];
1000 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1001 t.lc_count = percpu_cntr->lc_count;
1002 t.lc_sum = percpu_cntr->lc_sum;
1003 t.lc_min = percpu_cntr->lc_min;
1004 t.lc_max = percpu_cntr->lc_max;
1005 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1006 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1007 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1008 ret.lc_count += t.lc_count;
1009 ret.lc_sum += t.lc_sum;
1010 if (t.lc_min < ret.lc_min)
1011 ret.lc_min = t.lc_min;
1012 if (t.lc_max > ret.lc_max)
1013 ret.lc_max = t.lc_max;
1014 ret.lc_sumsquare += t.lc_sumsquare;
1017 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1018 ret.lc_count, cntr->lc_units);
1022 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1023 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1024 ret.lc_min, ret.lc_max, ret.lc_sum);
1027 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1028 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1032 rc = seq_printf(p, "\n");
1034 return (rc < 0) ? rc : 0;
1037 struct seq_operations lprocfs_stats_seq_sops = {
1038 start: lprocfs_stats_seq_start,
1039 stop: lprocfs_stats_seq_stop,
1040 next: lprocfs_stats_seq_next,
1041 show: lprocfs_stats_seq_show,
1044 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1046 struct proc_dir_entry *dp = PDE(inode);
1047 struct seq_file *seq;
1050 LPROCFS_ENTRY_AND_CHECK(dp);
1051 rc = seq_open(file, &lprocfs_stats_seq_sops);
1056 seq = file->private_data;
1057 seq->private = dp->data;
1061 struct file_operations lprocfs_stats_seq_fops = {
1062 .owner = THIS_MODULE,
1063 .open = lprocfs_stats_seq_open,
1065 .write = lprocfs_stats_seq_write,
1066 .llseek = seq_lseek,
1067 .release = lprocfs_seq_release,
1070 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1071 struct lprocfs_stats *stats)
1073 struct proc_dir_entry *entry;
1074 LASSERT(root != NULL);
1076 entry = create_proc_entry(name, 0644, root);
1079 entry->proc_fops = &lprocfs_stats_seq_fops;
1080 entry->data = (void *)stats;
1084 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1085 unsigned conf, const char *name, const char *units)
1087 struct lprocfs_counter *c;
1089 unsigned int num_cpu;
1091 LASSERT(stats != NULL);
1093 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1095 for (i = 0; i < num_cpu; i++) {
1096 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1097 c->lc_config = conf;
1100 c->lc_min = LC_MIN_INIT;
1103 c->lc_units = units;
1106 lprocfs_stats_unlock(stats);
1108 EXPORT_SYMBOL(lprocfs_counter_init);
1110 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1112 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1113 LASSERT(coffset < stats->ls_num); \
1114 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1117 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1119 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1120 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1121 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1122 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1123 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1124 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1125 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1126 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1127 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1128 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1129 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1130 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1131 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1132 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1133 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1134 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1135 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1136 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1137 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1138 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1139 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1140 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1141 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1142 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1143 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1144 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1145 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1146 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1147 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1148 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1149 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1150 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1151 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1152 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1153 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1154 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1155 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1156 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1157 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1158 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1159 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1160 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1161 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1162 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1163 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1164 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1165 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1166 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1167 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1168 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1169 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1170 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1171 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1172 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1173 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1174 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1175 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1176 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1177 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1178 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1179 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1180 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1181 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1182 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1183 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1184 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1185 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1186 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1187 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1188 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1189 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1190 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1191 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1192 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1193 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1194 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1197 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1199 struct lprocfs_stats *stats;
1200 unsigned int num_stats;
1203 LASSERT(obd->obd_stats == NULL);
1204 LASSERT(obd->obd_proc_entry != NULL);
1205 LASSERT(obd->obd_cntr_base == 0);
1207 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1208 num_private_stats - 1 /* o_owner */;
1209 stats = lprocfs_alloc_stats(num_stats, 0);
1213 lprocfs_init_ops_stats(num_private_stats, stats);
1215 for (i = num_private_stats; i < num_stats; i++) {
1216 /* If this LBUGs, it is likely that an obd
1217 * operation was added to struct obd_ops in
1218 * <obd.h>, and that the corresponding line item
1219 * LPROCFS_OBD_OP_INIT(.., .., opname)
1220 * is missing from the list above. */
1221 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1222 "Missing obd_stat initializer obd_op "
1223 "operation at offset %d.\n", i - num_private_stats);
1225 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1227 lprocfs_free_stats(&stats);
1229 obd->obd_stats = stats;
1230 obd->obd_cntr_base = num_private_stats;
1235 void lprocfs_free_obd_stats(struct obd_device *obd)
1238 lprocfs_free_stats(&obd->obd_stats);
1241 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1243 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1244 LASSERT(coffset < stats->ls_num); \
1245 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1248 int lprocfs_alloc_md_stats(struct obd_device *obd,
1249 unsigned num_private_stats)
1251 struct lprocfs_stats *stats;
1252 unsigned int num_stats;
1255 LASSERT(obd->md_stats == NULL);
1256 LASSERT(obd->obd_proc_entry != NULL);
1257 LASSERT(obd->md_cntr_base == 0);
1259 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1261 stats = lprocfs_alloc_stats(num_stats, 0);
1265 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1266 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1267 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1268 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1269 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1270 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1271 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1272 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1273 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1274 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1275 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1276 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1277 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1278 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1279 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1280 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1281 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1282 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1283 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1284 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1285 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1286 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1287 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1288 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1289 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1290 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1291 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1292 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1293 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1294 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1296 for (i = num_private_stats; i < num_stats; i++) {
1297 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1298 CERROR("Missing md_stat initializer md_op "
1299 "operation at offset %d. Aborting.\n",
1300 i - num_private_stats);
1304 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1306 lprocfs_free_stats(&stats);
1308 obd->md_stats = stats;
1309 obd->md_cntr_base = num_private_stats;
1314 void lprocfs_free_md_stats(struct obd_device *obd)
1316 struct lprocfs_stats *stats = obd->md_stats;
1318 if (stats != NULL) {
1319 obd->md_stats = NULL;
1320 lprocfs_free_stats(&stats);
1324 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1325 int *eof, void *data)
1327 struct obd_export *exp = (struct obd_export*)data;
1328 LASSERT(exp != NULL);
1330 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1333 struct exp_uuid_cb_data {
1340 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1342 struct obd_export *exp = (struct obd_export *)obj;
1343 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1345 if (exp->exp_nid_stats)
1346 *data->len += snprintf((data->page + *data->len),
1347 data->count, "%s\n",
1348 obd_uuid2str(&exp->exp_client_uuid));
1351 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1352 int *eof, void *data)
1354 struct nid_stat *stats = (struct nid_stat *)data;
1355 struct exp_uuid_cb_data cb_data;
1356 struct obd_device *obd = stats->nid_obd;
1361 LASSERT(obd != NULL);
1363 cb_data.page = page;
1364 cb_data.count = count;
1367 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1368 &stats->nid, lprocfs_exp_print_uuid,
1370 return (*cb_data.len);
1373 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1374 int count, int *eof, void *data)
1377 return snprintf(page, count, "%s\n",
1378 "Write into this file to clear all nid stats and "
1379 "stale nid entries");
1381 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1383 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1385 struct nid_stat *stat = obj;
1388 /* object has only hash + iterate_all references.
1389 * add/delete blocked by hash bucket lock */
1390 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1391 if(stat->nid_exp_ref_count == 2) {
1392 hlist_del_init(&stat->nid_hash);
1393 stat->nid_exp_ref_count--;
1394 spin_lock(&stat->nid_obd->obd_nid_lock);
1395 list_del_init(&stat->nid_list);
1396 spin_unlock(&stat->nid_obd->obd_nid_lock);
1397 list_add(&stat->nid_list, data);
1401 /* we has reference to object - only clear data*/
1402 if (stat->nid_stats)
1403 lprocfs_clear_stats(stat->nid_stats);
1405 if (stat->nid_brw_stats) {
1406 for (i = 0; i < BRW_LAST; i++)
1407 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1413 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1414 unsigned long count, void *data)
1416 struct obd_device *obd = (struct obd_device *)data;
1417 struct nid_stat *client_stat;
1418 CFS_LIST_HEAD(free_list);
1420 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1421 lprocfs_nid_stats_clear_write_cb, &free_list);
1423 while (!list_empty(&free_list)) {
1424 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1425 list_del_init(&client_stat->nid_list);
1426 lprocfs_free_client_stats(client_stat);
1431 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1433 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1436 struct nid_stat *tmp = NULL, *tmp1;
1437 struct obd_device *obd = NULL;
1442 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1443 !exp->exp_obd->obd_nid_stats_hash_body)
1446 /* not test against zero because eric say:
1447 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1449 if (!nid || *nid == LNET_NID_ANY)
1454 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1456 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1461 tmp->nid_obd = exp->exp_obd;
1462 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1464 /* protect competitive add to list, not need locking on destroy */
1465 spin_lock(&obd->obd_nid_lock);
1466 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1467 spin_unlock(&obd->obd_nid_lock);
1469 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1471 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1472 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1475 exp->exp_nid_stats = tmp1;
1476 GOTO(destroy_new, rc = 0);
1478 /* not found - create */
1479 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1480 obd->obd_proc_exports_entry, NULL, NULL);
1481 if (!tmp->nid_proc) {
1482 CERROR("Error making export directory for"
1483 " nid %s\n", libcfs_nid2str(*nid));
1484 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1486 GOTO(destroy_new, rc = -ENOMEM);
1489 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1490 lprocfs_exp_rd_uuid, NULL, tmp);
1492 CWARN("Error adding the uuid file\n");
1494 exp->exp_nid_stats = tmp;
1499 spin_lock(&obd->obd_nid_lock);
1500 list_del(&tmp->nid_list);
1501 spin_unlock(&obd->obd_nid_lock);
1502 OBD_FREE(tmp, sizeof(struct nid_stat));
1506 int lprocfs_exp_cleanup(struct obd_export *exp)
1508 struct nid_stat *stat = exp->exp_nid_stats;
1513 stat->nid_exp_ref_count--;
1514 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1516 exp->exp_nid_stats = NULL;
1520 int lprocfs_write_helper(const char *buffer, unsigned long count,
1523 return lprocfs_write_frac_helper(buffer, count, val, 1);
1526 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1529 char kernbuf[20], *end, *pbuf;
1531 if (count > (sizeof(kernbuf) - 1))
1534 if (copy_from_user(kernbuf, buffer, count))
1537 kernbuf[count] = '\0';
1544 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1548 if (end != NULL && *end == '.') {
1549 int temp_val, pow = 1;
1553 if (strlen(pbuf) > 5)
1554 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1556 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1559 for (i = 0; i < (end - pbuf); i++)
1562 *val += temp_val / pow;
1568 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1570 long decimal_val, frac_val;
1576 decimal_val = val / mult;
1577 prtn = snprintf(buffer, count, "%ld", decimal_val);
1578 frac_val = val % mult;
1580 if (prtn < (count - 4) && frac_val > 0) {
1582 int i, temp_mult = 1, frac_bits = 0;
1584 temp_frac = frac_val * 10;
1585 buffer[prtn++] = '.';
1586 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1587 buffer[prtn++] ='0';
1592 Need to think these cases :
1593 1. #echo x.00 > /proc/xxx output result : x
1594 2. #echo x.0x > /proc/xxx output result : x.0x
1595 3. #echo x.x0 > /proc/xxx output result : x.x
1596 4. #echo x.xx > /proc/xxx output result : x.xx
1597 Only reserved 2bits fraction.
1599 for (i = 0; i < (5 - prtn); i++)
1602 frac_bits = min((int)count - prtn, 3 - frac_bits);
1603 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1606 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1608 if (buffer[prtn] == '.') {
1615 buffer[prtn++] ='\n';
1619 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1621 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1624 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1625 __u64 *val, int mult)
1627 char kernbuf[22], *end, *pbuf;
1628 __u64 whole, frac = 0, units;
1629 unsigned frac_d = 1;
1631 if (count > (sizeof(kernbuf) - 1) )
1634 if (copy_from_user(kernbuf, buffer, count))
1637 kernbuf[count] = '\0';
1644 whole = simple_strtoull(pbuf, &end, 10);
1648 if (end != NULL && *end == '.') {
1652 /* need to limit frac_d to a __u32 */
1653 if (strlen(pbuf) > 10)
1656 frac = simple_strtoull(pbuf, &end, 10);
1657 /* count decimal places */
1658 for (i = 0; i < (end - pbuf); i++)
1675 /* Specified units override the multiplier */
1677 mult = mult < 0 ? -units : units;
1680 do_div(frac, frac_d);
1681 *val = whole * mult + frac;
1685 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1686 char *name, mode_t mode,
1687 struct file_operations *seq_fops, void *data)
1689 struct proc_dir_entry *entry;
1692 entry = create_proc_entry(name, mode, parent);
1695 entry->proc_fops = seq_fops;
1700 EXPORT_SYMBOL(lprocfs_seq_create);
1702 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1704 struct file_operations *seq_fops,
1707 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1708 mode, seq_fops, data));
1710 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1712 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1714 if (value >= OBD_HIST_MAX)
1715 value = OBD_HIST_MAX - 1;
1717 spin_lock(&oh->oh_lock);
1718 oh->oh_buckets[value]++;
1719 spin_unlock(&oh->oh_lock);
1721 EXPORT_SYMBOL(lprocfs_oh_tally);
1723 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1727 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1730 lprocfs_oh_tally(oh, val);
1732 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1734 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1736 unsigned long ret = 0;
1739 for (i = 0; i < OBD_HIST_MAX; i++)
1740 ret += oh->oh_buckets[i];
1743 EXPORT_SYMBOL(lprocfs_oh_sum);
1745 void lprocfs_oh_clear(struct obd_histogram *oh)
1747 spin_lock(&oh->oh_lock);
1748 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1749 spin_unlock(&oh->oh_lock);
1751 EXPORT_SYMBOL(lprocfs_oh_clear);
1753 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1754 int count, int *eof, void *data)
1756 struct obd_device *obd = data;
1759 LASSERT(obd != NULL);
1760 LASSERT(count >= 0);
1762 /* Set start of user data returned to
1763 page + off since the user may have
1764 requested to read much smaller than
1765 what we need to read */
1766 *start = page + off;
1768 /* We know we are allocated a page here.
1769 Also we know that this function will
1770 not need to write more than a page
1771 so we can truncate at CFS_PAGE_SIZE. */
1772 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1774 /* Initialize the page */
1775 memset(page, 0, size);
1777 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1779 if (obd->obd_max_recoverable_clients == 0) {
1780 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1786 /* sampled unlocked, but really... */
1787 if (obd->obd_recovering == 0) {
1788 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1790 if (lprocfs_obd_snprintf(&page, size, &len,
1791 "recovery_start: %lu\n",
1792 obd->obd_recovery_start) <= 0)
1794 if (lprocfs_obd_snprintf(&page, size, &len,
1795 "recovery_duration: %lu\n",
1796 obd->obd_recovery_end -
1797 obd->obd_recovery_start) <= 0)
1799 /* Number of clients that have completed recovery */
1800 if (lprocfs_obd_snprintf(&page, size, &len,
1801 "completed_clients: %d/%d\n",
1802 obd->obd_max_recoverable_clients -
1803 obd->obd_recoverable_clients,
1804 obd->obd_max_recoverable_clients) <= 0)
1806 if (lprocfs_obd_snprintf(&page, size, &len,
1807 "replayed_requests: %d\n",
1808 obd->obd_replayed_requests) <= 0)
1810 if (lprocfs_obd_snprintf(&page, size, &len,
1811 "last_transno: "LPD64"\n",
1812 obd->obd_next_recovery_transno - 1)<=0)
1817 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1819 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1820 obd->obd_recovery_start) <= 0)
1822 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1823 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1824 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1826 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1827 obd->obd_connected_clients,
1828 obd->obd_max_recoverable_clients) <= 0)
1830 /* Number of clients that have completed recovery */
1831 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1832 obd->obd_max_recoverable_clients -
1833 obd->obd_recoverable_clients,
1834 obd->obd_max_recoverable_clients) <= 0)
1836 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1837 obd->obd_replayed_requests) <= 0)
1839 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1840 obd->obd_requests_queued_for_recovery) <= 0)
1843 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1844 obd->obd_next_recovery_transno) <= 0)
1850 return min(count, len - (int)off);
1852 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1854 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1855 int count, int *eof, void *data)
1857 struct obd_device *obd = (struct obd_device *)data;
1858 LASSERT(obd != NULL);
1860 return snprintf(page, count, "%lu\n",
1861 obd->obd_recovery_max_time);
1863 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1865 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1866 unsigned long count, void *data)
1868 struct obd_device *obd = (struct obd_device *)data;
1870 LASSERT(obd != NULL);
1872 rc = lprocfs_write_helper(buffer, count, &val);
1876 obd->obd_recovery_max_time = val;
1879 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1881 EXPORT_SYMBOL(lprocfs_register);
1882 EXPORT_SYMBOL(lprocfs_srch);
1883 EXPORT_SYMBOL(lprocfs_remove);
1884 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1885 EXPORT_SYMBOL(lprocfs_add_vars);
1886 EXPORT_SYMBOL(lprocfs_obd_setup);
1887 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1888 EXPORT_SYMBOL(lprocfs_add_simple);
1889 EXPORT_SYMBOL(lprocfs_add_symlink);
1890 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1891 EXPORT_SYMBOL(lprocfs_alloc_stats);
1892 EXPORT_SYMBOL(lprocfs_free_stats);
1893 EXPORT_SYMBOL(lprocfs_clear_stats);
1894 EXPORT_SYMBOL(lprocfs_register_stats);
1895 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1896 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1897 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1898 EXPORT_SYMBOL(lprocfs_exp_setup);
1899 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1901 EXPORT_SYMBOL(lprocfs_rd_u64);
1902 EXPORT_SYMBOL(lprocfs_rd_atomic);
1903 EXPORT_SYMBOL(lprocfs_wr_atomic);
1904 EXPORT_SYMBOL(lprocfs_rd_uint);
1905 EXPORT_SYMBOL(lprocfs_wr_uint);
1906 EXPORT_SYMBOL(lprocfs_rd_uuid);
1907 EXPORT_SYMBOL(lprocfs_rd_name);
1908 EXPORT_SYMBOL(lprocfs_rd_fstype);
1909 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1910 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1911 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1912 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1913 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1914 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1915 EXPORT_SYMBOL(lprocfs_rd_blksize);
1916 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1917 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1918 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1919 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1920 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1922 EXPORT_SYMBOL(lprocfs_write_helper);
1923 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1924 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1925 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1926 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);