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, size_t size, loff_t *ppos)
211 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
215 if (!dp->deleted && dp->write_proc)
216 rc = dp->write_proc(f, buf, size, dp->data);
221 static struct file_operations lprocfs_generic_fops = {
222 .owner = THIS_MODULE,
223 .read = lprocfs_fops_read,
224 .write = lprocfs_fops_write,
227 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
229 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
230 struct obd_device *obd = dp->data;
232 atomic_inc(&obd->obd_evict_inprogress);
237 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
239 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
240 struct obd_device *obd = dp->data;
242 atomic_dec(&obd->obd_evict_inprogress);
243 wake_up(&obd->obd_evict_inprogress_waitq);
248 struct file_operations lprocfs_evict_client_fops = {
249 .owner = THIS_MODULE,
250 .read = lprocfs_fops_read,
251 .write = lprocfs_fops_write,
252 .open = lprocfs_evict_client_open,
253 .release = lprocfs_evict_client_release,
255 EXPORT_SYMBOL(lprocfs_evict_client_fops);
260 * \param root [in] The parent proc entry on which new entry will be added.
261 * \param list [in] Array of proc entries to be added.
262 * \param data [in] The argument to be passed when entries read/write routines
263 * are called through /proc file.
265 * \retval 0 on success
268 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
271 if (root == NULL || list == NULL)
274 while (list->name != NULL) {
275 struct proc_dir_entry *cur_root, *proc;
276 char *pathcopy, *cur, *next, pathbuf[64];
277 int pathsize = strlen(list->name) + 1;
282 /* need copy of path for strsep */
283 if (strlen(list->name) > sizeof(pathbuf) - 1) {
284 OBD_ALLOC(pathcopy, pathsize);
285 if (pathcopy == NULL)
292 strcpy(pathcopy, list->name);
294 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
295 if (*cur =='\0') /* skip double/trailing "/" */
298 proc = lprocfs_srch(cur_root, cur);
299 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
300 cur_root->name, cur, next,
301 (proc ? "exists" : "new"));
303 cur_root = (proc ? proc :
304 proc_mkdir(cur, cur_root));
305 } else if (proc == NULL) {
307 if (list->proc_mode != 0000) {
308 mode = list->proc_mode;
312 if (list->write_fptr)
315 proc = create_proc_entry(cur, mode, cur_root);
319 if (pathcopy != pathbuf)
320 OBD_FREE(pathcopy, pathsize);
322 if (cur_root == NULL || proc == NULL) {
323 CERROR("LprocFS: No memory to create /proc entry %s",
329 proc->proc_fops = list->fops;
331 proc->proc_fops = &lprocfs_generic_fops;
332 proc->read_proc = list->read_fptr;
333 proc->write_proc = list->write_fptr;
334 proc->data = (list->data ? list->data : data);
340 void lprocfs_remove(struct proc_dir_entry **rooth)
342 struct proc_dir_entry *root = *rooth;
343 struct proc_dir_entry *temp = root;
344 struct proc_dir_entry *rm_entry;
345 struct proc_dir_entry *parent;
351 parent = root->parent;
352 LASSERT(parent != NULL);
353 LPROCFS_WRITE_ENTRY(); /* search vs remove race */
356 while (temp->subdir != NULL)
362 /* Memory corruption once caused this to fail, and
363 without this LASSERT we would loop here forever. */
364 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
365 "0x%p %s/%s len %d\n", rm_entry, temp->name,
366 rm_entry->name, (int)strlen(rm_entry->name));
368 /* Now, the rm_entry->deleted flags is protected
369 * by _lprocfs_lock. */
370 rm_entry->data = NULL;
371 remove_proc_entry(rm_entry->name, temp);
375 LPROCFS_WRITE_EXIT();
378 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
380 LASSERT(parent != NULL);
381 remove_proc_entry(name, parent);
384 struct proc_dir_entry *lprocfs_register(const char *name,
385 struct proc_dir_entry *parent,
386 struct lprocfs_vars *list, void *data)
388 struct proc_dir_entry *newchild;
390 newchild = lprocfs_srch(parent, name);
391 if (newchild != NULL) {
392 CERROR(" Lproc: Attempting to register %s more than once \n",
394 return ERR_PTR(-EALREADY);
397 newchild = proc_mkdir(name, parent);
398 if (newchild != NULL && list != NULL) {
399 int rc = lprocfs_add_vars(newchild, list, data);
401 lprocfs_remove(&newchild);
408 /* Generic callbacks */
409 int lprocfs_rd_uint(char *page, char **start, off_t off,
410 int count, int *eof, void *data)
412 unsigned int *temp = (unsigned int *)data;
413 return snprintf(page, count, "%u\n", *temp);
416 int lprocfs_wr_uint(struct file *file, const char *buffer,
417 unsigned long count, void *data)
420 char dummy[MAX_STRING_SIZE + 1], *end;
423 dummy[MAX_STRING_SIZE] = '\0';
424 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
427 tmp = simple_strtoul(dummy, &end, 0);
431 *p = (unsigned int)tmp;
435 int lprocfs_rd_u64(char *page, char **start, off_t off,
436 int count, int *eof, void *data)
438 LASSERT(data != NULL);
440 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
443 int lprocfs_rd_atomic(char *page, char **start, off_t off,
444 int count, int *eof, void *data)
446 atomic_t *atom = (atomic_t *)data;
447 LASSERT(atom != NULL);
449 return snprintf(page, count, "%d\n", atomic_read(atom));
452 int lprocfs_wr_atomic(struct file *file, const char *buffer,
453 unsigned long count, void *data)
455 atomic_t *atm = data;
459 rc = lprocfs_write_helper(buffer, count, &val);
466 atomic_set(atm, val);
470 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
471 int *eof, void *data)
473 struct obd_device *obd = (struct obd_device*)data;
475 LASSERT(obd != NULL);
477 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
480 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
481 int *eof, void* data)
483 struct obd_device *dev = (struct obd_device *)data;
485 LASSERT(dev != NULL);
486 LASSERT(dev->obd_name != NULL);
488 return snprintf(page, count, "%s\n", dev->obd_name);
491 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
494 struct obd_device *obd = (struct obd_device *)data;
496 LASSERT(obd != NULL);
497 LASSERT(obd->obd_fsops != NULL);
498 LASSERT(obd->obd_fsops->fs_type != NULL);
499 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
502 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
503 int *eof, void *data)
505 struct obd_statfs osfs;
506 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
510 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
515 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
516 int *eof, void *data)
518 struct obd_statfs osfs;
519 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
522 __u32 blk_size = osfs.os_bsize >> 10;
523 __u64 result = osfs.os_blocks;
525 while (blk_size >>= 1)
529 rc = snprintf(page, count, LPU64"\n", result);
534 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
535 int *eof, void *data)
537 struct obd_statfs osfs;
538 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
541 __u32 blk_size = osfs.os_bsize >> 10;
542 __u64 result = osfs.os_bfree;
544 while (blk_size >>= 1)
548 rc = snprintf(page, count, LPU64"\n", result);
553 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
554 int *eof, void *data)
556 struct obd_statfs osfs;
557 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
560 __u32 blk_size = osfs.os_bsize >> 10;
561 __u64 result = osfs.os_bavail;
563 while (blk_size >>= 1)
567 rc = snprintf(page, count, LPU64"\n", result);
572 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
573 int *eof, void *data)
575 struct obd_statfs osfs;
576 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
580 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
586 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
587 int *eof, void *data)
589 struct obd_statfs osfs;
590 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
594 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
599 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
600 int *eof, void *data)
602 struct obd_device *obd = (struct obd_device *)data;
603 struct obd_import *imp;
604 char *imp_state_name = NULL;
607 LASSERT(obd != NULL);
608 LPROCFS_CLIMP_CHECK(obd);
609 imp = obd->u.cli.cl_import;
610 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
612 rc = snprintf(page, count, "%s\t%s%s\n",
613 obd2cli_tgt(obd), imp_state_name,
614 imp->imp_deactive ? "\tDEACTIVATED" : "");
616 LPROCFS_CLIMP_EXIT(obd);
620 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
621 int *eof, void *data)
623 struct obd_device *obd = (struct obd_device*)data;
624 struct ptlrpc_connection *conn;
627 LASSERT(obd != NULL);
629 LPROCFS_CLIMP_CHECK(obd);
630 conn = obd->u.cli.cl_import->imp_connection;
631 LASSERT(conn != NULL);
633 if (obd->u.cli.cl_import) {
634 rc = snprintf(page, count, "%s\n",
635 conn->c_remote_uuid.uuid);
637 rc = snprintf(page, count, "%s\n", "<none>");
640 LPROCFS_CLIMP_EXIT(obd);
644 #define flag2str(flag) \
645 if (imp->imp_##flag && max - len > 0) \
646 len += snprintf(str + len, max - len, " " #flag);
649 * Append a space separated list of current set flags to str.
651 static int obd_import_flags2str(struct obd_import *imp, char *str,
656 if (imp->imp_obd->obd_no_recov)
657 len += snprintf(str, max - len, " no_recov");
661 flag2str(replayable);
664 flag2str(last_recon);
669 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
670 int *eof, void *data)
672 struct obd_device *obd = (struct obd_device *)data;
673 struct obd_import *imp;
674 char *imp_state_name = NULL;
677 LASSERT(obd != NULL);
678 LPROCFS_CLIMP_CHECK(obd);
679 imp = obd->u.cli.cl_import;
680 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
683 rc = snprintf(page, count,
691 " last_replay_transno: "LPU64"\n"
692 " peer_committed_transno: "LPU64"\n"
693 " last_trasno_checked: "LPU64"\n"
696 obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
698 atomic_read(&imp->imp_inflight),
701 atomic_read(&imp->imp_inval_count),
702 imp->imp_last_replay_transno,
703 imp->imp_peer_committed_transno,
704 imp->imp_last_transno_checked);
705 rc += obd_import_flags2str(imp, page + rc, count - rc);
706 rc += snprintf(page+rc, count - rc, "\n");
707 LPROCFS_CLIMP_EXIT(obd);
711 int lprocfs_at_hist_helper(char *page, int count, int rc,
712 struct adaptive_timeout *at)
715 for (i = 0; i < AT_BINS; i++)
716 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
717 rc += snprintf(page + rc, count - rc, "\n");
721 /* See also ptlrpc_lprocfs_rd_timeouts */
722 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
723 int *eof, void *data)
725 struct obd_device *obd = (struct obd_device *)data;
726 struct obd_import *imp;
727 unsigned int cur, worst;
732 LASSERT(obd != NULL);
733 LPROCFS_CLIMP_CHECK(obd);
734 imp = obd->u.cli.cl_import;
737 now = cfs_time_current_sec();
739 /* Some network health info for kicks */
740 s2dhms(&ts, now - imp->imp_last_reply_time);
741 rc += snprintf(page + rc, count - rc,
742 "%-10s : %ld, "DHMS_FMT" ago\n",
743 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
746 cur = at_get(&imp->imp_at.iat_net_latency);
747 worst = imp->imp_at.iat_net_latency.at_worst_ever;
748 worstt = imp->imp_at.iat_net_latency.at_worst_time;
749 s2dhms(&ts, now - worstt);
750 rc += snprintf(page + rc, count - rc,
751 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
752 "network", cur, worst, worstt, DHMS_VARS(&ts));
753 rc = lprocfs_at_hist_helper(page, count, rc,
754 &imp->imp_at.iat_net_latency);
756 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
757 if (imp->imp_at.iat_portal[i] == 0)
759 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
760 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
761 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
762 s2dhms(&ts, now - worstt);
763 rc += snprintf(page + rc, count - rc,
764 "portal %-2d : cur %3u worst %3u (at %ld, "
765 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
766 cur, worst, worstt, DHMS_VARS(&ts));
767 rc = lprocfs_at_hist_helper(page, count, rc,
768 &imp->imp_at.iat_service_estimate[i]);
771 LPROCFS_CLIMP_EXIT(obd);
775 static const char *obd_connect_names[] = {
802 "mds_mds_connection",
805 "alt_checksum_algorithm",
812 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
813 int count, int *eof, void *data)
815 struct obd_device *obd = data;
816 __u64 mask = 1, flags;
819 LPROCFS_CLIMP_CHECK(obd);
820 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
821 ret = snprintf(page, count, "flags="LPX64"\n", flags);
822 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
824 ret += snprintf(page + ret, count - ret, "%s\n",
825 obd_connect_names[i]);
827 if (flags & ~(mask - 1))
828 ret += snprintf(page + ret, count - ret,
829 "unknown flags "LPX64"\n", flags & ~(mask - 1));
831 LPROCFS_CLIMP_EXIT(obd);
834 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
836 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
837 int *eof, void *data)
839 struct obd_device *obd = (struct obd_device*)data;
841 LASSERT(obd != NULL);
843 return snprintf(page, count, "%u\n", obd->obd_num_exports);
846 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
847 int *eof, void *data)
849 struct obd_type *class = (struct obd_type*) data;
851 LASSERT(class != NULL);
853 return snprintf(page, count, "%d\n", class->typ_refcnt);
856 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
860 LASSERT(obd != NULL);
861 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
862 LASSERT(obd->obd_type->typ_procroot != NULL);
864 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
865 obd->obd_type->typ_procroot,
867 if (IS_ERR(obd->obd_proc_entry)) {
868 rc = PTR_ERR(obd->obd_proc_entry);
869 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
870 obd->obd_proc_entry = NULL;
875 int lprocfs_obd_cleanup(struct obd_device *obd)
879 if (obd->obd_proc_exports_entry) {
880 /* Should be no exports left */
881 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
882 lprocfs_remove(&obd->obd_proc_exports_entry);
884 lprocfs_remove(&obd->obd_proc_entry);
888 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
890 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
891 client_stat->nid_proc, client_stat->nid_stats,
892 client_stat->nid_brw_stats);
894 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
895 client_stat->nid_exp_ref_count);
897 hlist_del_init(&client_stat->nid_hash);
899 if (client_stat->nid_proc)
900 lprocfs_remove(&client_stat->nid_proc);
902 if (client_stat->nid_stats)
903 lprocfs_free_stats(&client_stat->nid_stats);
905 if (client_stat->nid_brw_stats)
906 OBD_FREE_PTR(client_stat->nid_brw_stats);
908 if (client_stat->nid_ldlm_stats)
909 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
911 OBD_FREE_PTR(client_stat);
916 void lprocfs_free_per_client_stats(struct obd_device *obd)
918 struct nid_stat *stat;
921 /* we need extra list - because hash_exit called to early */
922 /* not need locking because all clients is died */
923 while(!list_empty(&obd->obd_nid_stats)) {
924 stat = list_entry(obd->obd_nid_stats.next,
925 struct nid_stat, nid_list);
926 list_del_init(&stat->nid_list);
927 lprocfs_free_client_stats(stat);
933 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
934 enum lprocfs_stats_flags flags)
936 struct lprocfs_stats *stats;
937 unsigned int percpusize;
939 unsigned int num_cpu;
944 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
947 num_cpu = num_possible_cpus();
949 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
953 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
954 stats->ls_flags = flags;
955 spin_lock_init(&stats->ls_lock);
956 /* Use this lock only if there are no percpu areas */
961 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
963 percpusize = L1_CACHE_ALIGN(percpusize);
965 for (i = 0; i < num_cpu; i++) {
966 OBD_ALLOC(stats->ls_percpu[i], percpusize);
967 if (stats->ls_percpu[i] == NULL) {
968 for (j = 0; j < i; j++) {
969 OBD_FREE(stats->ls_percpu[j], percpusize);
970 stats->ls_percpu[j] = NULL;
975 if (stats->ls_percpu[0] == NULL) {
976 OBD_FREE(stats, offsetof(typeof(*stats),
977 ls_percpu[num_cpu]));
985 void lprocfs_free_stats(struct lprocfs_stats **statsh)
987 struct lprocfs_stats *stats = *statsh;
988 unsigned int num_cpu;
989 unsigned int percpusize;
992 if (stats == NULL || stats->ls_num == 0)
996 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
999 num_cpu = num_possible_cpus();
1001 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1003 percpusize = L1_CACHE_ALIGN(percpusize);
1004 for (i = 0; i < num_cpu; i++)
1005 OBD_FREE(stats->ls_percpu[i], percpusize);
1006 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1009 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1011 struct lprocfs_counter *percpu_cntr;
1013 unsigned int num_cpu;
1015 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1017 for (i = 0; i < num_cpu; i++) {
1018 for (j = 0; j < stats->ls_num; j++) {
1019 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1020 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1021 percpu_cntr->lc_count = 0;
1022 percpu_cntr->lc_sum = 0;
1023 percpu_cntr->lc_min = LC_MIN_INIT;
1024 percpu_cntr->lc_max = 0;
1025 percpu_cntr->lc_sumsquare = 0;
1026 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1030 lprocfs_stats_unlock(stats);
1033 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1034 size_t len, loff_t *off)
1036 struct seq_file *seq = file->private_data;
1037 struct lprocfs_stats *stats = seq->private;
1039 lprocfs_clear_stats(stats);
1044 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1046 struct lprocfs_stats *stats = p->private;
1047 /* return 1st cpu location */
1048 return (*pos >= stats->ls_num) ? NULL :
1049 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1052 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1056 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1058 struct lprocfs_stats *stats = p->private;
1060 return (*pos >= stats->ls_num) ? NULL :
1061 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1064 /* seq file export of one lprocfs counter */
1065 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1067 struct lprocfs_stats *stats = p->private;
1068 struct lprocfs_counter *cntr = v;
1069 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
1071 unsigned int num_cpu;
1073 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1075 do_gettimeofday(&now);
1076 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1077 "snapshot_time", now.tv_sec, now.tv_usec);
1081 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1083 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1086 num_cpu = num_possible_cpus();
1088 for (i = 0; i < num_cpu; i++) {
1089 struct lprocfs_counter *percpu_cntr =
1090 &(stats->ls_percpu[i])->lp_cntr[idx];
1094 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1095 t.lc_count = percpu_cntr->lc_count;
1096 t.lc_sum = percpu_cntr->lc_sum;
1097 t.lc_min = percpu_cntr->lc_min;
1098 t.lc_max = percpu_cntr->lc_max;
1099 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1100 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1101 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1102 ret.lc_count += t.lc_count;
1103 ret.lc_sum += t.lc_sum;
1104 if (t.lc_min < ret.lc_min)
1105 ret.lc_min = t.lc_min;
1106 if (t.lc_max > ret.lc_max)
1107 ret.lc_max = t.lc_max;
1108 ret.lc_sumsquare += t.lc_sumsquare;
1111 if (ret.lc_count == 0)
1114 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1115 ret.lc_count, cntr->lc_units);
1119 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1120 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1121 ret.lc_min, ret.lc_max, ret.lc_sum);
1124 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1125 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1129 rc = seq_printf(p, "\n");
1131 return (rc < 0) ? rc : 0;
1134 struct seq_operations lprocfs_stats_seq_sops = {
1135 start: lprocfs_stats_seq_start,
1136 stop: lprocfs_stats_seq_stop,
1137 next: lprocfs_stats_seq_next,
1138 show: lprocfs_stats_seq_show,
1141 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1143 struct proc_dir_entry *dp = PDE(inode);
1144 struct seq_file *seq;
1147 LPROCFS_ENTRY_AND_CHECK(dp);
1148 rc = seq_open(file, &lprocfs_stats_seq_sops);
1153 seq = file->private_data;
1154 seq->private = dp->data;
1158 struct file_operations lprocfs_stats_seq_fops = {
1159 .owner = THIS_MODULE,
1160 .open = lprocfs_stats_seq_open,
1162 .write = lprocfs_stats_seq_write,
1163 .llseek = seq_lseek,
1164 .release = lprocfs_seq_release,
1167 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1168 struct lprocfs_stats *stats)
1170 struct proc_dir_entry *entry;
1171 LASSERT(root != NULL);
1173 entry = create_proc_entry(name, 0644, root);
1176 entry->proc_fops = &lprocfs_stats_seq_fops;
1177 entry->data = (void *)stats;
1181 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1182 unsigned conf, const char *name, const char *units)
1184 struct lprocfs_counter *c;
1186 unsigned int num_cpu;
1188 LASSERT(stats != NULL);
1190 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1192 for (i = 0; i < num_cpu; i++) {
1193 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1194 c->lc_config = conf;
1197 c->lc_min = LC_MIN_INIT;
1200 c->lc_units = units;
1203 lprocfs_stats_unlock(stats);
1205 EXPORT_SYMBOL(lprocfs_counter_init);
1207 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1209 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1210 LASSERT(coffset < stats->ls_num); \
1211 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1214 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1216 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1217 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1218 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1219 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1220 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1221 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1222 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1223 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1224 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1225 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1226 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1227 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1228 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1229 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1230 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1231 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1232 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1233 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1234 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1235 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1236 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1237 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1238 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1239 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1240 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1241 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1242 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1243 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1244 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1245 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1246 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1247 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1248 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1249 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1250 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1251 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1252 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1253 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1254 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1255 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1256 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1257 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1258 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1259 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1260 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1261 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1262 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1263 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1264 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1265 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1266 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1267 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1268 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1269 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1270 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1271 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1272 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1273 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1274 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1275 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1276 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1277 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1278 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1279 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1280 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1281 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1282 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1283 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1284 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1285 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1286 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1287 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1288 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1289 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1290 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1291 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1292 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1293 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1294 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1297 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1299 struct lprocfs_stats *stats;
1300 unsigned int num_stats;
1303 LASSERT(obd->obd_stats == NULL);
1304 LASSERT(obd->obd_proc_entry != NULL);
1305 LASSERT(obd->obd_cntr_base == 0);
1307 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1308 num_private_stats - 1 /* o_owner */;
1309 stats = lprocfs_alloc_stats(num_stats, 0);
1313 lprocfs_init_ops_stats(num_private_stats, stats);
1315 for (i = num_private_stats; i < num_stats; i++) {
1316 /* If this LBUGs, it is likely that an obd
1317 * operation was added to struct obd_ops in
1318 * <obd.h>, and that the corresponding line item
1319 * LPROCFS_OBD_OP_INIT(.., .., opname)
1320 * is missing from the list above. */
1321 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1322 "Missing obd_stat initializer obd_op "
1323 "operation at offset %d.\n", i - num_private_stats);
1325 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1327 lprocfs_free_stats(&stats);
1329 obd->obd_stats = stats;
1330 obd->obd_cntr_base = num_private_stats;
1335 void lprocfs_free_obd_stats(struct obd_device *obd)
1338 lprocfs_free_stats(&obd->obd_stats);
1341 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1343 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1344 LASSERT(coffset < stats->ls_num); \
1345 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1348 int lprocfs_alloc_md_stats(struct obd_device *obd,
1349 unsigned num_private_stats)
1351 struct lprocfs_stats *stats;
1352 unsigned int num_stats;
1355 LASSERT(obd->md_stats == NULL);
1356 LASSERT(obd->obd_proc_entry != NULL);
1357 LASSERT(obd->md_cntr_base == 0);
1359 num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1361 stats = lprocfs_alloc_stats(num_stats, 0);
1365 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1366 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1367 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1368 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1369 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1370 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1371 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1372 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1373 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1374 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1375 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1376 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1377 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1378 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1379 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1380 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1381 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1382 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1383 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1384 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1385 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1386 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1387 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1388 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1389 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1390 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1391 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1392 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1393 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1394 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1396 for (i = num_private_stats; i < num_stats; i++) {
1397 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1398 CERROR("Missing md_stat initializer md_op "
1399 "operation at offset %d. Aborting.\n",
1400 i - num_private_stats);
1404 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1406 lprocfs_free_stats(&stats);
1408 obd->md_stats = stats;
1409 obd->md_cntr_base = num_private_stats;
1414 void lprocfs_free_md_stats(struct obd_device *obd)
1416 struct lprocfs_stats *stats = obd->md_stats;
1418 if (stats != NULL) {
1419 obd->md_stats = NULL;
1420 lprocfs_free_stats(&stats);
1424 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1426 lprocfs_counter_init(ldlm_stats,
1427 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1428 0, "ldlm_enqueue", "reqs");
1429 lprocfs_counter_init(ldlm_stats,
1430 LDLM_CONVERT - LDLM_FIRST_OPC,
1431 0, "ldlm_convert", "reqs");
1432 lprocfs_counter_init(ldlm_stats,
1433 LDLM_CANCEL - LDLM_FIRST_OPC,
1434 0, "ldlm_cancel", "reqs");
1435 lprocfs_counter_init(ldlm_stats,
1436 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1437 0, "ldlm_bl_callback", "reqs");
1438 lprocfs_counter_init(ldlm_stats,
1439 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1440 0, "ldlm_cp_callback", "reqs");
1441 lprocfs_counter_init(ldlm_stats,
1442 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1443 0, "ldlm_gl_callback", "reqs");
1446 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1447 int *eof, void *data)
1449 struct obd_export *exp = (struct obd_export*)data;
1450 LASSERT(exp != NULL);
1452 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1455 struct exp_uuid_cb_data {
1463 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1464 int count, int *eof, int *len)
1466 cb_data->page = page;
1467 cb_data->count = count;
1472 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1474 struct obd_export *exp = (struct obd_export *)obj;
1475 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1477 if (exp->exp_nid_stats)
1478 *data->len += snprintf((data->page + *data->len),
1479 data->count, "%s\n",
1480 obd_uuid2str(&exp->exp_client_uuid));
1483 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1484 int *eof, void *data)
1486 struct nid_stat *stats = (struct nid_stat *)data;
1487 struct exp_uuid_cb_data cb_data;
1488 struct obd_device *obd = stats->nid_obd;
1493 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1494 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1495 lprocfs_exp_print_uuid, &cb_data);
1496 return (*cb_data.len);
1499 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1501 struct exp_uuid_cb_data *data = cb_data;
1502 struct obd_export *exp = obj;
1505 lh = exp->exp_lock_hash;
1508 *data->len += lustre_hash_debug_header(data->page,
1511 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1516 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1517 int *eof, void *data)
1519 struct nid_stat *stats = (struct nid_stat *)data;
1520 struct exp_uuid_cb_data cb_data;
1521 struct obd_device *obd = stats->nid_obd;
1526 lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1528 lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1529 lprocfs_exp_print_hash, &cb_data);
1530 return (*cb_data.len);
1533 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1534 int count, int *eof, void *data)
1537 return snprintf(page, count, "%s\n",
1538 "Write into this file to clear all nid stats and "
1539 "stale nid entries");
1541 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1543 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1545 struct nid_stat *stat = obj;
1548 /* object has only hash + iterate_all references.
1549 * add/delete blocked by hash bucket lock */
1550 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1551 if (stat->nid_exp_ref_count == 2) {
1552 hlist_del_init(&stat->nid_hash);
1553 stat->nid_exp_ref_count--;
1554 spin_lock(&stat->nid_obd->obd_nid_lock);
1555 list_move(&stat->nid_list, data);
1556 spin_unlock(&stat->nid_obd->obd_nid_lock);
1560 /* we has reference to object - only clear data*/
1561 if (stat->nid_stats)
1562 lprocfs_clear_stats(stat->nid_stats);
1564 if (stat->nid_brw_stats) {
1565 for (i = 0; i < BRW_LAST; i++)
1566 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1572 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1573 unsigned long count, void *data)
1575 struct obd_device *obd = (struct obd_device *)data;
1576 struct nid_stat *client_stat;
1577 CFS_LIST_HEAD(free_list);
1579 lustre_hash_for_each(obd->obd_nid_stats_hash,
1580 lprocfs_nid_stats_clear_write_cb, &free_list);
1582 while (!list_empty(&free_list)) {
1583 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1584 list_del_init(&client_stat->nid_list);
1585 lprocfs_free_client_stats(client_stat);
1590 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1592 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1594 struct nid_stat *new_stat, *old_stat;
1595 struct nid_stat_uuid *new_ns_uuid;
1596 struct obd_device *obd = NULL;
1597 cfs_proc_dir_entry_t *entry;
1603 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1604 !exp->exp_obd->obd_nid_stats_hash)
1607 /* not test against zero because eric say:
1608 * You may only test nid against another nid, or LNET_NID_ANY.
1609 * Anything else is nonsense.*/
1610 if (!nid || *nid == LNET_NID_ANY)
1615 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1617 OBD_ALLOC_PTR(new_stat);
1618 if (new_stat == NULL)
1621 OBD_ALLOC_PTR(new_ns_uuid);
1622 if (new_ns_uuid == NULL) {
1623 OBD_FREE_PTR(new_stat);
1626 CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1627 strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1628 sizeof(struct obd_uuid));
1630 CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1631 new_stat->nid = *nid;
1632 new_stat->nid_obd = exp->exp_obd;
1633 new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1635 /* protect competitive add to list, not need locking on destroy */
1636 spin_lock(&obd->obd_nid_lock);
1637 list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1638 spin_unlock(&obd->obd_nid_lock);
1640 old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1641 nid, &new_stat->nid_hash);
1642 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1643 old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1645 /* Return -EALREADY here so that we know that the /proc
1646 * entry already has been created */
1647 if (old_stat != new_stat) {
1648 struct nid_stat_uuid *tmp_uuid;
1651 exp->exp_nid_stats = old_stat;
1652 /* We need to decrement the refcount if the uuid was
1653 * already in our list */
1654 spin_lock(&obd->obd_nid_lock);
1655 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1657 if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1658 &exp->exp_client_uuid)){
1660 --old_stat->nid_exp_ref_count;
1666 list_add(&new_ns_uuid->ns_uuid_list,
1667 &old_stat->nid_uuid_list);
1669 OBD_FREE_PTR(new_ns_uuid);
1671 spin_unlock(&obd->obd_nid_lock);
1673 GOTO(destroy_new, rc = -EALREADY);
1675 /* not found - create */
1676 new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1677 obd->obd_proc_exports_entry,
1679 if (new_stat->nid_proc == NULL) {
1680 CERROR("Error making export directory for nid %s\n",
1681 libcfs_nid2str(*nid));
1682 GOTO(destroy_new_ns, rc = -ENOMEM);
1685 /* Add in uuid to our nid_stats list */
1686 spin_lock(&obd->obd_nid_lock);
1687 list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1688 spin_unlock(&obd->obd_nid_lock);
1690 entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1691 lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1692 if (IS_ERR(entry)) {
1693 CWARN("Error adding the NID stats file\n");
1694 rc = PTR_ERR(entry);
1695 GOTO(destroy_new_ns, rc);
1698 entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1699 lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1700 if (IS_ERR(entry)) {
1701 CWARN("Error adding the hash file\n");
1702 lprocfs_remove(&new_stat->nid_proc);
1703 rc = PTR_ERR(entry);
1704 GOTO(destroy_new_ns, rc);
1707 exp->exp_nid_stats = new_stat;
1712 lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1713 OBD_FREE_PTR(new_ns_uuid);
1716 spin_lock(&obd->obd_nid_lock);
1717 list_del(&new_stat->nid_list);
1718 spin_unlock(&obd->obd_nid_lock);
1719 OBD_FREE_PTR(new_stat);
1723 int lprocfs_exp_cleanup(struct obd_export *exp)
1725 struct nid_stat *stat = exp->exp_nid_stats;
1726 struct nid_stat_uuid *cursor, *tmp;
1729 if(!stat || !exp->exp_obd)
1732 spin_lock(&exp->exp_obd->obd_nid_lock);
1733 list_for_each_entry_safe(cursor, tmp,
1734 &stat->nid_uuid_list,
1736 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1737 &exp->exp_client_uuid)) {
1739 list_del(&cursor->ns_uuid_list);
1740 OBD_FREE_PTR(cursor);
1744 spin_unlock(&exp->exp_obd->obd_nid_lock);
1746 CERROR("obd_export's client uuid %s are not found in its "
1747 "nid_stats list\n", exp->exp_client_uuid.uuid);
1749 stat->nid_exp_ref_count--;
1750 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1752 exp->exp_nid_stats = NULL;
1753 lprocfs_free_md_stats(exp->exp_obd);
1758 int lprocfs_write_helper(const char *buffer, unsigned long count,
1761 return lprocfs_write_frac_helper(buffer, count, val, 1);
1764 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1767 char kernbuf[20], *end, *pbuf;
1769 if (count > (sizeof(kernbuf) - 1))
1772 if (copy_from_user(kernbuf, buffer, count))
1775 kernbuf[count] = '\0';
1782 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1786 if (end != NULL && *end == '.') {
1787 int temp_val, pow = 1;
1791 if (strlen(pbuf) > 5)
1792 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1794 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1797 for (i = 0; i < (end - pbuf); i++)
1800 *val += temp_val / pow;
1806 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1808 long decimal_val, frac_val;
1814 decimal_val = val / mult;
1815 prtn = snprintf(buffer, count, "%ld", decimal_val);
1816 frac_val = val % mult;
1818 if (prtn < (count - 4) && frac_val > 0) {
1820 int i, temp_mult = 1, frac_bits = 0;
1822 temp_frac = frac_val * 10;
1823 buffer[prtn++] = '.';
1824 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1825 buffer[prtn++] ='0';
1830 Need to think these cases :
1831 1. #echo x.00 > /proc/xxx output result : x
1832 2. #echo x.0x > /proc/xxx output result : x.0x
1833 3. #echo x.x0 > /proc/xxx output result : x.x
1834 4. #echo x.xx > /proc/xxx output result : x.xx
1835 Only reserved 2bits fraction.
1837 for (i = 0; i < (5 - prtn); i++)
1840 frac_bits = min((int)count - prtn, 3 - frac_bits);
1841 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1844 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1846 if (buffer[prtn] == '.') {
1853 buffer[prtn++] ='\n';
1857 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1859 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1862 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1863 __u64 *val, int mult)
1865 char kernbuf[22], *end, *pbuf;
1866 __u64 whole, frac = 0, units;
1867 unsigned frac_d = 1;
1869 if (count > (sizeof(kernbuf) - 1) )
1872 if (copy_from_user(kernbuf, buffer, count))
1875 kernbuf[count] = '\0';
1882 whole = simple_strtoull(pbuf, &end, 10);
1886 if (end != NULL && *end == '.') {
1890 /* need to limit frac_d to a __u32 */
1891 if (strlen(pbuf) > 10)
1894 frac = simple_strtoull(pbuf, &end, 10);
1895 /* count decimal places */
1896 for (i = 0; i < (end - pbuf); i++)
1913 /* Specified units override the multiplier */
1915 mult = mult < 0 ? -units : units;
1918 do_div(frac, frac_d);
1919 *val = whole * mult + frac;
1923 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1924 char *name, mode_t mode,
1925 struct file_operations *seq_fops, void *data)
1927 struct proc_dir_entry *entry;
1930 entry = create_proc_entry(name, mode, parent);
1933 entry->proc_fops = seq_fops;
1938 EXPORT_SYMBOL(lprocfs_seq_create);
1940 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1942 struct file_operations *seq_fops,
1945 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1946 mode, seq_fops, data));
1948 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1950 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1952 if (value >= OBD_HIST_MAX)
1953 value = OBD_HIST_MAX - 1;
1955 spin_lock(&oh->oh_lock);
1956 oh->oh_buckets[value]++;
1957 spin_unlock(&oh->oh_lock);
1959 EXPORT_SYMBOL(lprocfs_oh_tally);
1961 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1965 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1968 lprocfs_oh_tally(oh, val);
1970 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1972 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1974 unsigned long ret = 0;
1977 for (i = 0; i < OBD_HIST_MAX; i++)
1978 ret += oh->oh_buckets[i];
1981 EXPORT_SYMBOL(lprocfs_oh_sum);
1983 void lprocfs_oh_clear(struct obd_histogram *oh)
1985 spin_lock(&oh->oh_lock);
1986 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1987 spin_unlock(&oh->oh_lock);
1989 EXPORT_SYMBOL(lprocfs_oh_clear);
1991 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1992 int count, int *eof, void *data)
1994 struct obd_device *obd = data;
2000 c += lustre_hash_debug_header(page, count);
2001 c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2002 c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2003 c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2007 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2009 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2010 int count, int *eof, void *data)
2012 struct obd_device *obd = data;
2015 LASSERT(obd != NULL);
2016 LASSERT(count >= 0);
2018 /* Set start of user data returned to
2019 page + off since the user may have
2020 requested to read much smaller than
2021 what we need to read */
2022 *start = page + off;
2024 /* We know we are allocated a page here.
2025 Also we know that this function will
2026 not need to write more than a page
2027 so we can truncate at CFS_PAGE_SIZE. */
2028 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2030 /* Initialize the page */
2031 memset(page, 0, size);
2033 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2035 if (obd->obd_max_recoverable_clients == 0) {
2036 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2042 /* sampled unlocked, but really... */
2043 if (obd->obd_recovering == 0) {
2044 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2046 if (lprocfs_obd_snprintf(&page, size, &len,
2047 "recovery_start: %lu\n",
2048 obd->obd_recovery_start) <= 0)
2050 if (lprocfs_obd_snprintf(&page, size, &len,
2051 "recovery_duration: %lu\n",
2052 obd->obd_recovery_end -
2053 obd->obd_recovery_start) <= 0)
2055 /* Number of clients that have completed recovery */
2056 if (lprocfs_obd_snprintf(&page, size, &len,
2057 "completed_clients: %d/%d\n",
2058 obd->obd_max_recoverable_clients -
2059 obd->obd_recoverable_clients,
2060 obd->obd_max_recoverable_clients) <= 0)
2062 if (lprocfs_obd_snprintf(&page, size, &len,
2063 "replayed_requests: %d\n",
2064 obd->obd_replayed_requests) <= 0)
2066 if (lprocfs_obd_snprintf(&page, size, &len,
2067 "last_transno: "LPD64"\n",
2068 obd->obd_next_recovery_transno - 1)<=0)
2073 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2075 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2076 obd->obd_recovery_start) <= 0)
2078 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2079 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2080 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2082 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2083 obd->obd_connected_clients,
2084 obd->obd_max_recoverable_clients) <= 0)
2086 /* Number of clients that have completed recovery */
2087 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2088 obd->obd_max_recoverable_clients -
2089 obd->obd_recoverable_clients,
2090 obd->obd_max_recoverable_clients) <= 0)
2092 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2093 obd->obd_replayed_requests) <= 0)
2095 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2096 obd->obd_requests_queued_for_recovery) <= 0)
2099 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2100 obd->obd_next_recovery_transno) <= 0)
2106 return min(count, len - (int)off);
2108 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2110 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2111 int count, int *eof, void *data)
2113 struct obd_device *obd = (struct obd_device *)data;
2114 LASSERT(obd != NULL);
2116 return snprintf(page, count, "%lu\n",
2117 obd->obd_recovery_max_time);
2119 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2121 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2122 unsigned long count, void *data)
2124 struct obd_device *obd = (struct obd_device *)data;
2126 LASSERT(obd != NULL);
2128 rc = lprocfs_write_helper(buffer, count, &val);
2132 obd->obd_recovery_max_time = val;
2135 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2137 EXPORT_SYMBOL(lprocfs_register);
2138 EXPORT_SYMBOL(lprocfs_srch);
2139 EXPORT_SYMBOL(lprocfs_remove);
2140 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2141 EXPORT_SYMBOL(lprocfs_add_vars);
2142 EXPORT_SYMBOL(lprocfs_obd_setup);
2143 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2144 EXPORT_SYMBOL(lprocfs_add_simple);
2145 EXPORT_SYMBOL(lprocfs_add_symlink);
2146 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2147 EXPORT_SYMBOL(lprocfs_alloc_stats);
2148 EXPORT_SYMBOL(lprocfs_free_stats);
2149 EXPORT_SYMBOL(lprocfs_clear_stats);
2150 EXPORT_SYMBOL(lprocfs_register_stats);
2151 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2152 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2153 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2154 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2155 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2156 EXPORT_SYMBOL(lprocfs_exp_setup);
2157 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2159 EXPORT_SYMBOL(lprocfs_rd_u64);
2160 EXPORT_SYMBOL(lprocfs_rd_atomic);
2161 EXPORT_SYMBOL(lprocfs_wr_atomic);
2162 EXPORT_SYMBOL(lprocfs_rd_uint);
2163 EXPORT_SYMBOL(lprocfs_wr_uint);
2164 EXPORT_SYMBOL(lprocfs_rd_uuid);
2165 EXPORT_SYMBOL(lprocfs_rd_name);
2166 EXPORT_SYMBOL(lprocfs_rd_fstype);
2167 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2168 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2169 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2170 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2171 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2172 EXPORT_SYMBOL(lprocfs_rd_import);
2173 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2174 EXPORT_SYMBOL(lprocfs_rd_blksize);
2175 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2176 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2177 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2178 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2179 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2181 EXPORT_SYMBOL(lprocfs_write_helper);
2182 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2183 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2184 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2185 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);