1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/lprocfs_status.c
38 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
42 # define EXPORT_SYMTAB
44 #define DEBUG_SUBSYSTEM S_CLASS
47 # include <liblustre.h>
50 #include <obd_class.h>
51 #include <lprocfs_status.h>
52 #include <lustre_fsfilt.h>
56 #define MAX_STRING_SIZE 128
58 /* for bug 10866, global variable */
59 DECLARE_RWSEM(_lprocfs_lock);
60 EXPORT_SYMBOL(_lprocfs_lock);
62 int lprocfs_seq_release(struct inode *inode, struct file *file)
65 return seq_release(inode, file);
67 EXPORT_SYMBOL(lprocfs_seq_release);
69 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
72 struct proc_dir_entry *temp;
79 while (temp != NULL) {
80 if (strcmp(temp->name, name) == 0) {
91 /* lprocfs API calls */
93 /* Function that emulates snprintf but also has the side effect of advancing
94 the page pointer for the next write into the buffer, incrementing the total
95 length written to the buffer, and decrementing the size left in the
97 static int lprocfs_obd_snprintf(char **page, int end, int *len,
98 const char *format, ...)
106 va_start(list, format);
107 n = vsnprintf(*page, end - *len, format, list);
110 *page += n; *len += n;
114 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
116 read_proc_t *read_proc,
117 write_proc_t *write_proc,
119 struct file_operations *fops)
121 cfs_proc_dir_entry_t *proc;
124 if (root == NULL || name == NULL)
125 return ERR_PTR(-EINVAL);
132 proc = create_proc_entry(name, mode, root);
134 CERROR("LprocFS: No memory to create /proc entry %s", name);
135 return ERR_PTR(-ENOMEM);
137 proc->read_proc = read_proc;
138 proc->write_proc = write_proc;
141 proc->proc_fops = fops;
145 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
146 struct proc_dir_entry *parent, const char *dest)
148 struct proc_dir_entry *entry;
150 if (parent == NULL || dest == NULL)
153 entry = proc_symlink(name, parent, dest);
155 CERROR("LprocFS: Could not create symbolic link from %s to %s",
160 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
161 size_t size, loff_t *ppos)
163 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
164 char *page, *start = NULL;
165 int rc = 0, eof = 1, count;
167 if (*ppos >= CFS_PAGE_SIZE)
170 page = (char *)__get_free_page(GFP_KERNEL);
175 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
176 if (!dp->deleted && dp->read_proc)
177 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
183 /* for lustre proc read, the read count must be less than PAGE_SIZE */
192 start = page + *ppos;
193 } else if (start < page) {
197 count = (rc < size) ? rc : size;
198 if (copy_to_user(buf, start, count)) {
205 free_page((unsigned long)page);
209 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
210 size_t size, loff_t *ppos)
212 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
216 if (!dp->deleted && dp->write_proc)
217 rc = dp->write_proc(f, buf, size, dp->data);
222 static struct file_operations lprocfs_generic_fops = {
223 .owner = THIS_MODULE,
224 .read = lprocfs_fops_read,
225 .write = lprocfs_fops_write,
228 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
230 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
231 struct obd_device *obd = dp->data;
233 atomic_inc(&obd->obd_evict_inprogress);
238 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
240 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
241 struct obd_device *obd = dp->data;
243 atomic_dec(&obd->obd_evict_inprogress);
244 wake_up(&obd->obd_evict_inprogress_waitq);
249 struct file_operations lprocfs_evict_client_fops = {
250 .owner = THIS_MODULE,
251 .read = lprocfs_fops_read,
252 .write = lprocfs_fops_write,
253 .open = lprocfs_evict_client_open,
254 .release = lprocfs_evict_client_release,
256 EXPORT_SYMBOL(lprocfs_evict_client_fops);
261 * \param root [in] The parent proc entry on which new entry will be added.
262 * \param list [in] Array of proc entries to be added.
263 * \param data [in] The argument to be passed when entries read/write routines
264 * are called through /proc file.
266 * \retval 0 on success
269 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
272 if (root == NULL || list == NULL)
275 while (list->name != NULL) {
276 struct proc_dir_entry *cur_root, *proc;
277 char *pathcopy, *cur, *next, pathbuf[64];
278 int pathsize = strlen(list->name) + 1;
283 /* need copy of path for strsep */
284 if (strlen(list->name) > sizeof(pathbuf) - 1) {
285 OBD_ALLOC(pathcopy, pathsize);
286 if (pathcopy == NULL)
293 strcpy(pathcopy, list->name);
295 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
296 if (*cur =='\0') /* skip double/trailing "/" */
299 proc = lprocfs_srch(cur_root, cur);
300 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
301 cur_root->name, cur, next,
302 (proc ? "exists" : "new"));
304 cur_root = (proc ? proc :
305 proc_mkdir(cur, cur_root));
306 } else if (proc == NULL) {
308 if (list->proc_mode != 0000) {
309 mode = list->proc_mode;
313 if (list->write_fptr)
316 proc = create_proc_entry(cur, mode, cur_root);
320 if (pathcopy != pathbuf)
321 OBD_FREE(pathcopy, pathsize);
323 if (cur_root == NULL || proc == NULL) {
324 CERROR("LprocFS: No memory to create /proc entry %s",
330 proc->proc_fops = list->fops;
332 proc->proc_fops = &lprocfs_generic_fops;
333 proc->read_proc = list->read_fptr;
334 proc->write_proc = list->write_fptr;
335 proc->data = (list->data ? list->data : data);
341 void lprocfs_remove(struct proc_dir_entry **rooth)
343 struct proc_dir_entry *root = *rooth;
344 struct proc_dir_entry *temp = root;
345 struct proc_dir_entry *rm_entry;
346 struct proc_dir_entry *parent;
352 parent = root->parent;
353 LASSERT(parent != NULL);
354 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
357 while (temp->subdir != NULL)
363 /* Memory corruption once caused this to fail, and
364 without this LASSERT we would loop here forever. */
365 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
366 "0x%p %s/%s len %d\n", rm_entry, temp->name,
367 rm_entry->name, (int)strlen(rm_entry->name));
369 /* Now, the rm_entry->deleted flags is protected
370 * by _lprocfs_lock. */
371 rm_entry->data = NULL;
372 remove_proc_entry(rm_entry->name, temp);
376 LPROCFS_WRITE_EXIT();
379 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
381 LASSERT(parent != NULL);
382 remove_proc_entry(name, parent);
385 struct proc_dir_entry *lprocfs_register(const char *name,
386 struct proc_dir_entry *parent,
387 struct lprocfs_vars *list, void *data)
389 struct proc_dir_entry *newchild;
391 newchild = lprocfs_srch(parent, name);
392 if (newchild != NULL) {
393 CERROR(" Lproc: Attempting to register %s more than once \n",
395 return ERR_PTR(-EALREADY);
398 newchild = proc_mkdir(name, parent);
399 if (newchild != NULL && list != NULL) {
400 int rc = lprocfs_add_vars(newchild, list, data);
402 lprocfs_remove(&newchild);
409 /* Generic callbacks */
410 int lprocfs_rd_uint(char *page, char **start, off_t off,
411 int count, int *eof, void *data)
413 unsigned int *temp = data;
414 return snprintf(page, count, "%u\n", *temp);
417 int lprocfs_wr_uint(struct file *file, const char *buffer,
418 unsigned long count, void *data)
421 char dummy[MAX_STRING_SIZE + 1], *end;
424 dummy[MAX_STRING_SIZE] = '\0';
425 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
428 tmp = simple_strtoul(dummy, &end, 0);
432 *p = (unsigned int)tmp;
436 int lprocfs_rd_u64(char *page, char **start, off_t off,
437 int count, int *eof, void *data)
439 LASSERT(data != NULL);
441 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
444 int lprocfs_rd_atomic(char *page, char **start, off_t off,
445 int count, int *eof, void *data)
447 atomic_t *atom = data;
448 LASSERT(atom != NULL);
450 return snprintf(page, count, "%d\n", atomic_read(atom));
453 int lprocfs_wr_atomic(struct file *file, const char *buffer,
454 unsigned long count, void *data)
456 atomic_t *atm = data;
460 rc = lprocfs_write_helper(buffer, count, &val);
467 atomic_set(atm, val);
471 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
472 int *eof, void *data)
474 struct obd_device *obd = data;
476 LASSERT(obd != NULL);
478 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
481 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
482 int *eof, void *data)
484 struct obd_device *dev = data;
486 LASSERT(dev != NULL);
487 LASSERT(dev->obd_name != NULL);
489 return snprintf(page, count, "%s\n", dev->obd_name);
492 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
495 struct obd_device *obd = data;
497 LASSERT(obd != NULL);
498 LASSERT(obd->obd_fsops != NULL);
499 LASSERT(obd->obd_fsops->fs_type != NULL);
500 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
503 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
504 int *eof, void *data)
506 struct obd_statfs osfs;
507 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
511 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
516 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
517 int *eof, void *data)
519 struct obd_statfs osfs;
520 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
523 __u32 blk_size = osfs.os_bsize >> 10;
524 __u64 result = osfs.os_blocks;
526 while (blk_size >>= 1)
530 rc = snprintf(page, count, LPU64"\n", result);
535 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
536 int *eof, void *data)
538 struct obd_statfs osfs;
539 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
542 __u32 blk_size = osfs.os_bsize >> 10;
543 __u64 result = osfs.os_bfree;
545 while (blk_size >>= 1)
549 rc = snprintf(page, count, LPU64"\n", result);
554 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
555 int *eof, void *data)
557 struct obd_statfs osfs;
558 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
561 __u32 blk_size = osfs.os_bsize >> 10;
562 __u64 result = osfs.os_bavail;
564 while (blk_size >>= 1)
568 rc = snprintf(page, count, LPU64"\n", result);
573 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
574 int *eof, void *data)
576 struct obd_statfs osfs;
577 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
581 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
587 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
588 int *eof, void *data)
590 struct obd_statfs osfs;
591 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
595 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
600 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
601 int *eof, void *data)
603 struct obd_device *obd = data;
604 struct obd_import *imp;
605 char *imp_state_name = NULL;
608 LASSERT(obd != NULL);
609 LPROCFS_CLIMP_CHECK(obd);
610 imp = obd->u.cli.cl_import;
611 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
613 rc = snprintf(page, count, "%s\t%s%s\n",
614 obd2cli_tgt(obd), imp_state_name,
615 imp->imp_deactive ? "\tDEACTIVATED" : "");
617 LPROCFS_CLIMP_EXIT(obd);
621 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
622 int *eof, void *data)
624 struct obd_device *obd = data;
625 struct ptlrpc_connection *conn;
628 LASSERT(obd != NULL);
630 LPROCFS_CLIMP_CHECK(obd);
631 conn = obd->u.cli.cl_import->imp_connection;
632 LASSERT(conn != NULL);
634 if (obd->u.cli.cl_import) {
635 rc = snprintf(page, count, "%s\n",
636 conn->c_remote_uuid.uuid);
638 rc = snprintf(page, count, "%s\n", "<none>");
641 LPROCFS_CLIMP_EXIT(obd);
645 #define flag2str(flag) \
646 if (imp->imp_##flag && max - len > 0) \
647 len += snprintf(str + len, max - len, " " #flag);
650 * Append a space separated list of current set flags to str.
652 static int obd_import_flags2str(struct obd_import *imp, char *str,
657 if (imp->imp_obd->obd_no_recov)
658 len += snprintf(str, max - len, " no_recov");
662 flag2str(replayable);
665 flag2str(last_recon);
670 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
671 int *eof, void *data)
673 struct obd_device *obd = (struct obd_device *)data;
674 struct obd_import *imp;
675 char *imp_state_name = NULL;
678 LASSERT(obd != NULL);
679 LPROCFS_CLIMP_CHECK(obd);
680 imp = obd->u.cli.cl_import;
681 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
684 rc = snprintf(page, count,
689 " unregistering: %u\n"
693 " last_replay_transno: "LPU64"\n"
694 " peer_committed_transno: "LPU64"\n"
695 " last_trasno_checked: "LPU64"\n"
698 obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
700 atomic_read(&imp->imp_inflight),
701 atomic_read(&imp->imp_unregistering),
704 atomic_read(&imp->imp_inval_count),
705 imp->imp_last_replay_transno,
706 imp->imp_peer_committed_transno,
707 imp->imp_last_transno_checked);
708 rc += obd_import_flags2str(imp, page + rc, count - rc);
709 rc += snprintf(page+rc, count - rc, "\n");
710 LPROCFS_CLIMP_EXIT(obd);
714 int lprocfs_at_hist_helper(char *page, int count, int rc,
715 struct adaptive_timeout *at)
718 for (i = 0; i < AT_BINS; i++)
719 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
720 rc += snprintf(page + rc, count - rc, "\n");
724 /* See also ptlrpc_lprocfs_rd_timeouts */
725 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
726 int *eof, void *data)
728 struct obd_device *obd = (struct obd_device *)data;
729 struct obd_import *imp;
730 unsigned int cur, worst;
735 LASSERT(obd != NULL);
736 LPROCFS_CLIMP_CHECK(obd);
737 imp = obd->u.cli.cl_import;
740 now = cfs_time_current_sec();
742 /* Some network health info for kicks */
743 s2dhms(&ts, now - imp->imp_last_reply_time);
744 rc += snprintf(page + rc, count - rc,
745 "%-10s : %ld, "DHMS_FMT" ago\n",
746 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
748 cur = at_get(&imp->imp_at.iat_net_latency);
749 worst = imp->imp_at.iat_net_latency.at_worst_ever;
750 worstt = imp->imp_at.iat_net_latency.at_worst_time;
751 s2dhms(&ts, now - worstt);
752 rc += snprintf(page + rc, count - rc,
753 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
754 "network", cur, worst, worstt, DHMS_VARS(&ts));
755 rc = lprocfs_at_hist_helper(page, count, rc,
756 &imp->imp_at.iat_net_latency);
758 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
759 if (imp->imp_at.iat_portal[i] == 0)
761 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
762 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
763 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
764 s2dhms(&ts, now - worstt);
765 rc += snprintf(page + rc, count - rc,
766 "portal %-2d : cur %3u worst %3u (at %ld, "
767 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
768 cur, worst, worstt, DHMS_VARS(&ts));
769 rc = lprocfs_at_hist_helper(page, count, rc,
770 &imp->imp_at.iat_service_estimate[i]);
773 LPROCFS_CLIMP_EXIT(obd);
777 static const char *obd_connect_names[] = {
804 "mds_mds_connection",
807 "alt_checksum_algorithm",
814 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
815 int count, int *eof, void *data)
817 struct obd_device *obd = data;
818 __u64 mask = 1, flags;
821 LPROCFS_CLIMP_CHECK(obd);
822 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
823 ret = snprintf(page, count, "flags="LPX64"\n", flags);
824 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
826 ret += snprintf(page + ret, count - ret, "%s\n",
827 obd_connect_names[i]);
829 if (flags & ~(mask - 1))
830 ret += snprintf(page + ret, count - ret,
831 "unknown flags "LPX64"\n", flags & ~(mask - 1));
833 LPROCFS_CLIMP_EXIT(obd);
836 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
838 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
839 int *eof, void *data)
841 struct obd_device *obd = data;
843 LASSERT(obd != NULL);
845 return snprintf(page, count, "%u\n", obd->obd_num_exports);
848 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
849 int *eof, void *data)
851 struct obd_type *class = (struct obd_type*) data;
853 LASSERT(class != NULL);
855 return snprintf(page, count, "%d\n", class->typ_refcnt);
858 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
862 LASSERT(obd != NULL);
863 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
864 LASSERT(obd->obd_type->typ_procroot != NULL);
866 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
867 obd->obd_type->typ_procroot,
869 if (IS_ERR(obd->obd_proc_entry)) {
870 rc = PTR_ERR(obd->obd_proc_entry);
871 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
872 obd->obd_proc_entry = NULL;
877 int lprocfs_obd_cleanup(struct obd_device *obd)
881 if (obd->obd_proc_exports_entry) {
882 /* Should be no exports left */
883 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
884 lprocfs_remove(&obd->obd_proc_exports_entry);
885 obd->obd_proc_exports_entry = NULL;
887 lprocfs_remove(&obd->obd_proc_entry);
891 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
893 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
894 client_stat->nid_proc, client_stat->nid_stats,
895 client_stat->nid_brw_stats);
897 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
898 client_stat->nid_exp_ref_count);
900 hlist_del_init(&client_stat->nid_hash);
902 if (client_stat->nid_proc)
903 lprocfs_remove(&client_stat->nid_proc);
905 if (client_stat->nid_stats)
906 lprocfs_free_stats(&client_stat->nid_stats);
908 if (client_stat->nid_brw_stats)
909 OBD_FREE_PTR(client_stat->nid_brw_stats);
911 if (client_stat->nid_ldlm_stats)
912 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
914 OBD_FREE_PTR(client_stat);
919 void lprocfs_free_per_client_stats(struct obd_device *obd)
921 struct nid_stat *stat;
924 /* we need extra list - because hash_exit called to early */
925 /* not need locking because all clients is died */
926 while(!list_empty(&obd->obd_nid_stats)) {
927 stat = list_entry(obd->obd_nid_stats.next,
928 struct nid_stat, nid_list);
929 list_del_init(&stat->nid_list);
930 lprocfs_free_client_stats(stat);
936 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
937 enum lprocfs_stats_flags flags)
939 struct lprocfs_stats *stats;
940 unsigned int percpusize;
942 unsigned int num_cpu;
947 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
950 num_cpu = num_possible_cpus();
952 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
956 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
957 stats->ls_flags = flags;
958 spin_lock_init(&stats->ls_lock);
959 /* Use this lock only if there are no percpu areas */
964 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
966 percpusize = L1_CACHE_ALIGN(percpusize);
968 for (i = 0; i < num_cpu; i++) {
969 OBD_ALLOC(stats->ls_percpu[i], percpusize);
970 if (stats->ls_percpu[i] == NULL) {
971 for (j = 0; j < i; j++) {
972 OBD_FREE(stats->ls_percpu[j], percpusize);
973 stats->ls_percpu[j] = NULL;
978 if (stats->ls_percpu[0] == NULL) {
979 OBD_FREE(stats, offsetof(typeof(*stats),
980 ls_percpu[num_cpu]));
988 void lprocfs_free_stats(struct lprocfs_stats **statsh)
990 struct lprocfs_stats *stats = *statsh;
991 unsigned int num_cpu;
992 unsigned int percpusize;
995 if (stats == NULL || stats->ls_num == 0)
999 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1002 num_cpu = num_possible_cpus();
1004 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1006 percpusize = L1_CACHE_ALIGN(percpusize);
1007 for (i = 0; i < num_cpu; i++)
1008 OBD_FREE(stats->ls_percpu[i], percpusize);
1009 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1012 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1014 struct lprocfs_counter *percpu_cntr;
1016 unsigned int num_cpu;
1018 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1020 for (i = 0; i < num_cpu; i++) {
1021 for (j = 0; j < stats->ls_num; j++) {
1022 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1023 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1024 percpu_cntr->lc_count = 0;
1025 percpu_cntr->lc_sum = 0;
1026 percpu_cntr->lc_min = LC_MIN_INIT;
1027 percpu_cntr->lc_max = 0;
1028 percpu_cntr->lc_sumsquare = 0;
1029 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1033 lprocfs_stats_unlock(stats);
1036 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1037 size_t len, loff_t *off)
1039 struct seq_file *seq = file->private_data;
1040 struct lprocfs_stats *stats = seq->private;
1042 lprocfs_clear_stats(stats);
1047 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1049 struct lprocfs_stats *stats = p->private;
1050 /* return 1st cpu location */
1051 return (*pos >= stats->ls_num) ? NULL :
1052 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1055 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1059 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1061 struct lprocfs_stats *stats = p->private;
1063 return (*pos >= stats->ls_num) ? NULL :
1064 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1067 /* seq file export of one lprocfs counter */
1068 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1070 struct lprocfs_stats *stats = p->private;
1071 struct lprocfs_counter *cntr = v;
1072 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
1074 unsigned int num_cpu;
1076 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1078 do_gettimeofday(&now);
1079 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1080 "snapshot_time", now.tv_sec, now.tv_usec);
1084 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1086 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1089 num_cpu = num_possible_cpus();
1091 for (i = 0; i < num_cpu; i++) {
1092 struct lprocfs_counter *percpu_cntr =
1093 &(stats->ls_percpu[i])->lp_cntr[idx];
1097 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1098 t.lc_count = percpu_cntr->lc_count;
1099 t.lc_sum = percpu_cntr->lc_sum;
1100 t.lc_min = percpu_cntr->lc_min;
1101 t.lc_max = percpu_cntr->lc_max;
1102 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1103 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1104 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1105 ret.lc_count += t.lc_count;
1106 ret.lc_sum += t.lc_sum;
1107 if (t.lc_min < ret.lc_min)
1108 ret.lc_min = t.lc_min;
1109 if (t.lc_max > ret.lc_max)
1110 ret.lc_max = t.lc_max;
1111 ret.lc_sumsquare += t.lc_sumsquare;
1114 if (ret.lc_count == 0)
1117 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1118 ret.lc_count, cntr->lc_units);
1122 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1123 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1124 ret.lc_min, ret.lc_max, ret.lc_sum);
1127 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1128 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1132 rc = seq_printf(p, "\n");
1134 return (rc < 0) ? rc : 0;
1137 struct seq_operations lprocfs_stats_seq_sops = {
1138 start: lprocfs_stats_seq_start,
1139 stop: lprocfs_stats_seq_stop,
1140 next: lprocfs_stats_seq_next,
1141 show: lprocfs_stats_seq_show,
1144 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1146 struct proc_dir_entry *dp = PDE(inode);
1147 struct seq_file *seq;
1150 LPROCFS_ENTRY_AND_CHECK(dp);
1151 rc = seq_open(file, &lprocfs_stats_seq_sops);
1156 seq = file->private_data;
1157 seq->private = dp->data;
1161 struct file_operations lprocfs_stats_seq_fops = {
1162 .owner = THIS_MODULE,
1163 .open = lprocfs_stats_seq_open,
1165 .write = lprocfs_stats_seq_write,
1166 .llseek = seq_lseek,
1167 .release = lprocfs_seq_release,
1170 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1171 struct lprocfs_stats *stats)
1173 struct proc_dir_entry *entry;
1174 LASSERT(root != NULL);
1176 entry = create_proc_entry(name, 0644, root);
1179 entry->proc_fops = &lprocfs_stats_seq_fops;
1180 entry->data = stats;
1184 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1185 unsigned conf, const char *name, const char *units)
1187 struct lprocfs_counter *c;
1189 unsigned int num_cpu;
1191 LASSERT(stats != NULL);
1193 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1195 for (i = 0; i < num_cpu; i++) {
1196 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1197 c->lc_config = conf;
1200 c->lc_min = LC_MIN_INIT;
1203 c->lc_units = units;
1206 lprocfs_stats_unlock(stats);
1208 EXPORT_SYMBOL(lprocfs_counter_init);
1210 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1212 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1213 LASSERT(coffset < stats->ls_num); \
1214 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1217 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1219 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1220 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1221 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1222 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1223 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1224 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1225 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1226 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1227 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1228 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1229 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1230 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1231 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1232 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1233 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1234 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1235 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1236 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1237 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1238 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1239 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1240 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1241 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1242 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1243 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1244 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1245 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1246 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1247 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1248 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1249 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1250 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1251 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1265 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1272 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1273 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1274 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1275 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1276 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1277 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1278 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1279 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1280 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1281 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1282 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1283 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1284 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1287 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1289 struct lprocfs_stats *stats;
1290 unsigned int num_stats;
1293 LASSERT(obd->obd_stats == NULL);
1294 LASSERT(obd->obd_proc_entry != NULL);
1295 LASSERT(obd->obd_cntr_base == 0);
1297 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1298 num_private_stats - 1 /* o_owner */;
1299 stats = lprocfs_alloc_stats(num_stats, 0);
1303 lprocfs_init_ops_stats(num_private_stats, stats);
1305 for (i = num_private_stats; i < num_stats; i++) {
1306 /* If this LBUGs, it is likely that an obd
1307 * operation was added to struct obd_ops in
1308 * <obd.h>, and that the corresponding line item
1309 * LPROCFS_OBD_OP_INIT(.., .., opname)
1310 * is missing from the list above. */
1311 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1312 "Missing obd_stat initializer obd_op "
1313 "operation at offset %d.\n", i - num_private_stats);
1315 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1317 lprocfs_free_stats(&stats);
1319 obd->obd_stats = stats;
1320 obd->obd_cntr_base = num_private_stats;
1325 void lprocfs_free_obd_stats(struct obd_device *obd)
1328 lprocfs_free_stats(&obd->obd_stats);
1331 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1333 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1334 LASSERT(coffset < stats->ls_num); \
1335 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1338 int lprocfs_alloc_md_stats(struct obd_device *obd,
1339 unsigned num_private_stats)
1341 struct lprocfs_stats *stats;
1342 unsigned int num_stats;
1345 LASSERT(obd->md_stats == NULL);
1346 LASSERT(obd->obd_proc_entry != NULL);
1347 LASSERT(obd->md_cntr_base == 0);
1349 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1351 stats = lprocfs_alloc_stats(num_stats, 0);
1355 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1356 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1357 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1358 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1359 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1360 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1361 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1362 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1363 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1364 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1365 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1366 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1367 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1368 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1369 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1370 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1371 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1372 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1373 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1374 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1375 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1376 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1377 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1378 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1379 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1380 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1381 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1382 LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1383 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1384 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1385 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1387 for (i = num_private_stats; i < num_stats; i++) {
1388 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1389 CERROR("Missing md_stat initializer md_op "
1390 "operation at offset %d. Aborting.\n",
1391 i - num_private_stats);
1395 rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1397 lprocfs_free_stats(&stats);
1399 obd->md_stats = stats;
1400 obd->md_cntr_base = num_private_stats;
1405 void lprocfs_free_md_stats(struct obd_device *obd)
1407 struct lprocfs_stats *stats = obd->md_stats;
1409 if (stats != NULL) {
1410 obd->md_stats = NULL;
1411 obd->md_cntr_base = 0;
1412 lprocfs_free_stats(&stats);
1416 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1418 lprocfs_counter_init(ldlm_stats,
1419 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1420 0, "ldlm_enqueue", "reqs");
1421 lprocfs_counter_init(ldlm_stats,
1422 LDLM_CONVERT - LDLM_FIRST_OPC,
1423 0, "ldlm_convert", "reqs");
1424 lprocfs_counter_init(ldlm_stats,
1425 LDLM_CANCEL - LDLM_FIRST_OPC,
1426 0, "ldlm_cancel", "reqs");
1427 lprocfs_counter_init(ldlm_stats,
1428 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1429 0, "ldlm_bl_callback", "reqs");
1430 lprocfs_counter_init(ldlm_stats,
1431 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1432 0, "ldlm_cp_callback", "reqs");
1433 lprocfs_counter_init(ldlm_stats,
1434 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1435 0, "ldlm_gl_callback", "reqs");
1438 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1439 int *eof, void *data)
1441 struct obd_export *exp = data;
1442 LASSERT(exp != NULL);
1444 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1447 struct exp_uuid_cb_data {
1455 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1456 int count, int *eof, int *len)
1458 cb_data->page = page;
1459 cb_data->count = count;
1464 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1466 struct obd_export *exp = (struct obd_export *)obj;
1467 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1469 if (exp->exp_nid_stats)
1470 *data->len += snprintf((data->page + *data->len),
1471 data->count, "%s\n",
1472 obd_uuid2str(&exp->exp_client_uuid));
1475 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1476 int *eof, void *data)
1478 struct nid_stat *stats = (struct nid_stat *)data;
1479 struct exp_uuid_cb_data cb_data;
1480 struct obd_device *obd = stats->nid_obd;
1485 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1486 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1487 lprocfs_exp_print_uuid, &cb_data);
1488 return (*cb_data.len);
1491 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1493 struct exp_uuid_cb_data *data = cb_data;
1494 struct obd_export *exp = obj;
1497 lh = exp->exp_lock_hash;
1500 *data->len += lustre_hash_debug_header(data->page,
1503 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1508 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1509 int *eof, void *data)
1511 struct nid_stat *stats = (struct nid_stat *)data;
1512 struct exp_uuid_cb_data cb_data;
1513 struct obd_device *obd = stats->nid_obd;
1518 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1520 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1521 lprocfs_exp_print_hash, &cb_data);
1522 return (*cb_data.len);
1525 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1526 int count, int *eof, void *data)
1529 return snprintf(page, count, "%s\n",
1530 "Write into this file to clear all nid stats and "
1531 "stale nid entries");
1533 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1535 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1537 struct nid_stat *stat = obj;
1540 /* object has only hash + iterate_all references.
1541 * add/delete blocked by hash bucket lock */
1542 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1543 if (stat->nid_exp_ref_count == 2) {
1544 hlist_del_init(&stat->nid_hash);
1545 stat->nid_exp_ref_count--;
1546 spin_lock(&stat->nid_obd->obd_nid_lock);
1547 list_move(&stat->nid_list, data);
1548 spin_unlock(&stat->nid_obd->obd_nid_lock);
1552 /* we has reference to object - only clear data*/
1553 if (stat->nid_stats)
1554 lprocfs_clear_stats(stat->nid_stats);
1556 if (stat->nid_brw_stats) {
1557 for (i = 0; i < BRW_LAST; i++)
1558 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1564 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1565 unsigned long count, void *data)
1567 struct obd_device *obd = (struct obd_device *)data;
1568 struct nid_stat *client_stat;
1569 CFS_LIST_HEAD(free_list);
1571 lustre_hash_for_each(obd->obd_nid_stats_hash,
1572 lprocfs_nid_stats_clear_write_cb, &free_list);
1574 while (!list_empty(&free_list)) {
1575 client_stat = list_entry(free_list.next, struct nid_stat,
1577 list_del_init(&client_stat->nid_list);
1578 lprocfs_free_client_stats(client_stat);
1583 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1585 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1587 struct nid_stat *new_stat, *old_stat;
1588 struct nid_stat_uuid *new_ns_uuid;
1589 struct obd_device *obd = NULL;
1590 cfs_proc_dir_entry_t *entry;
1596 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1597 !exp->exp_obd->obd_nid_stats_hash)
1600 /* not test against zero because eric say:
1601 * You may only test nid against another nid, or LNET_NID_ANY.
1602 * Anything else is nonsense.*/
1603 if (!nid || *nid == LNET_NID_ANY)
1608 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1610 OBD_ALLOC_PTR(new_stat);
1611 if (new_stat == NULL)
1614 OBD_ALLOC_PTR(new_ns_uuid);
1615 if (new_ns_uuid == NULL) {
1616 OBD_FREE_PTR(new_stat);
1619 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1620 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1621 sizeof(struct obd_uuid));
1623 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1624 new_stat->nid = *nid;
1625 new_stat->nid_obd = exp->exp_obd;
1626 new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1628 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1629 nid, &new_stat->nid_hash);
1630 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1631 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1633 /* Return -EALREADY here so that we know that the /proc
1634 * entry already has been created */
1635 if (old_stat != new_stat) {
1636 struct nid_stat_uuid *tmp_uuid;
1639 exp->exp_nid_stats = old_stat;
1640 /* We need to decrement the refcount if the uuid was
1641 * already in our list */
1642 spin_lock(&obd->obd_nid_lock);
1643 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1645 if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1646 &exp->exp_client_uuid)){
1648 --old_stat->nid_exp_ref_count;
1654 list_add(&new_ns_uuid->ns_uuid_list,
1655 &old_stat->nid_uuid_list);
1657 OBD_FREE_PTR(new_ns_uuid);
1659 spin_unlock(&obd->obd_nid_lock);
1661 GOTO(destroy_new, rc = -EALREADY);
1663 /* not found - create */
1664 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1665 obd->obd_proc_exports_entry,
1667 if (new_stat->nid_proc == NULL) {
1668 CERROR("Error making export directory for nid %s\n",
1669 libcfs_nid2str(*nid));
1670 GOTO(destroy_new_ns, rc = -ENOMEM);
1673 /* Add in uuid to our nid_stats list */
1674 spin_lock(&obd->obd_nid_lock);
1675 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1676 spin_unlock(&obd->obd_nid_lock);
1678 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1679 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1680 if (IS_ERR(entry)) {
1681 CWARN("Error adding the NID stats file\n");
1682 rc = PTR_ERR(entry);
1683 GOTO(destroy_new_ns, rc);
1686 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1687 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1688 if (IS_ERR(entry)) {
1689 CWARN("Error adding the hash file\n");
1690 lprocfs_remove(&new_stat->nid_proc);
1691 rc = PTR_ERR(entry);
1692 GOTO(destroy_new_ns, rc);
1695 exp->exp_nid_stats = new_stat;
1697 /* protect competitive add to list, not need locking on destroy */
1698 spin_lock(&obd->obd_nid_lock);
1699 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1700 spin_unlock(&obd->obd_nid_lock);
1705 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1706 OBD_FREE_PTR(new_ns_uuid);
1709 OBD_FREE_PTR(new_stat);
1713 int lprocfs_exp_cleanup(struct obd_export *exp)
1715 struct nid_stat *stat = exp->exp_nid_stats;
1716 struct nid_stat_uuid *cursor, *tmp;
1719 if(!stat || !exp->exp_obd)
1722 spin_lock(&exp->exp_obd->obd_nid_lock);
1723 list_for_each_entry_safe(cursor, tmp,
1724 &stat->nid_uuid_list,
1726 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1727 &exp->exp_client_uuid)) {
1729 list_del(&cursor->ns_uuid_list);
1730 OBD_FREE_PTR(cursor);
1731 --stat->nid_exp_ref_count;
1732 CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1733 stat->nid_exp_ref_count);
1737 spin_unlock(&exp->exp_obd->obd_nid_lock);
1739 CERROR("obd_export's client uuid %s are not found in its "
1740 "nid_stats list\n", exp->exp_client_uuid.uuid);
1742 exp->exp_nid_stats = NULL;
1743 lprocfs_free_md_stats(exp->exp_obd);
1748 int lprocfs_write_helper(const char *buffer, unsigned long count,
1751 return lprocfs_write_frac_helper(buffer, count, val, 1);
1754 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1757 char kernbuf[20], *end, *pbuf;
1759 if (count > (sizeof(kernbuf) - 1))
1762 if (copy_from_user(kernbuf, buffer, count))
1765 kernbuf[count] = '\0';
1772 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1776 if (end != NULL && *end == '.') {
1777 int temp_val, pow = 1;
1781 if (strlen(pbuf) > 5)
1782 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1784 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1787 for (i = 0; i < (end - pbuf); i++)
1790 *val += temp_val / pow;
1796 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1799 long decimal_val, frac_val;
1805 decimal_val = val / mult;
1806 prtn = snprintf(buffer, count, "%ld", decimal_val);
1807 frac_val = val % mult;
1809 if (prtn < (count - 4) && frac_val > 0) {
1811 int i, temp_mult = 1, frac_bits = 0;
1813 temp_frac = frac_val * 10;
1814 buffer[prtn++] = '.';
1815 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1816 /* only reserved 2 bits fraction */
1817 buffer[prtn++] ='0';
1822 * Need to think these cases :
1823 * 1. #echo x.00 > /proc/xxx output result : x
1824 * 2. #echo x.0x > /proc/xxx output result : x.0x
1825 * 3. #echo x.x0 > /proc/xxx output result : x.x
1826 * 4. #echo x.xx > /proc/xxx output result : x.xx
1827 * Only reserved 2 bits fraction.
1829 for (i = 0; i < (5 - prtn); i++)
1832 frac_bits = min((int)count - prtn, 3 - frac_bits);
1833 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1834 frac_val * temp_mult / mult);
1837 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1839 if (buffer[prtn] == '.') {
1846 buffer[prtn++] ='\n';
1850 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1852 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1855 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1856 __u64 *val, int mult)
1858 char kernbuf[22], *end, *pbuf;
1859 __u64 whole, frac = 0, units;
1860 unsigned frac_d = 1;
1862 if (count > (sizeof(kernbuf) - 1))
1865 if (copy_from_user(kernbuf, buffer, count))
1868 kernbuf[count] = '\0';
1875 whole = simple_strtoull(pbuf, &end, 10);
1879 if (end != NULL && *end == '.') {
1883 /* need to limit frac_d to a __u32 */
1884 if (strlen(pbuf) > 10)
1887 frac = simple_strtoull(pbuf, &end, 10);
1888 /* count decimal places */
1889 for (i = 0; i < (end - pbuf); i++)
1906 /* Specified units override the multiplier */
1908 mult = mult < 0 ? -units : units;
1911 do_div(frac, frac_d);
1912 *val = whole * mult + frac;
1916 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1917 struct file_operations *seq_fops, void *data)
1919 struct proc_dir_entry *entry;
1922 entry = create_proc_entry(name, mode, parent);
1925 entry->proc_fops = seq_fops;
1930 EXPORT_SYMBOL(lprocfs_seq_create);
1932 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1934 struct file_operations *seq_fops,
1937 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1938 mode, seq_fops, data));
1940 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1942 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1944 if (value >= OBD_HIST_MAX)
1945 value = OBD_HIST_MAX - 1;
1947 spin_lock(&oh->oh_lock);
1948 oh->oh_buckets[value]++;
1949 spin_unlock(&oh->oh_lock);
1951 EXPORT_SYMBOL(lprocfs_oh_tally);
1953 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1957 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1960 lprocfs_oh_tally(oh, val);
1962 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1964 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1966 unsigned long ret = 0;
1969 for (i = 0; i < OBD_HIST_MAX; i++)
1970 ret += oh->oh_buckets[i];
1973 EXPORT_SYMBOL(lprocfs_oh_sum);
1975 void lprocfs_oh_clear(struct obd_histogram *oh)
1977 spin_lock(&oh->oh_lock);
1978 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1979 spin_unlock(&oh->oh_lock);
1981 EXPORT_SYMBOL(lprocfs_oh_clear);
1983 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1984 int count, int *eof, void *data)
1986 struct obd_device *obd = data;
1992 c += lustre_hash_debug_header(page, count);
1993 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
1994 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
1995 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
1999 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2001 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2002 int count, int *eof, void *data)
2004 struct obd_device *obd = data;
2007 LASSERT(obd != NULL);
2008 LASSERT(count >= 0);
2010 /* Set start of user data returned to
2011 page + off since the user may have
2012 requested to read much smaller than
2013 what we need to read */
2014 *start = page + off;
2016 /* We know we are allocated a page here.
2017 Also we know that this function will
2018 not need to write more than a page
2019 so we can truncate at CFS_PAGE_SIZE. */
2020 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2022 /* Initialize the page */
2023 memset(page, 0, size);
2025 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2027 if (obd->obd_max_recoverable_clients == 0) {
2028 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2034 /* sampled unlocked, but really... */
2035 if (obd->obd_recovering == 0) {
2036 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2038 if (lprocfs_obd_snprintf(&page, size, &len,
2039 "recovery_start: %lu\n",
2040 obd->obd_recovery_start) <= 0)
2042 if (lprocfs_obd_snprintf(&page, size, &len,
2043 "recovery_duration: %lu\n",
2044 obd->obd_recovery_end -
2045 obd->obd_recovery_start) <= 0)
2047 /* Number of clients that have completed recovery */
2048 if (lprocfs_obd_snprintf(&page, size, &len,
2049 "completed_clients: %d/%d\n",
2050 obd->obd_max_recoverable_clients -
2051 obd->obd_recoverable_clients,
2052 obd->obd_max_recoverable_clients) <= 0)
2054 if (lprocfs_obd_snprintf(&page, size, &len,
2055 "replayed_requests: %d\n",
2056 obd->obd_replayed_requests) <= 0)
2058 if (lprocfs_obd_snprintf(&page, size, &len,
2059 "last_transno: "LPD64"\n",
2060 obd->obd_next_recovery_transno - 1)<=0)
2065 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2067 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2068 obd->obd_recovery_start) <= 0)
2070 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2071 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2072 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2074 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2075 obd->obd_connected_clients,
2076 obd->obd_max_recoverable_clients) <= 0)
2078 /* Number of clients that have completed recovery */
2079 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2080 obd->obd_max_recoverable_clients -
2081 obd->obd_recoverable_clients,
2082 obd->obd_max_recoverable_clients) <= 0)
2084 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2085 obd->obd_replayed_requests) <= 0)
2087 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2088 obd->obd_requests_queued_for_recovery) <= 0)
2091 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2092 obd->obd_next_recovery_transno) <= 0)
2098 return min(count, len - (int)off);
2100 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2102 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2103 int count, int *eof, void *data)
2105 struct obd_device *obd = data;
2106 LASSERT(obd != NULL);
2108 return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2110 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2112 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2113 unsigned long count, void *data)
2115 struct obd_device *obd = data;
2117 LASSERT(obd != NULL);
2119 rc = lprocfs_write_helper(buffer, count, &val);
2123 obd->obd_recovery_max_time = val;
2126 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2128 EXPORT_SYMBOL(lprocfs_register);
2129 EXPORT_SYMBOL(lprocfs_srch);
2130 EXPORT_SYMBOL(lprocfs_remove);
2131 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2132 EXPORT_SYMBOL(lprocfs_add_vars);
2133 EXPORT_SYMBOL(lprocfs_obd_setup);
2134 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2135 EXPORT_SYMBOL(lprocfs_add_simple);
2136 EXPORT_SYMBOL(lprocfs_add_symlink);
2137 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2138 EXPORT_SYMBOL(lprocfs_alloc_stats);
2139 EXPORT_SYMBOL(lprocfs_free_stats);
2140 EXPORT_SYMBOL(lprocfs_clear_stats);
2141 EXPORT_SYMBOL(lprocfs_register_stats);
2142 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2143 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2144 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2145 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2146 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2147 EXPORT_SYMBOL(lprocfs_exp_setup);
2148 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2150 EXPORT_SYMBOL(lprocfs_rd_u64);
2151 EXPORT_SYMBOL(lprocfs_rd_atomic);
2152 EXPORT_SYMBOL(lprocfs_wr_atomic);
2153 EXPORT_SYMBOL(lprocfs_rd_uint);
2154 EXPORT_SYMBOL(lprocfs_wr_uint);
2155 EXPORT_SYMBOL(lprocfs_rd_uuid);
2156 EXPORT_SYMBOL(lprocfs_rd_name);
2157 EXPORT_SYMBOL(lprocfs_rd_fstype);
2158 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2159 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2160 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2161 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2162 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2163 EXPORT_SYMBOL(lprocfs_rd_import);
2164 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2165 EXPORT_SYMBOL(lprocfs_rd_blksize);
2166 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2167 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2168 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2169 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2170 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2172 EXPORT_SYMBOL(lprocfs_write_helper);
2173 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2174 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2175 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2176 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);