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, quotacheck);
1188 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1189 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1190 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1191 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1192 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1193 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1196 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1198 struct lprocfs_stats *stats;
1199 unsigned int num_stats;
1202 LASSERT(obd->obd_stats == NULL);
1203 LASSERT(obd->obd_proc_entry != NULL);
1204 LASSERT(obd->obd_cntr_base == 0);
1206 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1207 num_private_stats - 1 /* o_owner */;
1208 stats = lprocfs_alloc_stats(num_stats, 0);
1212 lprocfs_init_ops_stats(num_private_stats, stats);
1214 for (i = num_private_stats; i < num_stats; i++) {
1215 /* If this LBUGs, it is likely that an obd
1216 * operation was added to struct obd_ops in
1217 * <obd.h>, and that the corresponding line item
1218 * LPROCFS_OBD_OP_INIT(.., .., opname)
1219 * is missing from the list above. */
1220 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1221 "Missing obd_stat initializer obd_op "
1222 "operation at offset %d.\n", i - num_private_stats);
1224 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1226 lprocfs_free_stats(&stats);
1228 obd->obd_stats = stats;
1229 obd->obd_cntr_base = num_private_stats;
1234 void lprocfs_free_obd_stats(struct obd_device *obd)
1237 lprocfs_free_stats(&obd->obd_stats);
1240 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1242 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1243 LASSERT(coffset < stats->ls_num); \
1244 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1247 int lprocfs_alloc_md_stats(struct obd_device *obd,
1248 unsigned num_private_stats)
1250 struct lprocfs_stats *stats;
1251 unsigned int num_stats;
1254 LASSERT(obd->md_stats == NULL);
1255 LASSERT(obd->obd_proc_entry != NULL);
1256 LASSERT(obd->md_cntr_base == 0);
1258 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1260 stats = lprocfs_alloc_stats(num_stats, 0);
1264 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1265 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1266 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1267 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1268 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1269 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1270 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1271 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1272 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1273 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1274 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1275 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1276 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1277 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1278 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1279 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1280 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1281 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1282 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1283 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1284 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1285 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1286 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1287 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1288 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1289 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1290 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1291 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1292 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1293 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1295 for (i = num_private_stats; i < num_stats; i++) {
1296 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1297 CERROR("Missing md_stat initializer md_op "
1298 "operation at offset %d. Aborting.\n",
1299 i - num_private_stats);
1303 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1305 lprocfs_free_stats(&stats);
1307 obd->md_stats = stats;
1308 obd->md_cntr_base = num_private_stats;
1313 void lprocfs_free_md_stats(struct obd_device *obd)
1315 struct lprocfs_stats *stats = obd->md_stats;
1317 if (stats != NULL) {
1318 obd->md_stats = NULL;
1319 lprocfs_free_stats(&stats);
1323 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1324 int *eof, void *data)
1326 struct obd_export *exp = (struct obd_export*)data;
1327 LASSERT(exp != NULL);
1329 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1332 struct exp_uuid_cb_data {
1339 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1341 struct obd_export *exp = (struct obd_export *)obj;
1342 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1344 if (exp->exp_nid_stats)
1345 *data->len += snprintf((data->page + *data->len),
1346 data->count, "%s\n",
1347 obd_uuid2str(&exp->exp_client_uuid));
1350 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1351 int *eof, void *data)
1353 struct nid_stat *stats = (struct nid_stat *)data;
1354 struct exp_uuid_cb_data cb_data;
1355 struct obd_device *obd = stats->nid_obd;
1360 LASSERT(obd != NULL);
1362 cb_data.page = page;
1363 cb_data.count = count;
1366 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1367 &stats->nid, lprocfs_exp_print_uuid,
1369 return (*cb_data.len);
1372 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1373 int count, int *eof, void *data)
1376 return snprintf(page, count, "%s\n",
1377 "Write into this file to clear all nid stats and "
1378 "stale nid entries");
1380 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1382 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1384 struct nid_stat *stat = obj;
1387 /* object has only hash + iterate_all references.
1388 * add/delete blocked by hash bucket lock */
1389 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1390 if(stat->nid_exp_ref_count == 2) {
1391 hlist_del_init(&stat->nid_hash);
1392 stat->nid_exp_ref_count--;
1393 spin_lock(&stat->nid_obd->obd_nid_lock);
1394 list_del_init(&stat->nid_list);
1395 spin_unlock(&stat->nid_obd->obd_nid_lock);
1396 list_add(&stat->nid_list, data);
1400 /* we has reference to object - only clear data*/
1401 if (stat->nid_stats)
1402 lprocfs_clear_stats(stat->nid_stats);
1404 if (stat->nid_brw_stats) {
1405 for (i = 0; i < BRW_LAST; i++)
1406 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1412 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1413 unsigned long count, void *data)
1415 struct obd_device *obd = (struct obd_device *)data;
1416 struct nid_stat *client_stat;
1417 CFS_LIST_HEAD(free_list);
1419 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1420 lprocfs_nid_stats_clear_write_cb, &free_list);
1422 while (!list_empty(&free_list)) {
1423 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1424 list_del_init(&client_stat->nid_list);
1425 lprocfs_free_client_stats(client_stat);
1430 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1432 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1435 struct nid_stat *tmp = NULL, *tmp1;
1436 struct obd_device *obd = NULL;
1441 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1442 !exp->exp_obd->obd_nid_stats_hash_body)
1445 /* not test against zero because eric say:
1446 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1448 if (!nid || *nid == LNET_NID_ANY)
1453 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1455 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1460 tmp->nid_obd = exp->exp_obd;
1461 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1463 /* protect competitive add to list, not need locking on destroy */
1464 spin_lock(&obd->obd_nid_lock);
1465 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1466 spin_unlock(&obd->obd_nid_lock);
1468 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1470 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1471 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1474 exp->exp_nid_stats = tmp1;
1475 GOTO(destroy_new, rc = 0);
1477 /* not found - create */
1478 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1479 obd->obd_proc_exports_entry, NULL, NULL);
1480 if (!tmp->nid_proc) {
1481 CERROR("Error making export directory for"
1482 " nid %s\n", libcfs_nid2str(*nid));
1483 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1485 GOTO(destroy_new, rc = -ENOMEM);
1488 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1489 lprocfs_exp_rd_uuid, NULL, tmp);
1491 CWARN("Error adding the uuid file\n");
1493 exp->exp_nid_stats = tmp;
1498 spin_lock(&obd->obd_nid_lock);
1499 list_del(&tmp->nid_list);
1500 spin_unlock(&obd->obd_nid_lock);
1501 OBD_FREE(tmp, sizeof(struct nid_stat));
1505 int lprocfs_exp_cleanup(struct obd_export *exp)
1507 struct nid_stat *stat = exp->exp_nid_stats;
1512 stat->nid_exp_ref_count--;
1513 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1515 exp->exp_nid_stats = NULL;
1519 int lprocfs_write_helper(const char *buffer, unsigned long count,
1522 return lprocfs_write_frac_helper(buffer, count, val, 1);
1525 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1528 char kernbuf[20], *end, *pbuf;
1530 if (count > (sizeof(kernbuf) - 1))
1533 if (copy_from_user(kernbuf, buffer, count))
1536 kernbuf[count] = '\0';
1543 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1547 if (end != NULL && *end == '.') {
1548 int temp_val, pow = 1;
1552 if (strlen(pbuf) > 5)
1553 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1555 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1558 for (i = 0; i < (end - pbuf); i++)
1561 *val += temp_val / pow;
1567 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1569 long decimal_val, frac_val;
1575 decimal_val = val / mult;
1576 prtn = snprintf(buffer, count, "%ld", decimal_val);
1577 frac_val = val % mult;
1579 if (prtn < (count - 4) && frac_val > 0) {
1581 int i, temp_mult = 1, frac_bits = 0;
1583 temp_frac = frac_val * 10;
1584 buffer[prtn++] = '.';
1585 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1586 buffer[prtn++] ='0';
1591 Need to think these cases :
1592 1. #echo x.00 > /proc/xxx output result : x
1593 2. #echo x.0x > /proc/xxx output result : x.0x
1594 3. #echo x.x0 > /proc/xxx output result : x.x
1595 4. #echo x.xx > /proc/xxx output result : x.xx
1596 Only reserved 2bits fraction.
1598 for (i = 0; i < (5 - prtn); i++)
1601 frac_bits = min((int)count - prtn, 3 - frac_bits);
1602 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1605 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1607 if (buffer[prtn] == '.') {
1614 buffer[prtn++] ='\n';
1618 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1620 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1623 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1624 __u64 *val, int mult)
1626 char kernbuf[22], *end, *pbuf;
1627 __u64 whole, frac = 0, units;
1628 unsigned frac_d = 1;
1630 if (count > (sizeof(kernbuf) - 1) )
1633 if (copy_from_user(kernbuf, buffer, count))
1636 kernbuf[count] = '\0';
1643 whole = simple_strtoull(pbuf, &end, 10);
1647 if (end != NULL && *end == '.') {
1651 /* need to limit frac_d to a __u32 */
1652 if (strlen(pbuf) > 10)
1655 frac = simple_strtoull(pbuf, &end, 10);
1656 /* count decimal places */
1657 for (i = 0; i < (end - pbuf); i++)
1674 /* Specified units override the multiplier */
1676 mult = mult < 0 ? -units : units;
1679 do_div(frac, frac_d);
1680 *val = whole * mult + frac;
1684 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1685 char *name, mode_t mode,
1686 struct file_operations *seq_fops, void *data)
1688 struct proc_dir_entry *entry;
1691 entry = create_proc_entry(name, mode, parent);
1694 entry->proc_fops = seq_fops;
1699 EXPORT_SYMBOL(lprocfs_seq_create);
1701 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1703 struct file_operations *seq_fops,
1706 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1707 mode, seq_fops, data));
1709 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1711 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1713 if (value >= OBD_HIST_MAX)
1714 value = OBD_HIST_MAX - 1;
1716 spin_lock(&oh->oh_lock);
1717 oh->oh_buckets[value]++;
1718 spin_unlock(&oh->oh_lock);
1720 EXPORT_SYMBOL(lprocfs_oh_tally);
1722 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1726 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1729 lprocfs_oh_tally(oh, val);
1731 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1733 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1735 unsigned long ret = 0;
1738 for (i = 0; i < OBD_HIST_MAX; i++)
1739 ret += oh->oh_buckets[i];
1742 EXPORT_SYMBOL(lprocfs_oh_sum);
1744 void lprocfs_oh_clear(struct obd_histogram *oh)
1746 spin_lock(&oh->oh_lock);
1747 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1748 spin_unlock(&oh->oh_lock);
1750 EXPORT_SYMBOL(lprocfs_oh_clear);
1752 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1753 int count, int *eof, void *data)
1755 struct obd_device *obd = data;
1758 LASSERT(obd != NULL);
1759 LASSERT(count >= 0);
1761 /* Set start of user data returned to
1762 page + off since the user may have
1763 requested to read much smaller than
1764 what we need to read */
1765 *start = page + off;
1767 /* We know we are allocated a page here.
1768 Also we know that this function will
1769 not need to write more than a page
1770 so we can truncate at CFS_PAGE_SIZE. */
1771 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1773 /* Initialize the page */
1774 memset(page, 0, size);
1776 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1778 if (obd->obd_max_recoverable_clients == 0) {
1779 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1785 /* sampled unlocked, but really... */
1786 if (obd->obd_recovering == 0) {
1787 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1789 if (lprocfs_obd_snprintf(&page, size, &len,
1790 "recovery_start: %lu\n",
1791 obd->obd_recovery_start) <= 0)
1793 if (lprocfs_obd_snprintf(&page, size, &len,
1794 "recovery_duration: %lu\n",
1795 obd->obd_recovery_end -
1796 obd->obd_recovery_start) <= 0)
1798 /* Number of clients that have completed recovery */
1799 if (lprocfs_obd_snprintf(&page, size, &len,
1800 "completed_clients: %d/%d\n",
1801 obd->obd_max_recoverable_clients -
1802 obd->obd_recoverable_clients,
1803 obd->obd_max_recoverable_clients) <= 0)
1805 if (lprocfs_obd_snprintf(&page, size, &len,
1806 "replayed_requests: %d\n",
1807 obd->obd_replayed_requests) <= 0)
1809 if (lprocfs_obd_snprintf(&page, size, &len,
1810 "last_transno: "LPD64"\n",
1811 obd->obd_next_recovery_transno - 1)<=0)
1816 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1818 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1819 obd->obd_recovery_start) <= 0)
1821 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1822 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1823 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1825 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1826 obd->obd_connected_clients,
1827 obd->obd_max_recoverable_clients) <= 0)
1829 /* Number of clients that have completed recovery */
1830 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1831 obd->obd_max_recoverable_clients -
1832 obd->obd_recoverable_clients,
1833 obd->obd_max_recoverable_clients) <= 0)
1835 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1836 obd->obd_replayed_requests) <= 0)
1838 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1839 obd->obd_requests_queued_for_recovery) <= 0)
1842 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1843 obd->obd_next_recovery_transno) <= 0)
1849 return min(count, len - (int)off);
1851 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1853 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1854 int count, int *eof, void *data)
1856 struct obd_device *obd = (struct obd_device *)data;
1857 LASSERT(obd != NULL);
1859 return snprintf(page, count, "%lu\n",
1860 obd->obd_recovery_max_time);
1862 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1864 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1865 unsigned long count, void *data)
1867 struct obd_device *obd = (struct obd_device *)data;
1869 LASSERT(obd != NULL);
1871 rc = lprocfs_write_helper(buffer, count, &val);
1875 obd->obd_recovery_max_time = val;
1878 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1880 EXPORT_SYMBOL(lprocfs_register);
1881 EXPORT_SYMBOL(lprocfs_srch);
1882 EXPORT_SYMBOL(lprocfs_remove);
1883 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1884 EXPORT_SYMBOL(lprocfs_add_vars);
1885 EXPORT_SYMBOL(lprocfs_obd_setup);
1886 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1887 EXPORT_SYMBOL(lprocfs_add_simple);
1888 EXPORT_SYMBOL(lprocfs_add_symlink);
1889 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1890 EXPORT_SYMBOL(lprocfs_alloc_stats);
1891 EXPORT_SYMBOL(lprocfs_free_stats);
1892 EXPORT_SYMBOL(lprocfs_clear_stats);
1893 EXPORT_SYMBOL(lprocfs_register_stats);
1894 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1895 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1896 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1897 EXPORT_SYMBOL(lprocfs_exp_setup);
1898 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1900 EXPORT_SYMBOL(lprocfs_rd_u64);
1901 EXPORT_SYMBOL(lprocfs_rd_atomic);
1902 EXPORT_SYMBOL(lprocfs_wr_atomic);
1903 EXPORT_SYMBOL(lprocfs_rd_uint);
1904 EXPORT_SYMBOL(lprocfs_wr_uint);
1905 EXPORT_SYMBOL(lprocfs_rd_uuid);
1906 EXPORT_SYMBOL(lprocfs_rd_name);
1907 EXPORT_SYMBOL(lprocfs_rd_fstype);
1908 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1909 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1910 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1911 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1912 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1913 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1914 EXPORT_SYMBOL(lprocfs_rd_blksize);
1915 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1916 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1917 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1918 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1919 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1921 EXPORT_SYMBOL(lprocfs_write_helper);
1922 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1923 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1924 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1925 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);