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);
886 lprocfs_remove(&obd->obd_proc_entry);
890 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
892 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
893 client_stat->nid_proc, client_stat->nid_stats,
894 client_stat->nid_brw_stats);
896 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
897 client_stat->nid_exp_ref_count);
899 hlist_del_init(&client_stat->nid_hash);
901 if (client_stat->nid_proc)
902 lprocfs_remove(&client_stat->nid_proc);
904 if (client_stat->nid_stats)
905 lprocfs_free_stats(&client_stat->nid_stats);
907 if (client_stat->nid_brw_stats)
908 OBD_FREE_PTR(client_stat->nid_brw_stats);
910 if (client_stat->nid_ldlm_stats)
911 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
913 OBD_FREE_PTR(client_stat);
918 void lprocfs_free_per_client_stats(struct obd_device *obd)
920 struct nid_stat *stat;
923 /* we need extra list - because hash_exit called to early */
924 /* not need locking because all clients is died */
925 while(!list_empty(&obd->obd_nid_stats)) {
926 stat = list_entry(obd->obd_nid_stats.next,
927 struct nid_stat, nid_list);
928 list_del_init(&stat->nid_list);
929 lprocfs_free_client_stats(stat);
935 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
936 enum lprocfs_stats_flags flags)
938 struct lprocfs_stats *stats;
939 unsigned int percpusize;
941 unsigned int num_cpu;
946 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
949 num_cpu = num_possible_cpus();
951 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
955 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
956 stats->ls_flags = flags;
957 spin_lock_init(&stats->ls_lock);
958 /* Use this lock only if there are no percpu areas */
963 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
965 percpusize = L1_CACHE_ALIGN(percpusize);
967 for (i = 0; i < num_cpu; i++) {
968 OBD_ALLOC(stats->ls_percpu[i], percpusize);
969 if (stats->ls_percpu[i] == NULL) {
970 for (j = 0; j < i; j++) {
971 OBD_FREE(stats->ls_percpu[j], percpusize);
972 stats->ls_percpu[j] = NULL;
977 if (stats->ls_percpu[0] == NULL) {
978 OBD_FREE(stats, offsetof(typeof(*stats),
979 ls_percpu[num_cpu]));
987 void lprocfs_free_stats(struct lprocfs_stats **statsh)
989 struct lprocfs_stats *stats = *statsh;
990 unsigned int num_cpu;
991 unsigned int percpusize;
994 if (stats == NULL || stats->ls_num == 0)
998 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1001 num_cpu = num_possible_cpus();
1003 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1005 percpusize = L1_CACHE_ALIGN(percpusize);
1006 for (i = 0; i < num_cpu; i++)
1007 OBD_FREE(stats->ls_percpu[i], percpusize);
1008 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1011 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1013 struct lprocfs_counter *percpu_cntr;
1015 unsigned int num_cpu;
1017 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1019 for (i = 0; i < num_cpu; i++) {
1020 for (j = 0; j < stats->ls_num; j++) {
1021 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1022 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1023 percpu_cntr->lc_count = 0;
1024 percpu_cntr->lc_sum = 0;
1025 percpu_cntr->lc_min = LC_MIN_INIT;
1026 percpu_cntr->lc_max = 0;
1027 percpu_cntr->lc_sumsquare = 0;
1028 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1032 lprocfs_stats_unlock(stats);
1035 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1036 size_t len, loff_t *off)
1038 struct seq_file *seq = file->private_data;
1039 struct lprocfs_stats *stats = seq->private;
1041 lprocfs_clear_stats(stats);
1046 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1048 struct lprocfs_stats *stats = p->private;
1049 /* return 1st cpu location */
1050 return (*pos >= stats->ls_num) ? NULL :
1051 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1054 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1058 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1060 struct lprocfs_stats *stats = p->private;
1062 return (*pos >= stats->ls_num) ? NULL :
1063 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1066 /* seq file export of one lprocfs counter */
1067 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1069 struct lprocfs_stats *stats = p->private;
1070 struct lprocfs_counter *cntr = v;
1071 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
1073 unsigned int num_cpu;
1075 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1077 do_gettimeofday(&now);
1078 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1079 "snapshot_time", now.tv_sec, now.tv_usec);
1083 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1085 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1088 num_cpu = num_possible_cpus();
1090 for (i = 0; i < num_cpu; i++) {
1091 struct lprocfs_counter *percpu_cntr =
1092 &(stats->ls_percpu[i])->lp_cntr[idx];
1096 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1097 t.lc_count = percpu_cntr->lc_count;
1098 t.lc_sum = percpu_cntr->lc_sum;
1099 t.lc_min = percpu_cntr->lc_min;
1100 t.lc_max = percpu_cntr->lc_max;
1101 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1102 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1103 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1104 ret.lc_count += t.lc_count;
1105 ret.lc_sum += t.lc_sum;
1106 if (t.lc_min < ret.lc_min)
1107 ret.lc_min = t.lc_min;
1108 if (t.lc_max > ret.lc_max)
1109 ret.lc_max = t.lc_max;
1110 ret.lc_sumsquare += t.lc_sumsquare;
1113 if (ret.lc_count == 0)
1116 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1117 ret.lc_count, cntr->lc_units);
1121 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1122 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1123 ret.lc_min, ret.lc_max, ret.lc_sum);
1126 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1127 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1131 rc = seq_printf(p, "\n");
1133 return (rc < 0) ? rc : 0;
1136 struct seq_operations lprocfs_stats_seq_sops = {
1137 start: lprocfs_stats_seq_start,
1138 stop: lprocfs_stats_seq_stop,
1139 next: lprocfs_stats_seq_next,
1140 show: lprocfs_stats_seq_show,
1143 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1145 struct proc_dir_entry *dp = PDE(inode);
1146 struct seq_file *seq;
1149 LPROCFS_ENTRY_AND_CHECK(dp);
1150 rc = seq_open(file, &lprocfs_stats_seq_sops);
1155 seq = file->private_data;
1156 seq->private = dp->data;
1160 struct file_operations lprocfs_stats_seq_fops = {
1161 .owner = THIS_MODULE,
1162 .open = lprocfs_stats_seq_open,
1164 .write = lprocfs_stats_seq_write,
1165 .llseek = seq_lseek,
1166 .release = lprocfs_seq_release,
1169 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1170 struct lprocfs_stats *stats)
1172 struct proc_dir_entry *entry;
1173 LASSERT(root != NULL);
1175 entry = create_proc_entry(name, 0644, root);
1178 entry->proc_fops = &lprocfs_stats_seq_fops;
1179 entry->data = stats;
1183 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1184 unsigned conf, const char *name, const char *units)
1186 struct lprocfs_counter *c;
1188 unsigned int num_cpu;
1190 LASSERT(stats != NULL);
1192 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1194 for (i = 0; i < num_cpu; i++) {
1195 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1196 c->lc_config = conf;
1199 c->lc_min = LC_MIN_INIT;
1202 c->lc_units = units;
1205 lprocfs_stats_unlock(stats);
1207 EXPORT_SYMBOL(lprocfs_counter_init);
1209 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1211 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1212 LASSERT(coffset < stats->ls_num); \
1213 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1216 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1218 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1219 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1220 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1221 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1222 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1223 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1224 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1225 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1226 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1227 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1228 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1229 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1230 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1231 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1232 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1233 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1234 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1235 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1236 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1237 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1238 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1239 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1240 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1241 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1242 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1243 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1244 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1245 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1246 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1247 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1248 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1249 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1250 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1251 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1265 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1272 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1273 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1274 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1275 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1276 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1277 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1278 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1279 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1280 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1281 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1282 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1285 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1287 struct lprocfs_stats *stats;
1288 unsigned int num_stats;
1291 LASSERT(obd->obd_stats == NULL);
1292 LASSERT(obd->obd_proc_entry != NULL);
1293 LASSERT(obd->obd_cntr_base == 0);
1295 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1296 num_private_stats - 1 /* o_owner */;
1297 stats = lprocfs_alloc_stats(num_stats, 0);
1301 lprocfs_init_ops_stats(num_private_stats, stats);
1303 for (i = num_private_stats; i < num_stats; i++) {
1304 /* If this LBUGs, it is likely that an obd
1305 * operation was added to struct obd_ops in
1306 * <obd.h>, and that the corresponding line item
1307 * LPROCFS_OBD_OP_INIT(.., .., opname)
1308 * is missing from the list above. */
1309 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1310 "Missing obd_stat initializer obd_op "
1311 "operation at offset %d.\n", i - num_private_stats);
1313 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1315 lprocfs_free_stats(&stats);
1317 obd->obd_stats = stats;
1318 obd->obd_cntr_base = num_private_stats;
1323 void lprocfs_free_obd_stats(struct obd_device *obd)
1326 lprocfs_free_stats(&obd->obd_stats);
1329 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1331 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1332 LASSERT(coffset < stats->ls_num); \
1333 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1336 int lprocfs_alloc_md_stats(struct obd_device *obd,
1337 unsigned num_private_stats)
1339 struct lprocfs_stats *stats;
1340 unsigned int num_stats;
1343 LASSERT(obd->md_stats == NULL);
1344 LASSERT(obd->obd_proc_entry != NULL);
1345 LASSERT(obd->md_cntr_base == 0);
1347 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1349 stats = lprocfs_alloc_stats(num_stats, 0);
1353 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1354 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1355 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1356 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1357 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1358 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1359 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1360 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1361 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1362 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1363 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1364 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1365 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1366 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1367 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1368 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1369 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1370 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1371 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1372 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1373 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1374 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1375 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1376 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1377 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1378 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1379 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1380 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1381 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1382 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1384 for (i = num_private_stats; i < num_stats; i++) {
1385 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1386 CERROR("Missing md_stat initializer md_op "
1387 "operation at offset %d. Aborting.\n",
1388 i - num_private_stats);
1392 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1394 lprocfs_free_stats(&stats);
1396 obd->md_stats = stats;
1397 obd->md_cntr_base = num_private_stats;
1402 void lprocfs_free_md_stats(struct obd_device *obd)
1404 struct lprocfs_stats *stats = obd->md_stats;
1406 if (stats != NULL) {
1407 obd->md_stats = NULL;
1408 obd->md_cntr_base = 0;
1409 lprocfs_free_stats(&stats);
1413 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1415 lprocfs_counter_init(ldlm_stats,
1416 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1417 0, "ldlm_enqueue", "reqs");
1418 lprocfs_counter_init(ldlm_stats,
1419 LDLM_CONVERT - LDLM_FIRST_OPC,
1420 0, "ldlm_convert", "reqs");
1421 lprocfs_counter_init(ldlm_stats,
1422 LDLM_CANCEL - LDLM_FIRST_OPC,
1423 0, "ldlm_cancel", "reqs");
1424 lprocfs_counter_init(ldlm_stats,
1425 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1426 0, "ldlm_bl_callback", "reqs");
1427 lprocfs_counter_init(ldlm_stats,
1428 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1429 0, "ldlm_cp_callback", "reqs");
1430 lprocfs_counter_init(ldlm_stats,
1431 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1432 0, "ldlm_gl_callback", "reqs");
1435 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1436 int *eof, void *data)
1438 struct obd_export *exp = data;
1439 LASSERT(exp != NULL);
1441 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1444 struct exp_uuid_cb_data {
1452 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1453 int count, int *eof, int *len)
1455 cb_data->page = page;
1456 cb_data->count = count;
1461 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1463 struct obd_export *exp = (struct obd_export *)obj;
1464 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1466 if (exp->exp_nid_stats)
1467 *data->len += snprintf((data->page + *data->len),
1468 data->count, "%s\n",
1469 obd_uuid2str(&exp->exp_client_uuid));
1472 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1473 int *eof, void *data)
1475 struct nid_stat *stats = (struct nid_stat *)data;
1476 struct exp_uuid_cb_data cb_data;
1477 struct obd_device *obd = stats->nid_obd;
1482 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1483 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1484 lprocfs_exp_print_uuid, &cb_data);
1485 return (*cb_data.len);
1488 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1490 struct exp_uuid_cb_data *data = cb_data;
1491 struct obd_export *exp = obj;
1494 lh = exp->exp_lock_hash;
1497 *data->len += lustre_hash_debug_header(data->page,
1500 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1505 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1506 int *eof, void *data)
1508 struct nid_stat *stats = (struct nid_stat *)data;
1509 struct exp_uuid_cb_data cb_data;
1510 struct obd_device *obd = stats->nid_obd;
1515 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1517 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1518 lprocfs_exp_print_hash, &cb_data);
1519 return (*cb_data.len);
1522 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1523 int count, int *eof, void *data)
1526 return snprintf(page, count, "%s\n",
1527 "Write into this file to clear all nid stats and "
1528 "stale nid entries");
1530 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1532 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1534 struct nid_stat *stat = obj;
1537 /* object has only hash + iterate_all references.
1538 * add/delete blocked by hash bucket lock */
1539 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1540 if (stat->nid_exp_ref_count == 2) {
1541 hlist_del_init(&stat->nid_hash);
1542 stat->nid_exp_ref_count--;
1543 spin_lock(&stat->nid_obd->obd_nid_lock);
1544 list_move(&stat->nid_list, data);
1545 spin_unlock(&stat->nid_obd->obd_nid_lock);
1549 /* we has reference to object - only clear data*/
1550 if (stat->nid_stats)
1551 lprocfs_clear_stats(stat->nid_stats);
1553 if (stat->nid_brw_stats) {
1554 for (i = 0; i < BRW_LAST; i++)
1555 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1561 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1562 unsigned long count, void *data)
1564 struct obd_device *obd = (struct obd_device *)data;
1565 struct nid_stat *client_stat;
1566 CFS_LIST_HEAD(free_list);
1568 lustre_hash_for_each(obd->obd_nid_stats_hash,
1569 lprocfs_nid_stats_clear_write_cb, &free_list);
1571 while (!list_empty(&free_list)) {
1572 client_stat = list_entry(free_list.next, struct nid_stat,
1574 list_del_init(&client_stat->nid_list);
1575 lprocfs_free_client_stats(client_stat);
1580 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1582 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1584 struct nid_stat *new_stat, *old_stat;
1585 struct nid_stat_uuid *new_ns_uuid;
1586 struct obd_device *obd = NULL;
1587 cfs_proc_dir_entry_t *entry;
1593 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1594 !exp->exp_obd->obd_nid_stats_hash)
1597 /* not test against zero because eric say:
1598 * You may only test nid against another nid, or LNET_NID_ANY.
1599 * Anything else is nonsense.*/
1600 if (!nid || *nid == LNET_NID_ANY)
1605 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1607 OBD_ALLOC_PTR(new_stat);
1608 if (new_stat == NULL)
1611 OBD_ALLOC_PTR(new_ns_uuid);
1612 if (new_ns_uuid == NULL) {
1613 OBD_FREE_PTR(new_stat);
1616 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1617 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1618 sizeof(struct obd_uuid));
1620 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1621 new_stat->nid = *nid;
1622 new_stat->nid_obd = exp->exp_obd;
1623 new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1625 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1626 nid, &new_stat->nid_hash);
1627 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1628 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1630 /* Return -EALREADY here so that we know that the /proc
1631 * entry already has been created */
1632 if (old_stat != new_stat) {
1633 struct nid_stat_uuid *tmp_uuid;
1636 exp->exp_nid_stats = old_stat;
1637 /* We need to decrement the refcount if the uuid was
1638 * already in our list */
1639 spin_lock(&obd->obd_nid_lock);
1640 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1642 if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1643 &exp->exp_client_uuid)){
1645 --old_stat->nid_exp_ref_count;
1651 list_add(&new_ns_uuid->ns_uuid_list,
1652 &old_stat->nid_uuid_list);
1654 OBD_FREE_PTR(new_ns_uuid);
1656 spin_unlock(&obd->obd_nid_lock);
1658 GOTO(destroy_new, rc = -EALREADY);
1660 /* not found - create */
1661 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1662 obd->obd_proc_exports_entry,
1664 if (new_stat->nid_proc == NULL) {
1665 CERROR("Error making export directory for nid %s\n",
1666 libcfs_nid2str(*nid));
1667 GOTO(destroy_new_ns, rc = -ENOMEM);
1670 /* Add in uuid to our nid_stats list */
1671 spin_lock(&obd->obd_nid_lock);
1672 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1673 spin_unlock(&obd->obd_nid_lock);
1675 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1676 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1677 if (IS_ERR(entry)) {
1678 CWARN("Error adding the NID stats file\n");
1679 rc = PTR_ERR(entry);
1680 GOTO(destroy_new_ns, rc);
1683 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1684 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1685 if (IS_ERR(entry)) {
1686 CWARN("Error adding the hash file\n");
1687 lprocfs_remove(&new_stat->nid_proc);
1688 rc = PTR_ERR(entry);
1689 GOTO(destroy_new_ns, rc);
1692 exp->exp_nid_stats = new_stat;
1694 /* protect competitive add to list, not need locking on destroy */
1695 spin_lock(&obd->obd_nid_lock);
1696 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1697 spin_unlock(&obd->obd_nid_lock);
1702 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1703 OBD_FREE_PTR(new_ns_uuid);
1706 OBD_FREE_PTR(new_stat);
1710 int lprocfs_exp_cleanup(struct obd_export *exp)
1712 struct nid_stat *stat = exp->exp_nid_stats;
1713 struct nid_stat_uuid *cursor, *tmp;
1716 if(!stat || !exp->exp_obd)
1719 spin_lock(&exp->exp_obd->obd_nid_lock);
1720 list_for_each_entry_safe(cursor, tmp,
1721 &stat->nid_uuid_list,
1723 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1724 &exp->exp_client_uuid)) {
1726 list_del(&cursor->ns_uuid_list);
1727 OBD_FREE_PTR(cursor);
1728 --stat->nid_exp_ref_count;
1729 CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1730 stat->nid_exp_ref_count);
1734 spin_unlock(&exp->exp_obd->obd_nid_lock);
1736 CERROR("obd_export's client uuid %s are not found in its "
1737 "nid_stats list\n", exp->exp_client_uuid.uuid);
1739 exp->exp_nid_stats = NULL;
1740 lprocfs_free_md_stats(exp->exp_obd);
1745 int lprocfs_write_helper(const char *buffer, unsigned long count,
1748 return lprocfs_write_frac_helper(buffer, count, val, 1);
1751 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1754 char kernbuf[20], *end, *pbuf;
1756 if (count > (sizeof(kernbuf) - 1))
1759 if (copy_from_user(kernbuf, buffer, count))
1762 kernbuf[count] = '\0';
1769 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1773 if (end != NULL && *end == '.') {
1774 int temp_val, pow = 1;
1778 if (strlen(pbuf) > 5)
1779 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1781 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1784 for (i = 0; i < (end - pbuf); i++)
1787 *val += temp_val / pow;
1793 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1796 long decimal_val, frac_val;
1802 decimal_val = val / mult;
1803 prtn = snprintf(buffer, count, "%ld", decimal_val);
1804 frac_val = val % mult;
1806 if (prtn < (count - 4) && frac_val > 0) {
1808 int i, temp_mult = 1, frac_bits = 0;
1810 temp_frac = frac_val * 10;
1811 buffer[prtn++] = '.';
1812 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1813 /* only reserved 2 bits fraction */
1814 buffer[prtn++] ='0';
1819 * Need to think these cases :
1820 * 1. #echo x.00 > /proc/xxx output result : x
1821 * 2. #echo x.0x > /proc/xxx output result : x.0x
1822 * 3. #echo x.x0 > /proc/xxx output result : x.x
1823 * 4. #echo x.xx > /proc/xxx output result : x.xx
1824 * Only reserved 2 bits fraction.
1826 for (i = 0; i < (5 - prtn); i++)
1829 frac_bits = min((int)count - prtn, 3 - frac_bits);
1830 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1831 frac_val * temp_mult / mult);
1834 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1836 if (buffer[prtn] == '.') {
1843 buffer[prtn++] ='\n';
1847 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1849 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1852 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1853 __u64 *val, int mult)
1855 char kernbuf[22], *end, *pbuf;
1856 __u64 whole, frac = 0, units;
1857 unsigned frac_d = 1;
1859 if (count > (sizeof(kernbuf) - 1) )
1862 if (copy_from_user(kernbuf, buffer, count))
1865 kernbuf[count] = '\0';
1872 whole = simple_strtoull(pbuf, &end, 10);
1876 if (end != NULL && *end == '.') {
1880 /* need to limit frac_d to a __u32 */
1881 if (strlen(pbuf) > 10)
1884 frac = simple_strtoull(pbuf, &end, 10);
1885 /* count decimal places */
1886 for (i = 0; i < (end - pbuf); i++)
1903 /* Specified units override the multiplier */
1905 mult = mult < 0 ? -units : units;
1908 do_div(frac, frac_d);
1909 *val = whole * mult + frac;
1913 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1914 struct file_operations *seq_fops, void *data)
1916 struct proc_dir_entry *entry;
1919 entry = create_proc_entry(name, mode, parent);
1922 entry->proc_fops = seq_fops;
1927 EXPORT_SYMBOL(lprocfs_seq_create);
1929 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1931 struct file_operations *seq_fops,
1934 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1935 mode, seq_fops, data));
1937 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1939 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1941 if (value >= OBD_HIST_MAX)
1942 value = OBD_HIST_MAX - 1;
1944 spin_lock(&oh->oh_lock);
1945 oh->oh_buckets[value]++;
1946 spin_unlock(&oh->oh_lock);
1948 EXPORT_SYMBOL(lprocfs_oh_tally);
1950 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1954 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1957 lprocfs_oh_tally(oh, val);
1959 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1961 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1963 unsigned long ret = 0;
1966 for (i = 0; i < OBD_HIST_MAX; i++)
1967 ret += oh->oh_buckets[i];
1970 EXPORT_SYMBOL(lprocfs_oh_sum);
1972 void lprocfs_oh_clear(struct obd_histogram *oh)
1974 spin_lock(&oh->oh_lock);
1975 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1976 spin_unlock(&oh->oh_lock);
1978 EXPORT_SYMBOL(lprocfs_oh_clear);
1980 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1981 int count, int *eof, void *data)
1983 struct obd_device *obd = data;
1989 c += lustre_hash_debug_header(page, count);
1990 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
1991 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
1992 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
1996 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
1998 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1999 int count, int *eof, void *data)
2001 struct obd_device *obd = data;
2004 LASSERT(obd != NULL);
2005 LASSERT(count >= 0);
2007 /* Set start of user data returned to
2008 page + off since the user may have
2009 requested to read much smaller than
2010 what we need to read */
2011 *start = page + off;
2013 /* We know we are allocated a page here.
2014 Also we know that this function will
2015 not need to write more than a page
2016 so we can truncate at CFS_PAGE_SIZE. */
2017 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2019 /* Initialize the page */
2020 memset(page, 0, size);
2022 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2024 if (obd->obd_max_recoverable_clients == 0) {
2025 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2031 /* sampled unlocked, but really... */
2032 if (obd->obd_recovering == 0) {
2033 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2035 if (lprocfs_obd_snprintf(&page, size, &len,
2036 "recovery_start: %lu\n",
2037 obd->obd_recovery_start) <= 0)
2039 if (lprocfs_obd_snprintf(&page, size, &len,
2040 "recovery_duration: %lu\n",
2041 obd->obd_recovery_end -
2042 obd->obd_recovery_start) <= 0)
2044 /* Number of clients that have completed recovery */
2045 if (lprocfs_obd_snprintf(&page, size, &len,
2046 "completed_clients: %d/%d\n",
2047 obd->obd_max_recoverable_clients -
2048 obd->obd_recoverable_clients,
2049 obd->obd_max_recoverable_clients) <= 0)
2051 if (lprocfs_obd_snprintf(&page, size, &len,
2052 "replayed_requests: %d\n",
2053 obd->obd_replayed_requests) <= 0)
2055 if (lprocfs_obd_snprintf(&page, size, &len,
2056 "last_transno: "LPD64"\n",
2057 obd->obd_next_recovery_transno - 1)<=0)
2062 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2064 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2065 obd->obd_recovery_start) <= 0)
2067 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2068 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2069 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2071 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2072 obd->obd_connected_clients,
2073 obd->obd_max_recoverable_clients) <= 0)
2075 /* Number of clients that have completed recovery */
2076 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2077 obd->obd_max_recoverable_clients -
2078 obd->obd_recoverable_clients,
2079 obd->obd_max_recoverable_clients) <= 0)
2081 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2082 obd->obd_replayed_requests) <= 0)
2084 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2085 obd->obd_requests_queued_for_recovery) <= 0)
2088 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2089 obd->obd_next_recovery_transno) <= 0)
2095 return min(count, len - (int)off);
2097 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2099 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2100 int count, int *eof, void *data)
2102 struct obd_device *obd = data;
2103 LASSERT(obd != NULL);
2105 return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2107 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2109 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2110 unsigned long count, void *data)
2112 struct obd_device *obd = data;
2114 LASSERT(obd != NULL);
2116 rc = lprocfs_write_helper(buffer, count, &val);
2120 obd->obd_recovery_max_time = val;
2123 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2125 EXPORT_SYMBOL(lprocfs_register);
2126 EXPORT_SYMBOL(lprocfs_srch);
2127 EXPORT_SYMBOL(lprocfs_remove);
2128 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2129 EXPORT_SYMBOL(lprocfs_add_vars);
2130 EXPORT_SYMBOL(lprocfs_obd_setup);
2131 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2132 EXPORT_SYMBOL(lprocfs_add_simple);
2133 EXPORT_SYMBOL(lprocfs_add_symlink);
2134 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2135 EXPORT_SYMBOL(lprocfs_alloc_stats);
2136 EXPORT_SYMBOL(lprocfs_free_stats);
2137 EXPORT_SYMBOL(lprocfs_clear_stats);
2138 EXPORT_SYMBOL(lprocfs_register_stats);
2139 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2140 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2141 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2142 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2143 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2144 EXPORT_SYMBOL(lprocfs_exp_setup);
2145 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2147 EXPORT_SYMBOL(lprocfs_rd_u64);
2148 EXPORT_SYMBOL(lprocfs_rd_atomic);
2149 EXPORT_SYMBOL(lprocfs_wr_atomic);
2150 EXPORT_SYMBOL(lprocfs_rd_uint);
2151 EXPORT_SYMBOL(lprocfs_wr_uint);
2152 EXPORT_SYMBOL(lprocfs_rd_uuid);
2153 EXPORT_SYMBOL(lprocfs_rd_name);
2154 EXPORT_SYMBOL(lprocfs_rd_fstype);
2155 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2156 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2157 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2158 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2159 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2160 EXPORT_SYMBOL(lprocfs_rd_import);
2161 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2162 EXPORT_SYMBOL(lprocfs_rd_blksize);
2163 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2164 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2165 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2166 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2167 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2169 EXPORT_SYMBOL(lprocfs_write_helper);
2170 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2171 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2172 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2173 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);