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, brw_async);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1265 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1272 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1273 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1274 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1275 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1276 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1277 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1278 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1279 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1280 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1281 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1282 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1283 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1284 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1285 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1286 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1287 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1288 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1289 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1290 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1291 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1292 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1293 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1294 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1295 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1296 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1299 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1301 struct lprocfs_stats *stats;
1302 unsigned int num_stats;
1305 LASSERT(obd->obd_stats == NULL);
1306 LASSERT(obd->obd_proc_entry != NULL);
1307 LASSERT(obd->obd_cntr_base == 0);
1309 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1310 num_private_stats - 1 /* o_owner */;
1311 stats = lprocfs_alloc_stats(num_stats, 0);
1315 lprocfs_init_ops_stats(num_private_stats, stats);
1317 for (i = num_private_stats; i < num_stats; i++) {
1318 /* If this LBUGs, it is likely that an obd
1319 * operation was added to struct obd_ops in
1320 * <obd.h>, and that the corresponding line item
1321 * LPROCFS_OBD_OP_INIT(.., .., opname)
1322 * is missing from the list above. */
1323 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1324 "Missing obd_stat initializer obd_op "
1325 "operation at offset %d.\n", i - num_private_stats);
1327 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1329 lprocfs_free_stats(&stats);
1331 obd->obd_stats = stats;
1332 obd->obd_cntr_base = num_private_stats;
1337 void lprocfs_free_obd_stats(struct obd_device *obd)
1340 lprocfs_free_stats(&obd->obd_stats);
1343 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1345 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1346 LASSERT(coffset < stats->ls_num); \
1347 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1350 int lprocfs_alloc_md_stats(struct obd_device *obd,
1351 unsigned num_private_stats)
1353 struct lprocfs_stats *stats;
1354 unsigned int num_stats;
1357 LASSERT(obd->md_stats == NULL);
1358 LASSERT(obd->obd_proc_entry != NULL);
1359 LASSERT(obd->md_cntr_base == 0);
1361 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1363 stats = lprocfs_alloc_stats(num_stats, 0);
1367 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1368 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1369 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1370 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1371 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1372 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1373 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1374 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1375 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1376 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1377 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1378 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1379 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1380 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1381 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1382 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1383 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1384 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1385 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1386 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1387 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1388 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1389 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1390 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1391 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1392 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1393 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1394 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1395 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1396 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1398 for (i = num_private_stats; i < num_stats; i++) {
1399 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1400 CERROR("Missing md_stat initializer md_op "
1401 "operation at offset %d. Aborting.\n",
1402 i - num_private_stats);
1406 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1408 lprocfs_free_stats(&stats);
1410 obd->md_stats = stats;
1411 obd->md_cntr_base = num_private_stats;
1416 void lprocfs_free_md_stats(struct obd_device *obd)
1418 struct lprocfs_stats *stats = obd->md_stats;
1420 if (stats != NULL) {
1421 obd->md_stats = NULL;
1422 obd->md_cntr_base = 0;
1423 lprocfs_free_stats(&stats);
1427 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1429 lprocfs_counter_init(ldlm_stats,
1430 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1431 0, "ldlm_enqueue", "reqs");
1432 lprocfs_counter_init(ldlm_stats,
1433 LDLM_CONVERT - LDLM_FIRST_OPC,
1434 0, "ldlm_convert", "reqs");
1435 lprocfs_counter_init(ldlm_stats,
1436 LDLM_CANCEL - LDLM_FIRST_OPC,
1437 0, "ldlm_cancel", "reqs");
1438 lprocfs_counter_init(ldlm_stats,
1439 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1440 0, "ldlm_bl_callback", "reqs");
1441 lprocfs_counter_init(ldlm_stats,
1442 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1443 0, "ldlm_cp_callback", "reqs");
1444 lprocfs_counter_init(ldlm_stats,
1445 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1446 0, "ldlm_gl_callback", "reqs");
1449 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1450 int *eof, void *data)
1452 struct obd_export *exp = data;
1453 LASSERT(exp != NULL);
1455 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1458 struct exp_uuid_cb_data {
1466 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1467 int count, int *eof, int *len)
1469 cb_data->page = page;
1470 cb_data->count = count;
1475 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1477 struct obd_export *exp = (struct obd_export *)obj;
1478 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1480 if (exp->exp_nid_stats)
1481 *data->len += snprintf((data->page + *data->len),
1482 data->count, "%s\n",
1483 obd_uuid2str(&exp->exp_client_uuid));
1486 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1487 int *eof, void *data)
1489 struct nid_stat *stats = (struct nid_stat *)data;
1490 struct exp_uuid_cb_data cb_data;
1491 struct obd_device *obd = stats->nid_obd;
1496 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1497 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1498 lprocfs_exp_print_uuid, &cb_data);
1499 return (*cb_data.len);
1502 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1504 struct exp_uuid_cb_data *data = cb_data;
1505 struct obd_export *exp = obj;
1508 lh = exp->exp_lock_hash;
1511 *data->len += lustre_hash_debug_header(data->page,
1514 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1519 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1520 int *eof, void *data)
1522 struct nid_stat *stats = (struct nid_stat *)data;
1523 struct exp_uuid_cb_data cb_data;
1524 struct obd_device *obd = stats->nid_obd;
1529 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1531 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1532 lprocfs_exp_print_hash, &cb_data);
1533 return (*cb_data.len);
1536 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1537 int count, int *eof, void *data)
1540 return snprintf(page, count, "%s\n",
1541 "Write into this file to clear all nid stats and "
1542 "stale nid entries");
1544 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1546 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1548 struct nid_stat *stat = obj;
1551 /* object has only hash + iterate_all references.
1552 * add/delete blocked by hash bucket lock */
1553 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1554 if (stat->nid_exp_ref_count == 2) {
1555 hlist_del_init(&stat->nid_hash);
1556 stat->nid_exp_ref_count--;
1557 spin_lock(&stat->nid_obd->obd_nid_lock);
1558 list_move(&stat->nid_list, data);
1559 spin_unlock(&stat->nid_obd->obd_nid_lock);
1563 /* we has reference to object - only clear data*/
1564 if (stat->nid_stats)
1565 lprocfs_clear_stats(stat->nid_stats);
1567 if (stat->nid_brw_stats) {
1568 for (i = 0; i < BRW_LAST; i++)
1569 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1575 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1576 unsigned long count, void *data)
1578 struct obd_device *obd = (struct obd_device *)data;
1579 struct nid_stat *client_stat;
1580 CFS_LIST_HEAD(free_list);
1582 lustre_hash_for_each(obd->obd_nid_stats_hash,
1583 lprocfs_nid_stats_clear_write_cb, &free_list);
1585 while (!list_empty(&free_list)) {
1586 client_stat = list_entry(free_list.next, struct nid_stat,
1588 list_del_init(&client_stat->nid_list);
1589 lprocfs_free_client_stats(client_stat);
1594 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1596 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1598 struct nid_stat *new_stat, *old_stat;
1599 struct nid_stat_uuid *new_ns_uuid;
1600 struct obd_device *obd = NULL;
1601 cfs_proc_dir_entry_t *entry;
1607 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1608 !exp->exp_obd->obd_nid_stats_hash)
1611 /* not test against zero because eric say:
1612 * You may only test nid against another nid, or LNET_NID_ANY.
1613 * Anything else is nonsense.*/
1614 if (!nid || *nid == LNET_NID_ANY)
1619 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1621 OBD_ALLOC_PTR(new_stat);
1622 if (new_stat == NULL)
1625 OBD_ALLOC_PTR(new_ns_uuid);
1626 if (new_ns_uuid == NULL) {
1627 OBD_FREE_PTR(new_stat);
1630 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1631 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1632 sizeof(struct obd_uuid));
1634 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1635 new_stat->nid = *nid;
1636 new_stat->nid_obd = exp->exp_obd;
1637 new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1639 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1640 nid, &new_stat->nid_hash);
1641 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1642 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1644 /* Return -EALREADY here so that we know that the /proc
1645 * entry already has been created */
1646 if (old_stat != new_stat) {
1647 struct nid_stat_uuid *tmp_uuid;
1650 exp->exp_nid_stats = old_stat;
1651 /* We need to decrement the refcount if the uuid was
1652 * already in our list */
1653 spin_lock(&obd->obd_nid_lock);
1654 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1656 if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1657 &exp->exp_client_uuid)){
1659 --old_stat->nid_exp_ref_count;
1665 list_add(&new_ns_uuid->ns_uuid_list,
1666 &old_stat->nid_uuid_list);
1668 OBD_FREE_PTR(new_ns_uuid);
1670 spin_unlock(&obd->obd_nid_lock);
1672 GOTO(destroy_new, rc = -EALREADY);
1674 /* not found - create */
1675 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1676 obd->obd_proc_exports_entry,
1678 if (new_stat->nid_proc == NULL) {
1679 CERROR("Error making export directory for nid %s\n",
1680 libcfs_nid2str(*nid));
1681 GOTO(destroy_new_ns, rc = -ENOMEM);
1684 /* Add in uuid to our nid_stats list */
1685 spin_lock(&obd->obd_nid_lock);
1686 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1687 spin_unlock(&obd->obd_nid_lock);
1689 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1690 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1691 if (IS_ERR(entry)) {
1692 CWARN("Error adding the NID stats file\n");
1693 rc = PTR_ERR(entry);
1694 GOTO(destroy_new_ns, rc);
1697 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1698 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1699 if (IS_ERR(entry)) {
1700 CWARN("Error adding the hash file\n");
1701 lprocfs_remove(&new_stat->nid_proc);
1702 rc = PTR_ERR(entry);
1703 GOTO(destroy_new_ns, rc);
1706 exp->exp_nid_stats = new_stat;
1708 /* protect competitive add to list, not need locking on destroy */
1709 spin_lock(&obd->obd_nid_lock);
1710 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1711 spin_unlock(&obd->obd_nid_lock);
1716 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1717 OBD_FREE_PTR(new_ns_uuid);
1720 OBD_FREE_PTR(new_stat);
1724 int lprocfs_exp_cleanup(struct obd_export *exp)
1726 struct nid_stat *stat = exp->exp_nid_stats;
1727 struct nid_stat_uuid *cursor, *tmp;
1730 if(!stat || !exp->exp_obd)
1733 spin_lock(&exp->exp_obd->obd_nid_lock);
1734 list_for_each_entry_safe(cursor, tmp,
1735 &stat->nid_uuid_list,
1737 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1738 &exp->exp_client_uuid)) {
1740 list_del(&cursor->ns_uuid_list);
1741 OBD_FREE_PTR(cursor);
1742 --stat->nid_exp_ref_count;
1743 CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1744 stat->nid_exp_ref_count);
1748 spin_unlock(&exp->exp_obd->obd_nid_lock);
1750 CERROR("obd_export's client uuid %s are not found in its "
1751 "nid_stats list\n", exp->exp_client_uuid.uuid);
1753 exp->exp_nid_stats = NULL;
1754 lprocfs_free_md_stats(exp->exp_obd);
1759 int lprocfs_write_helper(const char *buffer, unsigned long count,
1762 return lprocfs_write_frac_helper(buffer, count, val, 1);
1765 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1768 char kernbuf[20], *end, *pbuf;
1770 if (count > (sizeof(kernbuf) - 1))
1773 if (copy_from_user(kernbuf, buffer, count))
1776 kernbuf[count] = '\0';
1783 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1787 if (end != NULL && *end == '.') {
1788 int temp_val, pow = 1;
1792 if (strlen(pbuf) > 5)
1793 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1795 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1798 for (i = 0; i < (end - pbuf); i++)
1801 *val += temp_val / pow;
1807 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1810 long decimal_val, frac_val;
1816 decimal_val = val / mult;
1817 prtn = snprintf(buffer, count, "%ld", decimal_val);
1818 frac_val = val % mult;
1820 if (prtn < (count - 4) && frac_val > 0) {
1822 int i, temp_mult = 1, frac_bits = 0;
1824 temp_frac = frac_val * 10;
1825 buffer[prtn++] = '.';
1826 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1827 /* only reserved 2 bits fraction */
1828 buffer[prtn++] ='0';
1833 * Need to think these cases :
1834 * 1. #echo x.00 > /proc/xxx output result : x
1835 * 2. #echo x.0x > /proc/xxx output result : x.0x
1836 * 3. #echo x.x0 > /proc/xxx output result : x.x
1837 * 4. #echo x.xx > /proc/xxx output result : x.xx
1838 * Only reserved 2 bits fraction.
1840 for (i = 0; i < (5 - prtn); i++)
1843 frac_bits = min((int)count - prtn, 3 - frac_bits);
1844 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1845 frac_val * temp_mult / mult);
1848 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1850 if (buffer[prtn] == '.') {
1857 buffer[prtn++] ='\n';
1861 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1863 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1866 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1867 __u64 *val, int mult)
1869 char kernbuf[22], *end, *pbuf;
1870 __u64 whole, frac = 0, units;
1871 unsigned frac_d = 1;
1873 if (count > (sizeof(kernbuf) - 1) )
1876 if (copy_from_user(kernbuf, buffer, count))
1879 kernbuf[count] = '\0';
1886 whole = simple_strtoull(pbuf, &end, 10);
1890 if (end != NULL && *end == '.') {
1894 /* need to limit frac_d to a __u32 */
1895 if (strlen(pbuf) > 10)
1898 frac = simple_strtoull(pbuf, &end, 10);
1899 /* count decimal places */
1900 for (i = 0; i < (end - pbuf); i++)
1917 /* Specified units override the multiplier */
1919 mult = mult < 0 ? -units : units;
1922 do_div(frac, frac_d);
1923 *val = whole * mult + frac;
1927 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1928 struct file_operations *seq_fops, void *data)
1930 struct proc_dir_entry *entry;
1933 entry = create_proc_entry(name, mode, parent);
1936 entry->proc_fops = seq_fops;
1941 EXPORT_SYMBOL(lprocfs_seq_create);
1943 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1945 struct file_operations *seq_fops,
1948 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1949 mode, seq_fops, data));
1951 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1953 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1955 if (value >= OBD_HIST_MAX)
1956 value = OBD_HIST_MAX - 1;
1958 spin_lock(&oh->oh_lock);
1959 oh->oh_buckets[value]++;
1960 spin_unlock(&oh->oh_lock);
1962 EXPORT_SYMBOL(lprocfs_oh_tally);
1964 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1968 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1971 lprocfs_oh_tally(oh, val);
1973 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1975 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1977 unsigned long ret = 0;
1980 for (i = 0; i < OBD_HIST_MAX; i++)
1981 ret += oh->oh_buckets[i];
1984 EXPORT_SYMBOL(lprocfs_oh_sum);
1986 void lprocfs_oh_clear(struct obd_histogram *oh)
1988 spin_lock(&oh->oh_lock);
1989 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1990 spin_unlock(&oh->oh_lock);
1992 EXPORT_SYMBOL(lprocfs_oh_clear);
1994 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1995 int count, int *eof, void *data)
1997 struct obd_device *obd = data;
2003 c += lustre_hash_debug_header(page, count);
2004 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2005 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2006 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2010 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2012 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2013 int count, int *eof, void *data)
2015 struct obd_device *obd = data;
2018 LASSERT(obd != NULL);
2019 LASSERT(count >= 0);
2021 /* Set start of user data returned to
2022 page + off since the user may have
2023 requested to read much smaller than
2024 what we need to read */
2025 *start = page + off;
2027 /* We know we are allocated a page here.
2028 Also we know that this function will
2029 not need to write more than a page
2030 so we can truncate at CFS_PAGE_SIZE. */
2031 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2033 /* Initialize the page */
2034 memset(page, 0, size);
2036 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2038 if (obd->obd_max_recoverable_clients == 0) {
2039 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2045 /* sampled unlocked, but really... */
2046 if (obd->obd_recovering == 0) {
2047 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2049 if (lprocfs_obd_snprintf(&page, size, &len,
2050 "recovery_start: %lu\n",
2051 obd->obd_recovery_start) <= 0)
2053 if (lprocfs_obd_snprintf(&page, size, &len,
2054 "recovery_duration: %lu\n",
2055 obd->obd_recovery_end -
2056 obd->obd_recovery_start) <= 0)
2058 /* Number of clients that have completed recovery */
2059 if (lprocfs_obd_snprintf(&page, size, &len,
2060 "completed_clients: %d/%d\n",
2061 obd->obd_max_recoverable_clients -
2062 obd->obd_recoverable_clients,
2063 obd->obd_max_recoverable_clients) <= 0)
2065 if (lprocfs_obd_snprintf(&page, size, &len,
2066 "replayed_requests: %d\n",
2067 obd->obd_replayed_requests) <= 0)
2069 if (lprocfs_obd_snprintf(&page, size, &len,
2070 "last_transno: "LPD64"\n",
2071 obd->obd_next_recovery_transno - 1)<=0)
2076 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2078 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2079 obd->obd_recovery_start) <= 0)
2081 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2082 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2083 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2085 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2086 obd->obd_connected_clients,
2087 obd->obd_max_recoverable_clients) <= 0)
2089 /* Number of clients that have completed recovery */
2090 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2091 obd->obd_max_recoverable_clients -
2092 obd->obd_recoverable_clients,
2093 obd->obd_max_recoverable_clients) <= 0)
2095 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2096 obd->obd_replayed_requests) <= 0)
2098 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2099 obd->obd_requests_queued_for_recovery) <= 0)
2102 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2103 obd->obd_next_recovery_transno) <= 0)
2109 return min(count, len - (int)off);
2111 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2113 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2114 int count, int *eof, void *data)
2116 struct obd_device *obd = data;
2117 LASSERT(obd != NULL);
2119 return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2121 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2123 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2124 unsigned long count, void *data)
2126 struct obd_device *obd = data;
2128 LASSERT(obd != NULL);
2130 rc = lprocfs_write_helper(buffer, count, &val);
2134 obd->obd_recovery_max_time = val;
2137 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2139 EXPORT_SYMBOL(lprocfs_register);
2140 EXPORT_SYMBOL(lprocfs_srch);
2141 EXPORT_SYMBOL(lprocfs_remove);
2142 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2143 EXPORT_SYMBOL(lprocfs_add_vars);
2144 EXPORT_SYMBOL(lprocfs_obd_setup);
2145 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2146 EXPORT_SYMBOL(lprocfs_add_simple);
2147 EXPORT_SYMBOL(lprocfs_add_symlink);
2148 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2149 EXPORT_SYMBOL(lprocfs_alloc_stats);
2150 EXPORT_SYMBOL(lprocfs_free_stats);
2151 EXPORT_SYMBOL(lprocfs_clear_stats);
2152 EXPORT_SYMBOL(lprocfs_register_stats);
2153 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2154 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2155 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2156 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2157 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2158 EXPORT_SYMBOL(lprocfs_exp_setup);
2159 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2161 EXPORT_SYMBOL(lprocfs_rd_u64);
2162 EXPORT_SYMBOL(lprocfs_rd_atomic);
2163 EXPORT_SYMBOL(lprocfs_wr_atomic);
2164 EXPORT_SYMBOL(lprocfs_rd_uint);
2165 EXPORT_SYMBOL(lprocfs_wr_uint);
2166 EXPORT_SYMBOL(lprocfs_rd_uuid);
2167 EXPORT_SYMBOL(lprocfs_rd_name);
2168 EXPORT_SYMBOL(lprocfs_rd_fstype);
2169 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2170 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2171 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2172 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2173 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2174 EXPORT_SYMBOL(lprocfs_rd_import);
2175 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2176 EXPORT_SYMBOL(lprocfs_rd_blksize);
2177 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2178 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2179 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2180 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2181 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2183 EXPORT_SYMBOL(lprocfs_write_helper);
2184 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2185 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2186 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2187 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);