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 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf, size_t size,
148 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
149 char *page, *start = NULL;
150 int rc = 0, eof = 1, count;
152 if (*ppos >= PAGE_SIZE)
155 page = (char *)__get_free_page(GFP_KERNEL);
160 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
161 if (!dp->deleted && dp->read_proc)
162 rc = dp->read_proc(page, &start, *ppos, PAGE_SIZE,
168 /* for lustre proc read, the read count must be less than PAGE_SIZE */
177 start = page + *ppos;
178 } else if (start < page) {
182 count = (rc < size) ? rc : size;
183 if (copy_to_user(buf, start, count)) {
190 free_page((unsigned long)page);
194 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
195 size_t size, loff_t *ppos)
197 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
201 if (!dp->deleted && dp->write_proc)
202 rc = dp->write_proc(f, buf, size, dp->data);
207 static struct file_operations lprocfs_generic_fops = {
208 .owner = THIS_MODULE,
209 .read = lprocfs_fops_read,
210 .write = lprocfs_fops_write,
213 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
215 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
216 struct obd_device *obd = dp->data;
218 atomic_inc(&obd->obd_evict_inprogress);
223 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
225 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
226 struct obd_device *obd = dp->data;
228 atomic_dec(&obd->obd_evict_inprogress);
229 wake_up(&obd->obd_evict_inprogress_waitq);
234 struct file_operations lprocfs_evict_client_fops = {
235 .owner = THIS_MODULE,
236 .read = lprocfs_fops_read,
237 .write = lprocfs_fops_write,
238 .open = lprocfs_evict_client_open,
239 .release = lprocfs_evict_client_release,
241 EXPORT_SYMBOL(lprocfs_evict_client_fops);
246 * \param root [in] The parent proc entry on which new entry will be added.
247 * \param list [in] Array of proc entries to be added.
248 * \param data [in] The argument to be passed when entries read/write routines
249 * are called through /proc file.
251 * \retval 0 on success
254 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
257 if (root == NULL || list == NULL)
260 while (list->name != NULL) {
261 struct proc_dir_entry *cur_root, *proc;
262 char *pathcopy, *cur, *next, pathbuf[64];
263 int pathsize = strlen(list->name) + 1;
268 /* need copy of path for strsep */
269 if (strlen(list->name) > sizeof(pathbuf) - 1) {
270 OBD_ALLOC(pathcopy, pathsize);
271 if (pathcopy == NULL)
278 strcpy(pathcopy, list->name);
280 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
281 if (*cur =='\0') /* skip double/trailing "/" */
284 proc = lprocfs_srch(cur_root, cur);
285 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
286 cur_root->name, cur, next,
287 (proc ? "exists" : "new"));
289 cur_root = (proc ? proc :
290 proc_mkdir(cur, cur_root));
291 } else if (proc == NULL) {
293 if (list->proc_mode != 0000) {
294 mode = list->proc_mode;
298 if (list->write_fptr)
301 proc = create_proc_entry(cur, mode, cur_root);
305 if (pathcopy != pathbuf)
306 OBD_FREE(pathcopy, pathsize);
308 if (cur_root == NULL || proc == NULL) {
309 CERROR("LprocFS: No memory to create /proc entry %s",
315 proc->proc_fops = list->fops;
317 proc->proc_fops = &lprocfs_generic_fops;
318 proc->read_proc = list->read_fptr;
319 proc->write_proc = list->write_fptr;
320 proc->data = (list->data ? list->data : data);
326 void lprocfs_remove(struct proc_dir_entry **rooth)
328 struct proc_dir_entry *root = *rooth;
329 struct proc_dir_entry *temp = root;
330 struct proc_dir_entry *rm_entry;
331 struct proc_dir_entry *parent;
337 parent = root->parent;
338 LASSERT(parent != NULL);
339 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
342 while (temp->subdir != NULL)
348 /* Memory corruption once caused this to fail, and
349 without this LASSERT we would loop here forever. */
350 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
351 "0x%p %s/%s len %d\n", rm_entry, temp->name,
352 rm_entry->name, (int)strlen(rm_entry->name));
354 /* Now, the rm_entry->deleted flags is protected
355 * by _lprocfs_lock. */
356 rm_entry->data = NULL;
357 remove_proc_entry(rm_entry->name, temp);
361 LPROCFS_WRITE_EXIT();
364 struct proc_dir_entry *lprocfs_register(const char *name,
365 struct proc_dir_entry *parent,
366 struct lprocfs_vars *list, void *data)
368 struct proc_dir_entry *newchild;
370 newchild = lprocfs_srch(parent, name);
371 if (newchild != NULL) {
372 CERROR(" Lproc: Attempting to register %s more than once \n",
374 return ERR_PTR(-EALREADY);
377 newchild = proc_mkdir(name, parent);
378 if (newchild != NULL && list != NULL) {
379 int rc = lprocfs_add_vars(newchild, list, data);
381 lprocfs_remove(&newchild);
388 /* Generic callbacks */
389 int lprocfs_rd_uint(char *page, char **start, off_t off,
390 int count, int *eof, void *data)
392 unsigned int *temp = (unsigned int *)data;
393 return snprintf(page, count, "%u\n", *temp);
396 int lprocfs_wr_uint(struct file *file, const char *buffer,
397 unsigned long count, void *data)
400 char dummy[MAX_STRING_SIZE + 1] = { '\0' }, *end;
403 if (count >= sizeof(dummy) || count == 0)
406 if (copy_from_user(dummy, buffer, count))
409 tmp = simple_strtoul(dummy, &end, 0);
413 *p = (unsigned int)tmp;
417 int lprocfs_rd_u64(char *page, char **start, off_t off,
418 int count, int *eof, void *data)
420 LASSERT(data != NULL);
422 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
425 int lprocfs_rd_atomic(char *page, char **start, off_t off,
426 int count, int *eof, void *data)
428 atomic_t *atom = (atomic_t *)data;
429 LASSERT(atom != NULL);
431 return snprintf(page, count, "%d\n", atomic_read(atom));
434 int lprocfs_wr_atomic(struct file *file, const char *buffer,
435 unsigned long count, void *data)
437 atomic_t *atm = data;
441 rc = lprocfs_write_helper(buffer, count, &val);
448 atomic_set(atm, val);
452 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
453 int *eof, void *data)
455 struct obd_device *obd = (struct obd_device*)data;
457 LASSERT(obd != NULL);
459 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
462 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
463 int *eof, void* data)
465 struct obd_device *dev = (struct obd_device *)data;
467 LASSERT(dev != NULL);
468 LASSERT(dev->obd_name != NULL);
470 return snprintf(page, count, "%s\n", dev->obd_name);
473 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
476 struct obd_device *obd = (struct obd_device *)data;
478 LASSERT(obd != NULL);
479 LASSERT(obd->obd_fsops != NULL);
480 LASSERT(obd->obd_fsops->fs_type != NULL);
481 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
484 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
485 int *eof, void *data)
487 struct obd_statfs osfs;
488 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
492 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
497 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
498 int *eof, void *data)
500 struct obd_statfs osfs;
501 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
504 __u32 blk_size = osfs.os_bsize >> 10;
505 __u64 result = osfs.os_blocks;
507 while (blk_size >>= 1)
511 rc = snprintf(page, count, LPU64"\n", result);
516 int lprocfs_rd_kbytesfree(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_bfree;
526 while (blk_size >>= 1)
530 rc = snprintf(page, count, LPU64"\n", result);
535 int lprocfs_rd_kbytesavail(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_bavail;
545 while (blk_size >>= 1)
549 rc = snprintf(page, count, LPU64"\n", result);
554 int lprocfs_rd_filestotal(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,
562 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
568 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
569 int *eof, void *data)
571 struct obd_statfs osfs;
572 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
576 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
581 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
582 int *eof, void *data)
584 struct obd_device *obd = (struct obd_device *)data;
585 struct obd_import *imp;
586 char *imp_state_name = NULL;
589 LASSERT(obd != NULL);
590 LPROCFS_CLIMP_CHECK(obd);
591 imp = obd->u.cli.cl_import;
592 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
594 rc = snprintf(page, count, "%s\t%s%s\n",
595 obd2cli_tgt(obd), imp_state_name,
596 imp->imp_deactive ? "\tDEACTIVATED" : "");
598 LPROCFS_CLIMP_EXIT(obd);
602 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
603 int *eof, void *data)
605 struct obd_device *obd = (struct obd_device*)data;
606 struct ptlrpc_connection *conn;
609 LASSERT(obd != NULL);
610 LPROCFS_CLIMP_CHECK(obd);
611 conn = obd->u.cli.cl_import->imp_connection;
612 LASSERT(conn != NULL);
614 rc = snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
616 LPROCFS_CLIMP_EXIT(obd);
620 #define flag2str(flag) \
621 if (imp->imp_##flag && max - len > 0) \
622 len += snprintf(str + len, max - len, " " #flag);
625 * Append a space separated list of current set flags to str.
627 static int obd_import_flags2str(struct obd_import *imp, char *str,
632 if (imp->imp_obd->obd_no_recov)
633 len += snprintf(str, max - len, " no_recov");
637 flag2str(replayable);
640 flag2str(last_recon);
645 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
646 int *eof, void *data)
648 struct obd_device *obd = (struct obd_device *)data;
649 struct obd_import *imp;
650 char *imp_state_name = NULL;
653 LASSERT(obd != NULL);
654 LPROCFS_CLIMP_CHECK(obd);
655 imp = obd->u.cli.cl_import;
656 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
659 rc = snprintf(page, count,
664 " unregistering: %u\n"
668 " last_replay_transno: "LPU64"\n"
669 " peer_committed_transno: "LPU64"\n"
670 " last_trasno_checked: "LPU64"\n"
673 obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
675 atomic_read(&imp->imp_inflight),
676 atomic_read(&imp->imp_unregistering),
679 atomic_read(&imp->imp_inval_count),
680 imp->imp_last_replay_transno,
681 imp->imp_peer_committed_transno,
682 imp->imp_last_transno_checked);
683 rc += obd_import_flags2str(imp, page + rc, count - rc);
684 rc += snprintf(page+rc, count - rc, "\n");
685 LPROCFS_CLIMP_EXIT(obd);
689 int lprocfs_at_hist_helper(char *page, int count, int rc,
690 struct adaptive_timeout *at)
693 for (i = 0; i < AT_BINS; i++)
694 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
695 rc += snprintf(page + rc, count - rc, "\n");
699 /* See also ptlrpc_lprocfs_rd_timeouts */
700 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
701 int *eof, void *data)
703 struct obd_device *obd = (struct obd_device *)data;
704 struct obd_import *imp;
705 unsigned int cur, worst;
710 LASSERT(obd != NULL);
711 LPROCFS_CLIMP_CHECK(obd);
712 imp = obd->u.cli.cl_import;
715 now = cfs_time_current_sec();
717 /* Some network health info for kicks */
718 s2dhms(&ts, now - imp->imp_last_reply_time);
719 rc += snprintf(page + rc, count - rc,
720 "%-10s : %ld, "DHMS_FMT" ago\n",
721 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
723 cur = at_get(&imp->imp_at.iat_net_latency);
724 worst = imp->imp_at.iat_net_latency.at_worst_ever;
725 worstt = imp->imp_at.iat_net_latency.at_worst_time;
726 s2dhms(&ts, now - worstt);
727 rc += snprintf(page + rc, count - rc,
728 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
729 "network", cur, worst, worstt, DHMS_VARS(&ts));
730 rc = lprocfs_at_hist_helper(page, count, rc,
731 &imp->imp_at.iat_net_latency);
733 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
734 if (imp->imp_at.iat_portal[i] == 0)
736 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
737 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
738 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
739 s2dhms(&ts, now - worstt);
740 rc += snprintf(page + rc, count - rc,
741 "portal %-2d : cur %3u worst %3u (at %ld, "
742 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
743 cur, worst, worstt, DHMS_VARS(&ts));
744 rc = lprocfs_at_hist_helper(page, count, rc,
745 &imp->imp_at.iat_service_estimate[i]);
748 LPROCFS_CLIMP_EXIT(obd);
752 /* see OBD_CONNECT_* */
753 static const char *obd_connect_names[] = {
780 "mds_mds_connection",
783 "alt_checksum_algorithm",
790 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
791 int count, int *eof, void *data)
793 struct obd_device *obd = data;
794 __u64 mask = 1, flags;
797 LPROCFS_CLIMP_CHECK(obd);
798 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
799 ret = snprintf(page, count, "flags="LPX64"\n", flags);
800 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
802 ret += snprintf(page + ret, count - ret, "%s\n",
803 obd_connect_names[i]);
805 if (flags & ~(mask - 1))
806 ret += snprintf(page + ret, count - ret,
807 "unknown flags "LPX64"\n", flags & ~(mask - 1));
809 LPROCFS_CLIMP_EXIT(obd);
812 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
814 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
815 int *eof, void *data)
817 struct obd_device *obd = (struct obd_device*)data;
819 LASSERT(obd != NULL);
821 return snprintf(page, count, "%u\n", obd->obd_num_exports);
824 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
825 int *eof, void *data)
827 struct obd_type *class = (struct obd_type*) data;
829 LASSERT(class != NULL);
831 return snprintf(page, count, "%d\n", class->typ_refcnt);
834 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
838 LASSERT(obd != NULL);
839 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
840 LASSERT(obd->obd_type->typ_procroot != NULL);
842 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
843 obd->obd_type->typ_procroot,
845 if (IS_ERR(obd->obd_proc_entry)) {
846 rc = PTR_ERR(obd->obd_proc_entry);
847 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
848 obd->obd_proc_entry = NULL;
853 int lprocfs_obd_cleanup(struct obd_device *obd)
857 if (obd->obd_proc_exports_entry) {
858 /* Should be no exports left */
859 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
860 lprocfs_remove(&obd->obd_proc_exports_entry);
862 lprocfs_remove(&obd->obd_proc_entry);
866 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
868 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
869 client_stat->nid_proc, client_stat->nid_stats,
870 client_stat->nid_brw_stats);
872 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
873 client_stat->nid_exp_ref_count);
875 hlist_del_init(&client_stat->nid_hash);
877 if (client_stat->nid_proc)
878 lprocfs_remove(&client_stat->nid_proc);
880 if (client_stat->nid_stats)
881 lprocfs_free_stats(&client_stat->nid_stats);
883 if (client_stat->nid_brw_stats)
884 OBD_FREE_PTR(client_stat->nid_brw_stats);
886 if (client_stat->nid_ldlm_stats)
887 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
889 OBD_FREE_PTR(client_stat);
894 void lprocfs_free_per_client_stats(struct obd_device *obd)
896 struct nid_stat *stat;
899 /* we need extra list - because hash_exit called to early */
900 /* not need locking because all clients is died */
901 while(!list_empty(&obd->obd_nid_stats)) {
902 stat = list_entry(obd->obd_nid_stats.next,
903 struct nid_stat, nid_list);
904 list_del_init(&stat->nid_list);
905 lprocfs_free_client_stats(stat);
911 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
912 enum lprocfs_stats_flags flags)
914 struct lprocfs_stats *stats;
915 unsigned int percpusize;
917 unsigned int num_cpu;
922 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
925 num_cpu = num_possible_cpus();
927 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
931 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
932 stats->ls_flags = flags;
933 spin_lock_init(&stats->ls_lock);
934 /* Use this lock only if there are no percpu areas */
939 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
941 percpusize = L1_CACHE_ALIGN(percpusize);
943 for (i = 0; i < num_cpu; i++) {
944 OBD_ALLOC(stats->ls_percpu[i], percpusize);
945 if (stats->ls_percpu[i] == NULL) {
946 for (j = 0; j < i; j++) {
947 OBD_FREE(stats->ls_percpu[j], percpusize);
948 stats->ls_percpu[j] = NULL;
953 if (stats->ls_percpu[0] == NULL) {
954 OBD_FREE(stats, offsetof(typeof(*stats),
955 ls_percpu[num_cpu]));
963 void lprocfs_free_stats(struct lprocfs_stats **statsh)
965 struct lprocfs_stats *stats = *statsh;
966 unsigned int num_cpu;
967 unsigned int percpusize;
970 if (!stats || (stats->ls_num == 0))
973 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
976 num_cpu = num_possible_cpus();
978 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
980 percpusize = L1_CACHE_ALIGN(percpusize);
981 for (i = 0; i < num_cpu; i++)
982 OBD_FREE(stats->ls_percpu[i], percpusize);
983 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
986 void lprocfs_clear_stats(struct lprocfs_stats *stats)
988 struct lprocfs_counter *percpu_cntr;
990 unsigned int num_cpu;
992 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
994 for (i = 0; i < num_cpu; i++) {
995 for (j = 0; j < stats->ls_num; j++) {
996 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
997 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
998 percpu_cntr->lc_count = 0;
999 percpu_cntr->lc_sum = 0;
1000 percpu_cntr->lc_min = LC_MIN_INIT;
1001 percpu_cntr->lc_max = 0;
1002 percpu_cntr->lc_sumsquare = 0;
1003 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1007 lprocfs_stats_unlock(stats);
1010 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1011 size_t len, loff_t *off)
1013 struct seq_file *seq = file->private_data;
1014 struct lprocfs_stats *stats = seq->private;
1016 lprocfs_clear_stats(stats);
1021 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1023 struct lprocfs_stats *stats = p->private;
1024 /* return 1st cpu location */
1025 return (*pos >= stats->ls_num) ? NULL :
1026 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1029 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1033 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1035 struct lprocfs_stats *stats = p->private;
1037 return (*pos >= stats->ls_num) ? NULL :
1038 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1041 /* seq file export of one lprocfs counter */
1042 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1044 struct lprocfs_stats *stats = p->private;
1045 struct lprocfs_counter *cntr = v;
1046 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
1048 unsigned int num_cpu;
1050 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1052 do_gettimeofday(&now);
1053 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1054 "snapshot_time", now.tv_sec, now.tv_usec);
1058 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1060 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1063 num_cpu = num_possible_cpus();
1065 for (i = 0; i < num_cpu; i++) {
1066 struct lprocfs_counter *percpu_cntr =
1067 &(stats->ls_percpu[i])->lp_cntr[idx];
1071 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1072 t.lc_count = percpu_cntr->lc_count;
1073 t.lc_sum = percpu_cntr->lc_sum;
1074 t.lc_min = percpu_cntr->lc_min;
1075 t.lc_max = percpu_cntr->lc_max;
1076 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1077 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1078 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1079 ret.lc_count += t.lc_count;
1080 ret.lc_sum += t.lc_sum;
1081 if (t.lc_min < ret.lc_min)
1082 ret.lc_min = t.lc_min;
1083 if (t.lc_max > ret.lc_max)
1084 ret.lc_max = t.lc_max;
1085 ret.lc_sumsquare += t.lc_sumsquare;
1088 if (ret.lc_count == 0)
1091 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1092 ret.lc_count, cntr->lc_units);
1096 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1097 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1098 ret.lc_min, ret.lc_max, ret.lc_sum);
1101 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1102 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1106 rc = seq_printf(p, "\n");
1108 return (rc < 0) ? rc : 0;
1111 struct seq_operations lprocfs_stats_seq_sops = {
1112 start: lprocfs_stats_seq_start,
1113 stop: lprocfs_stats_seq_stop,
1114 next: lprocfs_stats_seq_next,
1115 show: lprocfs_stats_seq_show,
1118 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1120 struct proc_dir_entry *dp = PDE(inode);
1121 struct seq_file *seq;
1124 LPROCFS_ENTRY_AND_CHECK(dp);
1125 rc = seq_open(file, &lprocfs_stats_seq_sops);
1131 seq = file->private_data;
1132 seq->private = dp->data;
1136 struct file_operations lprocfs_stats_seq_fops = {
1137 .owner = THIS_MODULE,
1138 .open = lprocfs_stats_seq_open,
1140 .write = lprocfs_stats_seq_write,
1141 .llseek = seq_lseek,
1142 .release = lprocfs_seq_release,
1145 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1146 struct lprocfs_stats *stats)
1148 struct proc_dir_entry *entry;
1149 LASSERT(root != NULL);
1151 entry = create_proc_entry(name, 0644, root);
1154 entry->proc_fops = &lprocfs_stats_seq_fops;
1155 entry->data = (void *)stats;
1159 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1160 unsigned conf, const char *name, const char *units)
1162 struct lprocfs_counter *c;
1164 unsigned int num_cpu;
1166 LASSERT(stats != NULL);
1168 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1170 for (i = 0; i < num_cpu; i++) {
1171 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1172 c->lc_config = conf;
1175 c->lc_min = LC_MIN_INIT;
1178 c->lc_units = units;
1181 lprocfs_stats_unlock(stats);
1183 EXPORT_SYMBOL(lprocfs_counter_init);
1185 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1187 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1188 LASSERT(coffset < stats->ls_num); \
1189 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1192 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1194 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1195 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1196 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1197 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1198 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1199 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1200 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1201 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1202 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1203 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1204 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1205 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1206 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1207 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1208 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1209 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1210 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1211 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1212 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1213 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1214 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1215 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1216 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1217 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1218 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1219 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1220 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1221 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1222 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1223 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1224 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1225 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1226 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1227 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1228 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1229 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1230 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1231 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1232 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1233 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1234 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1235 LPROCFS_OBD_OP_INIT(num_private_stats, stats, update_lvb);
1236 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1237 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1238 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1239 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1240 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1241 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1242 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1243 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1244 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1245 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1246 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1247 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1248 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1249 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1250 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1251 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1265 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1274 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1276 lprocfs_counter_init(ldlm_stats,
1277 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1278 0, "ldlm_enqueue", "reqs");
1279 lprocfs_counter_init(ldlm_stats,
1280 LDLM_CONVERT - LDLM_FIRST_OPC,
1281 0, "ldlm_convert", "reqs");
1282 lprocfs_counter_init(ldlm_stats,
1283 LDLM_CANCEL - LDLM_FIRST_OPC,
1284 0, "ldlm_cancel", "reqs");
1285 lprocfs_counter_init(ldlm_stats,
1286 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1287 0, "ldlm_bl_callback", "reqs");
1288 lprocfs_counter_init(ldlm_stats,
1289 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1290 0, "ldlm_cp_callback", "reqs");
1291 lprocfs_counter_init(ldlm_stats,
1292 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1293 0, "ldlm_gl_callback", "reqs");
1296 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1298 struct lprocfs_stats *stats;
1299 unsigned int num_stats;
1302 LASSERT(obd->obd_stats == NULL);
1303 LASSERT(obd->obd_proc_entry != NULL);
1304 LASSERT(obd->obd_cntr_base == 0);
1306 num_stats = ((int)sizeof(*obd->obd_type->typ_ops) / sizeof(void *)) +
1307 num_private_stats - 1 /* o_owner */;
1308 stats = lprocfs_alloc_stats(num_stats, 0);
1312 lprocfs_init_ops_stats(num_private_stats, stats);
1314 for (i = num_private_stats; i < num_stats; i++) {
1315 /* If this LBUGs, it is likely that an obd
1316 * operation was added to struct obd_ops in
1317 * <obd.h>, and that the corresponding line item
1318 * LPROCFS_OBD_OP_INIT(.., .., opname)
1319 * is missing from the list above. */
1320 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1321 "Missing obd_stat initializer obd_op "
1322 "operation at offset %d.\n", i - num_private_stats);
1324 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1326 lprocfs_free_stats(&stats);
1328 obd->obd_stats = stats;
1329 obd->obd_cntr_base = num_private_stats;
1334 void lprocfs_free_obd_stats(struct obd_device *obd)
1337 lprocfs_free_stats(&obd->obd_stats);
1340 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1341 int *eof, void *data)
1343 struct obd_export *exp = (struct obd_export*)data;
1344 LASSERT(exp != NULL);
1346 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1349 struct exp_uuid_cb_data {
1357 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1358 int count, int *eof, int *len)
1360 cb_data->page = page;
1361 cb_data->count = count;
1366 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1368 struct obd_export *exp = (struct obd_export *)obj;
1369 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1371 if (exp->exp_nid_stats)
1372 *data->len += snprintf((data->page + *data->len),
1373 data->count, "%s\n",
1374 obd_uuid2str(&exp->exp_client_uuid));
1377 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1378 int *eof, void *data)
1380 struct nid_stat *stats = (struct nid_stat *)data;
1381 struct exp_uuid_cb_data cb_data;
1382 struct obd_device *obd = stats->nid_obd;
1387 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1388 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1389 lprocfs_exp_print_uuid, &cb_data);
1390 return (*cb_data.len);
1393 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1395 struct obd_export *exp = (struct obd_export *)obj;
1396 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1399 lh = exp->exp_lock_hash;
1402 *data->len += lustre_hash_debug_header(data->page,
1405 *data->len += lustre_hash_debug_str(lh, data->page +
1411 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1412 int *eof, void *data)
1414 struct nid_stat *stats = (struct nid_stat *)data;
1415 struct exp_uuid_cb_data cb_data;
1416 struct obd_device *obd = stats->nid_obd;
1421 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1422 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1423 lprocfs_exp_print_hash, &cb_data);
1424 return (*cb_data.len);
1427 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1428 int count, int *eof, void *data)
1431 return snprintf(page, count, "%s\n",
1432 "Write into this file to clear all nid stats and "
1433 "stale nid entries");
1435 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1437 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1439 struct nid_stat *stat = obj;
1442 /* object has only hash + iterate_all references.
1443 * add/delete blocked by hash bucket lock */
1444 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1445 if (stat->nid_exp_ref_count == 2) {
1446 hlist_del_init(&stat->nid_hash);
1447 stat->nid_exp_ref_count--;
1448 spin_lock(&stat->nid_obd->obd_nid_lock);
1449 list_move(&stat->nid_list, data);
1450 spin_unlock(&stat->nid_obd->obd_nid_lock);
1454 /* we has reference to object - only clear data*/
1455 if (stat->nid_stats)
1456 lprocfs_clear_stats(stat->nid_stats);
1458 if (stat->nid_brw_stats) {
1459 for (i = 0; i < BRW_LAST; i++)
1460 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1466 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1467 unsigned long count, void *data)
1469 struct obd_device *obd = (struct obd_device *)data;
1470 struct nid_stat *client_stat;
1471 CFS_LIST_HEAD(free_list);
1473 lustre_hash_for_each(obd->obd_nid_stats_hash,
1474 lprocfs_nid_stats_clear_write_cb, &free_list);
1476 while (!list_empty(&free_list)) {
1477 client_stat = list_entry(free_list.next, struct nid_stat,
1479 list_del_init(&client_stat->nid_list);
1480 lprocfs_free_client_stats(client_stat);
1485 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1487 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1490 struct nid_stat *new_stat, *old_stat;
1491 struct nid_stat_uuid *cursor, *new_ns_uuid;
1492 struct obd_device *obd;
1493 cfs_proc_dir_entry_t *entry;
1498 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1499 !exp->exp_obd->obd_nid_stats_hash)
1502 /* not test against zero because eric say:
1503 * You may only test nid against another nid, or LNET_NID_ANY.
1504 * Anything else is nonsense.*/
1505 if (!nid || *nid == LNET_NID_ANY)
1510 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1512 OBD_ALLOC_PTR(new_stat);
1513 if (new_stat == NULL)
1516 OBD_ALLOC_PTR(new_ns_uuid);
1517 if (new_ns_uuid == NULL) {
1518 OBD_FREE_PTR(new_stat);
1521 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1522 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1523 sizeof(struct obd_uuid));
1525 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1526 new_stat->nid = *nid;
1527 new_stat->nid_obd = exp->exp_obd;
1528 /* need live in hash after destroy export */
1529 new_stat->nid_exp_ref_count = 1;
1531 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1532 nid, &new_stat->nid_hash);
1533 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1534 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1536 /* Return -EALREADY here so that we know that the /proc
1537 * entry already has been created */
1538 if (old_stat != new_stat) {
1541 exp->exp_nid_stats = old_stat;
1543 /* We need to decrement the refcount if the uuid was
1544 * already in our list */
1545 spin_lock(&obd->obd_nid_lock);
1546 list_for_each_entry(cursor,
1547 &old_stat->nid_uuid_list,
1549 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1550 &exp->exp_client_uuid)) {
1552 --old_stat->nid_exp_ref_count;
1558 list_add(&new_ns_uuid->ns_uuid_list,
1559 &old_stat->nid_uuid_list);
1561 OBD_FREE_PTR(new_ns_uuid);
1563 spin_unlock(&obd->obd_nid_lock);
1565 GOTO(destroy_new, rc = -EALREADY);
1567 /* not found - create */
1568 new_stat->nid_proc = proc_mkdir(libcfs_nid2str(*nid),
1569 obd->obd_proc_exports_entry);
1570 if (!new_stat->nid_proc) {
1571 CERROR("Error making export directory for"
1572 " nid %s\n", libcfs_nid2str(*nid));
1573 GOTO(destroy_new_ns, rc = -ENOMEM);
1576 /* Add in uuid to our nid_stats list */
1577 spin_lock(&obd->obd_nid_lock);
1578 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1579 spin_unlock(&obd->obd_nid_lock);
1581 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1582 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1583 if (IS_ERR(entry)) {
1584 CWARN("Error adding the uuid file\n");
1585 rc = PTR_ERR(entry);
1586 GOTO(destroy_new_ns, rc);
1589 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1590 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1591 if (IS_ERR(entry)) {
1592 CWARN("Error adding the hash file\n");
1593 rc = PTR_ERR(entry);
1594 lprocfs_remove(&new_stat->nid_proc);
1595 GOTO(destroy_new_ns, rc);
1598 exp->exp_nid_stats = new_stat;
1600 /* protect competitive add to list, not need locking on destroy */
1601 spin_lock(&obd->obd_nid_lock);
1602 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1603 spin_unlock(&obd->obd_nid_lock);
1608 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1609 OBD_FREE_PTR(new_ns_uuid);
1612 OBD_FREE_PTR(new_stat);
1616 int lprocfs_exp_cleanup(struct obd_export *exp)
1618 struct nid_stat *stat = exp->exp_nid_stats;
1619 struct nid_stat_uuid *cursor, *tmp;
1622 if(!stat || !exp->exp_obd)
1625 spin_lock(&exp->exp_obd->obd_nid_lock);
1626 list_for_each_entry_safe(cursor, tmp,
1627 &stat->nid_uuid_list,
1629 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1630 &exp->exp_client_uuid)) {
1632 list_del(&cursor->ns_uuid_list);
1633 OBD_FREE_PTR(cursor);
1634 --stat->nid_exp_ref_count;
1635 CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1636 stat->nid_exp_ref_count);
1640 spin_unlock(&exp->exp_obd->obd_nid_lock);
1642 CERROR("obd_export's client uuid %s are not found in its "
1643 "nid_stats list\n", exp->exp_client_uuid.uuid);
1645 exp->exp_nid_stats = NULL;
1646 lprocfs_free_stats(&exp->exp_ops_stats);
1651 int lprocfs_write_helper(const char *buffer, unsigned long count,
1654 return lprocfs_write_frac_helper(buffer, count, val, 1);
1657 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1660 char kernbuf[20], *end, *pbuf;
1662 if (count > (sizeof(kernbuf) - 1))
1665 if (copy_from_user(kernbuf, buffer, count))
1668 kernbuf[count] = '\0';
1675 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1679 if (end != NULL && *end == '.') {
1680 int temp_val, pow = 1;
1684 if (strlen(pbuf) > 5)
1685 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1687 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1690 for (i = 0; i < (end - pbuf); i++)
1693 *val += temp_val / pow;
1699 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1702 long decimal_val, frac_val;
1708 decimal_val = val / mult;
1709 prtn = snprintf(buffer, count, "%ld", decimal_val);
1710 frac_val = val % mult;
1712 if (prtn < (count - 4) && frac_val > 0) {
1714 int i, temp_mult = 1, frac_bits = 0;
1716 temp_frac = frac_val * 10;
1717 buffer[prtn++] = '.';
1718 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1719 /*only reserved 2bits fraction*/
1720 buffer[prtn++] ='0';
1725 Need to think these cases :
1726 1. #echo x.00 > /proc/xxx output result : x
1727 2. #echo x.0x > /proc/xxx output result : x.0x
1728 3. #echo x.x0 > /proc/xxx output result : x.x
1729 4. #echo x.xx > /proc/xxx output result : x.xx
1730 Only reserved 2bits fraction.
1732 for (i = 0; i < (5 - prtn); i++)
1735 frac_bits = min((int)count - prtn, 3 - frac_bits);
1736 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1739 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1741 if (buffer[prtn] == '.') {
1748 buffer[prtn++] ='\n';
1752 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1754 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1757 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1758 __u64 *val, int mult)
1760 char kernbuf[22], *end, *pbuf;
1761 __u64 whole, frac = 0, units;
1762 unsigned frac_d = 1;
1764 if (count > (sizeof(kernbuf) - 1))
1767 if (copy_from_user(kernbuf, buffer, count))
1770 kernbuf[count] = '\0';
1777 whole = simple_strtoull(pbuf, &end, 10);
1781 if (end != NULL && *end == '.') {
1785 /* need to limit frac_d to a __u32 */
1786 if (strlen(pbuf) > 10)
1789 frac = simple_strtoull(pbuf, &end, 10);
1790 /* count decimal places */
1791 for (i = 0; i < (end - pbuf); i++)
1808 /* Specified units override the multiplier */
1810 mult = mult < 0 ? -units : units;
1813 do_div(frac, frac_d);
1814 *val = whole * mult + frac;
1818 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1819 char *name, mode_t mode,
1820 struct file_operations *seq_fops, void *data)
1822 struct proc_dir_entry *entry;
1825 entry = create_proc_entry(name, mode, parent);
1828 entry->proc_fops = seq_fops;
1833 EXPORT_SYMBOL(lprocfs_seq_create);
1835 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1837 struct file_operations *seq_fops,
1840 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1841 mode, seq_fops, data));
1843 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1845 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1847 if (value >= OBD_HIST_MAX)
1848 value = OBD_HIST_MAX - 1;
1850 spin_lock(&oh->oh_lock);
1851 oh->oh_buckets[value]++;
1852 spin_unlock(&oh->oh_lock);
1854 EXPORT_SYMBOL(lprocfs_oh_tally);
1856 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1860 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1863 lprocfs_oh_tally(oh, val);
1865 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1867 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1869 unsigned long ret = 0;
1872 for (i = 0; i < OBD_HIST_MAX; i++)
1873 ret += oh->oh_buckets[i];
1876 EXPORT_SYMBOL(lprocfs_oh_sum);
1878 void lprocfs_oh_clear(struct obd_histogram *oh)
1880 spin_lock(&oh->oh_lock);
1881 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1882 spin_unlock(&oh->oh_lock);
1884 EXPORT_SYMBOL(lprocfs_oh_clear);
1886 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1887 int count, int *eof, void *data)
1889 struct obd_device *obd = data;
1892 LASSERT(obd != NULL);
1893 LASSERT(count >= 0);
1895 /* Set start of user data returned to
1896 page + off since the user may have
1897 requested to read much smaller than
1898 what we need to read */
1899 *start = page + off;
1901 /* We know we are allocated a page here.
1902 Also we know that this function will
1903 not need to write more than a page
1904 so we can truncate at CFS_PAGE_SIZE. */
1905 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1907 /* Initialize the page */
1908 memset(page, 0, size);
1910 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1912 if (obd->obd_max_recoverable_clients == 0) {
1913 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1919 /* sampled unlocked, but really... */
1920 if (obd->obd_recovering == 0) {
1921 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1923 if (lprocfs_obd_snprintf(&page, size, &len,
1924 "recovery_start: %lu\n",
1925 obd->obd_recovery_start) <= 0)
1927 if (lprocfs_obd_snprintf(&page, size, &len,
1928 "recovery_duration: %lu\n",
1929 obd->obd_recovery_end -
1930 obd->obd_recovery_start) <= 0)
1932 if (lprocfs_obd_snprintf(&page, size, &len,
1933 "delayed_clients: %d/%d\n",
1934 obd->obd_delayed_clients,
1935 obd->obd_max_recoverable_clients) <= 0)
1937 /* Number of clients that have completed recovery */
1938 if (lprocfs_obd_snprintf(&page, size, &len,
1939 "completed_clients: %d/%d\n",
1940 obd->obd_max_recoverable_clients -
1941 obd->obd_recoverable_clients -
1942 obd->obd_delayed_clients,
1943 obd->obd_max_recoverable_clients) <= 0)
1945 if (lprocfs_obd_snprintf(&page, size, &len,
1946 "replayed_requests: %d\n",
1947 obd->obd_replayed_requests) <= 0)
1949 if (lprocfs_obd_snprintf(&page, size, &len,
1950 "last_transno: "LPD64"\n",
1951 obd->obd_next_recovery_transno - 1)<=0)
1956 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1958 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1959 obd->obd_recovery_start) <= 0)
1961 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1962 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1963 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1965 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1966 obd->obd_connected_clients,
1967 obd->obd_max_recoverable_clients) <= 0)
1969 if (lprocfs_obd_snprintf(&page, size, &len,"delayed_clients: %d/%d\n",
1970 obd->obd_delayed_clients,
1971 obd->obd_max_recoverable_clients) <= 0)
1973 /* Number of clients that have completed recovery */
1974 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1975 obd->obd_max_recoverable_clients -
1976 obd->obd_recoverable_clients -
1977 obd->obd_delayed_clients,
1978 obd->obd_max_recoverable_clients) <= 0)
1980 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1981 obd->obd_replayed_requests) <= 0)
1983 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1984 obd->obd_requests_queued_for_recovery) <= 0)
1986 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1987 obd->obd_next_recovery_transno) <= 0)
1993 return min(count, len - (int)off);
1995 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1997 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1998 int count, int *eof, void *data)
2000 struct obd_device *obd = data;
2006 c += lustre_hash_debug_header(page, count);
2007 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2008 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2009 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2013 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2016 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2017 int count, int *eof, void *data)
2019 struct obd_device *obd = (struct obd_device *)data;
2020 LASSERT(obd != NULL);
2022 return snprintf(page, count, "%lu\n",
2023 obd->obd_recovery_max_time);
2025 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2027 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2028 unsigned long count, void *data)
2030 struct obd_device *obd = (struct obd_device *)data;
2032 LASSERT(obd != NULL);
2034 rc = lprocfs_write_helper(buffer, count, &val);
2038 obd->obd_recovery_max_time = val;
2041 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2042 #endif /* CRAY_XT3 */
2044 #ifdef HAVE_DELAYED_RECOVERY
2045 int lprocfs_obd_rd_stale_export_age(char *page, char **start, off_t off,
2046 int count, int *eof, void *data)
2048 struct obd_device *obd = (struct obd_device *)data;
2049 LASSERT(obd != NULL);
2051 return snprintf(page, count, "%u\n",
2052 obd->u.obt.obt_stale_export_age);
2054 EXPORT_SYMBOL(lprocfs_obd_rd_stale_export_age);
2056 int lprocfs_obd_wr_stale_export_age(struct file *file, const char *buffer,
2057 unsigned long count, void *data)
2059 struct obd_device *obd = (struct obd_device *)data;
2061 LASSERT(obd != NULL);
2063 rc = lprocfs_write_helper(buffer, count, &val);
2067 target_trans_table_recalc(obd, val);
2068 obd->u.obt.obt_stale_export_age = val;
2071 EXPORT_SYMBOL(lprocfs_obd_wr_stale_export_age);
2073 static int obd_stale_exports_seq_show(struct seq_file *seq, void *v)
2075 struct obd_device *obd = seq->private;
2076 struct obd_export *exp;
2078 spin_lock(&obd->obd_dev_lock);
2079 list_for_each_entry(exp, &obd->obd_delayed_exports,
2081 seq_printf(seq, "%s: %ld seconds ago%s\n",
2082 obd_uuid2str(&exp->exp_client_uuid),
2083 cfs_time_current_sec() - exp->exp_last_request_time,
2084 exp_expired(exp, obd->u.obt.obt_stale_export_age) ?
2087 spin_unlock(&obd->obd_dev_lock);
2091 LPROC_SEQ_FOPS_RO(obd_stale_exports);
2093 int lprocfs_obd_attach_stale_exports(struct obd_device *dev)
2095 return lprocfs_obd_seq_create(dev, "stale_exports", 0444,
2096 &obd_stale_exports_fops, dev);
2098 EXPORT_SYMBOL(lprocfs_obd_attach_stale_exports);
2100 int lprocfs_obd_wr_flush_stale_exports(struct file *file, const char *buffer,
2101 unsigned long count, void *data)
2103 struct obd_device *obd = (struct obd_device *)data;
2105 LASSERT(obd != NULL);
2107 rc = lprocfs_write_helper(buffer, count, &val);
2111 class_disconnect_expired_exports(obd);
2114 EXPORT_SYMBOL(lprocfs_obd_wr_flush_stale_exports);
2117 EXPORT_SYMBOL(lprocfs_register);
2118 EXPORT_SYMBOL(lprocfs_srch);
2119 EXPORT_SYMBOL(lprocfs_remove);
2120 EXPORT_SYMBOL(lprocfs_add_vars);
2121 EXPORT_SYMBOL(lprocfs_obd_setup);
2122 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2123 EXPORT_SYMBOL(lprocfs_add_simple);
2124 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2125 EXPORT_SYMBOL(lprocfs_alloc_stats);
2126 EXPORT_SYMBOL(lprocfs_free_stats);
2127 EXPORT_SYMBOL(lprocfs_clear_stats);
2128 EXPORT_SYMBOL(lprocfs_register_stats);
2129 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2130 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2131 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2132 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2133 EXPORT_SYMBOL(lprocfs_exp_setup);
2134 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2136 EXPORT_SYMBOL(lprocfs_rd_u64);
2137 EXPORT_SYMBOL(lprocfs_rd_atomic);
2138 EXPORT_SYMBOL(lprocfs_wr_atomic);
2139 EXPORT_SYMBOL(lprocfs_rd_uint);
2140 EXPORT_SYMBOL(lprocfs_wr_uint);
2141 EXPORT_SYMBOL(lprocfs_rd_uuid);
2142 EXPORT_SYMBOL(lprocfs_rd_name);
2143 EXPORT_SYMBOL(lprocfs_rd_fstype);
2144 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2145 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2146 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2147 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2148 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2149 EXPORT_SYMBOL(lprocfs_rd_import);
2150 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2151 EXPORT_SYMBOL(lprocfs_rd_blksize);
2152 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2153 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2154 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2155 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2156 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2158 EXPORT_SYMBOL(lprocfs_write_helper);
2159 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2160 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2161 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2162 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);