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 [sun.com URL with a
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;
78 while (temp != NULL) {
79 if (strcmp(temp->name, name) == 0)
87 /* lprocfs API calls */
89 /* Function that emulates snprintf but also has the side effect of advancing
90 the page pointer for the next write into the buffer, incrementing the total
91 length written to the buffer, and decrementing the size left in the
93 static int lprocfs_obd_snprintf(char **page, int end, int *len,
94 const char *format, ...)
102 va_start(list, format);
103 n = vsnprintf(*page, end - *len, format, list);
106 *page += n; *len += n;
110 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
111 read_proc_t *read_proc, write_proc_t *write_proc,
114 struct proc_dir_entry *proc;
117 if (root == NULL || name == NULL)
123 proc = create_proc_entry(name, mode, root);
125 CERROR("LprocFS: No memory to create /proc entry %s", name);
128 proc->read_proc = read_proc;
129 proc->write_proc = write_proc;
134 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
135 struct proc_dir_entry *parent, const char *dest)
137 struct proc_dir_entry *entry;
139 if (parent == NULL || dest == NULL)
142 entry = proc_symlink(name, parent, dest);
144 CERROR("LprocFS: Could not create symbolic link from %s to %s",
149 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
150 size_t size, loff_t *ppos)
152 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
153 char *page, *start = NULL;
154 int rc = 0, eof = 1, count;
156 if (*ppos >= CFS_PAGE_SIZE)
159 page = (char *)__get_free_page(GFP_KERNEL);
164 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
165 if (!dp->deleted && dp->read_proc)
166 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
172 /* for lustre proc read, the read count must be less than PAGE_SIZE */
181 start = page + *ppos;
182 } else if (start < page) {
186 count = (rc < size) ? rc : size;
187 if (copy_to_user(buf, start, count)) {
194 free_page((unsigned long)page);
198 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
200 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
204 if (!dp->deleted && dp->write_proc)
205 rc = dp->write_proc(f, buf, size, dp->data);
210 static struct file_operations lprocfs_generic_fops = {
211 .owner = THIS_MODULE,
212 .read = lprocfs_fops_read,
213 .write = lprocfs_fops_write,
216 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
218 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
219 struct obd_device *obd = dp->data;
221 atomic_inc(&obd->obd_evict_inprogress);
226 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
228 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
229 struct obd_device *obd = dp->data;
231 atomic_dec(&obd->obd_evict_inprogress);
232 wake_up(&obd->obd_evict_inprogress_waitq);
237 struct file_operations lprocfs_evict_client_fops = {
238 .owner = THIS_MODULE,
239 .read = lprocfs_fops_read,
240 .write = lprocfs_fops_write,
241 .open = lprocfs_evict_client_open,
242 .release = lprocfs_evict_client_release,
244 EXPORT_SYMBOL(lprocfs_evict_client_fops);
246 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
249 if (root == NULL || list == NULL)
252 while (list->name != NULL) {
253 struct proc_dir_entry *cur_root, *proc;
254 char *pathcopy, *cur, *next, pathbuf[64];
255 int pathsize = strlen(list->name) + 1;
260 /* need copy of path for strsep */
261 if (strlen(list->name) > sizeof(pathbuf) - 1) {
262 OBD_ALLOC(pathcopy, pathsize);
263 if (pathcopy == NULL)
270 strcpy(pathcopy, list->name);
272 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
273 if (*cur =='\0') /* skip double/trailing "/" */
276 proc = lprocfs_srch(cur_root, cur);
277 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
278 cur_root->name, cur, next,
279 (proc ? "exists" : "new"));
281 cur_root = (proc ? proc :
282 proc_mkdir(cur, cur_root));
283 } else if (proc == NULL) {
287 if (list->write_fptr)
289 proc = create_proc_entry(cur, mode, cur_root);
293 if (pathcopy != pathbuf)
294 OBD_FREE(pathcopy, pathsize);
296 if (cur_root == NULL || proc == NULL) {
297 CERROR("LprocFS: No memory to create /proc entry %s",
303 proc->proc_fops = list->fops;
305 proc->proc_fops = &lprocfs_generic_fops;
306 proc->read_proc = list->read_fptr;
307 proc->write_proc = list->write_fptr;
308 proc->data = (list->data ? list->data : data);
314 void lprocfs_remove(struct proc_dir_entry **rooth)
316 struct proc_dir_entry *root = *rooth;
317 struct proc_dir_entry *temp = root;
318 struct proc_dir_entry *rm_entry;
319 struct proc_dir_entry *parent;
325 parent = root->parent;
326 LASSERT(parent != NULL);
329 while (temp->subdir != NULL)
335 /* Memory corruption once caused this to fail, and
336 without this LASSERT we would loop here forever. */
337 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
338 "0x%p %s/%s len %d\n", rm_entry, temp->name,
339 rm_entry->name, (int)strlen(rm_entry->name));
341 /* Now, the rm_entry->deleted flags is protected
342 * by _lprocfs_lock. */
343 down_write(&_lprocfs_lock);
344 rm_entry->data = NULL;
345 remove_proc_entry(rm_entry->name, temp);
346 up_write(&_lprocfs_lock);
352 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
354 LASSERT(parent != NULL);
355 remove_proc_entry(name, parent);
358 struct proc_dir_entry *lprocfs_register(const char *name,
359 struct proc_dir_entry *parent,
360 struct lprocfs_vars *list, void *data)
362 struct proc_dir_entry *newchild;
364 newchild = lprocfs_srch(parent, name);
365 if (newchild != NULL) {
366 CERROR(" Lproc: Attempting to register %s more than once \n",
368 return ERR_PTR(-EALREADY);
371 newchild = proc_mkdir(name, parent);
372 if (newchild != NULL && list != NULL) {
373 int rc = lprocfs_add_vars(newchild, list, data);
375 lprocfs_remove(&newchild);
382 /* Generic callbacks */
383 int lprocfs_rd_uint(char *page, char **start, off_t off,
384 int count, int *eof, void *data)
386 unsigned int *temp = (unsigned int *)data;
387 return snprintf(page, count, "%u\n", *temp);
390 int lprocfs_wr_uint(struct file *file, const char *buffer,
391 unsigned long count, void *data)
394 char dummy[MAX_STRING_SIZE + 1], *end;
397 dummy[MAX_STRING_SIZE] = '\0';
398 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
401 tmp = simple_strtoul(dummy, &end, 0);
405 *p = (unsigned int)tmp;
409 int lprocfs_rd_u64(char *page, char **start, off_t off,
410 int count, int *eof, void *data)
412 LASSERT(data != NULL);
414 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
417 int lprocfs_rd_atomic(char *page, char **start, off_t off,
418 int count, int *eof, void *data)
420 atomic_t *atom = (atomic_t *)data;
421 LASSERT(atom != NULL);
423 return snprintf(page, count, "%d\n", atomic_read(atom));
426 int lprocfs_wr_atomic(struct file *file, const char *buffer,
427 unsigned long count, void *data)
429 atomic_t *atm = data;
433 rc = lprocfs_write_helper(buffer, count, &val);
440 atomic_set(atm, val);
444 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
445 int *eof, void *data)
447 struct obd_device *obd = (struct obd_device*)data;
449 LASSERT(obd != NULL);
451 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
454 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
455 int *eof, void* data)
457 struct obd_device *dev = (struct obd_device *)data;
459 LASSERT(dev != NULL);
460 LASSERT(dev->obd_name != NULL);
462 return snprintf(page, count, "%s\n", dev->obd_name);
465 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
468 struct obd_device *obd = (struct obd_device *)data;
470 LASSERT(obd != NULL);
471 LASSERT(obd->obd_fsops != NULL);
472 LASSERT(obd->obd_fsops->fs_type != NULL);
473 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
476 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
477 int *eof, void *data)
479 struct obd_statfs osfs;
480 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
484 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
489 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
490 int *eof, void *data)
492 struct obd_statfs osfs;
493 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
496 __u32 blk_size = osfs.os_bsize >> 10;
497 __u64 result = osfs.os_blocks;
499 while (blk_size >>= 1)
503 rc = snprintf(page, count, LPU64"\n", result);
508 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
509 int *eof, void *data)
511 struct obd_statfs osfs;
512 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
515 __u32 blk_size = osfs.os_bsize >> 10;
516 __u64 result = osfs.os_bfree;
518 while (blk_size >>= 1)
522 rc = snprintf(page, count, LPU64"\n", result);
527 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
528 int *eof, void *data)
530 struct obd_statfs osfs;
531 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
534 __u32 blk_size = osfs.os_bsize >> 10;
535 __u64 result = osfs.os_bavail;
537 while (blk_size >>= 1)
541 rc = snprintf(page, count, LPU64"\n", result);
546 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
547 int *eof, void *data)
549 struct obd_statfs osfs;
550 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
554 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
560 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
561 int *eof, void *data)
563 struct obd_statfs osfs;
564 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
568 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
573 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
574 int *eof, void *data)
576 struct obd_device *obd = (struct obd_device *)data;
577 struct obd_import *imp;
578 char *imp_state_name = NULL;
581 LASSERT(obd != NULL);
582 LPROCFS_CLIMP_CHECK(obd);
583 imp = obd->u.cli.cl_import;
584 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
586 rc = snprintf(page, count, "%s\t%s%s\n",
587 obd2cli_tgt(obd), imp_state_name,
588 imp->imp_deactive ? "\tDEACTIVATED" : "");
590 LPROCFS_CLIMP_EXIT(obd);
594 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
595 int *eof, void *data)
597 struct obd_device *obd = (struct obd_device*)data;
598 struct ptlrpc_connection *conn;
601 LASSERT(obd != NULL);
603 LPROCFS_CLIMP_CHECK(obd);
604 conn = obd->u.cli.cl_import->imp_connection;
605 LASSERT(conn != NULL);
607 if (obd->u.cli.cl_import) {
608 rc = snprintf(page, count, "%s\n",
609 conn->c_remote_uuid.uuid);
611 rc = snprintf(page, count, "%s\n", "<none>");
614 LPROCFS_CLIMP_EXIT(obd);
618 int lprocfs_at_hist_helper(char *page, int count, int rc,
619 struct adaptive_timeout *at)
622 for (i = 0; i < AT_BINS; i++)
623 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
624 rc += snprintf(page + rc, count - rc, "\n");
628 /* See also ptlrpc_lprocfs_rd_timeouts */
629 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
630 int *eof, void *data)
632 struct obd_device *obd = (struct obd_device *)data;
633 struct obd_import *imp;
634 unsigned int cur, worst;
639 LASSERT(obd != NULL);
640 LPROCFS_CLIMP_CHECK(obd);
641 imp = obd->u.cli.cl_import;
644 now = cfs_time_current_sec();
646 /* Some network health info for kicks */
647 s2dhms(&ts, now - imp->imp_last_reply_time);
648 rc += snprintf(page + rc, count - rc,
649 "%-10s : %ld, "DHMS_FMT" ago\n",
650 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
653 cur = at_get(&imp->imp_at.iat_net_latency);
654 worst = imp->imp_at.iat_net_latency.at_worst_ever;
655 worstt = imp->imp_at.iat_net_latency.at_worst_time;
656 s2dhms(&ts, now - worstt);
657 rc += snprintf(page + rc, count - rc,
658 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
659 "network", cur, worst, worstt, DHMS_VARS(&ts));
660 rc = lprocfs_at_hist_helper(page, count, rc,
661 &imp->imp_at.iat_net_latency);
663 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
664 if (imp->imp_at.iat_portal[i] == 0)
666 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
667 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
668 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
669 s2dhms(&ts, now - worstt);
670 rc += snprintf(page + rc, count - rc,
671 "portal %-2d : cur %3u worst %3u (at %ld, "
672 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
673 cur, worst, worstt, DHMS_VARS(&ts));
674 rc = lprocfs_at_hist_helper(page, count, rc,
675 &imp->imp_at.iat_service_estimate[i]);
678 LPROCFS_CLIMP_EXIT(obd);
682 static const char *obd_connect_names[] = {
709 "mds_mds_connection",
712 "alt_checksum_algorithm",
717 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
718 int count, int *eof, void *data)
720 struct obd_device *obd = data;
721 __u64 mask = 1, flags;
724 LPROCFS_CLIMP_CHECK(obd);
725 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
726 ret = snprintf(page, count, "flags="LPX64"\n", flags);
727 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
729 ret += snprintf(page + ret, count - ret, "%s\n",
730 obd_connect_names[i]);
732 if (flags & ~(mask - 1))
733 ret += snprintf(page + ret, count - ret,
734 "unknown flags "LPX64"\n", flags & ~(mask - 1));
736 LPROCFS_CLIMP_EXIT(obd);
739 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
741 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
742 int *eof, void *data)
744 struct obd_device *obd = (struct obd_device*)data;
746 LASSERT(obd != NULL);
748 return snprintf(page, count, "%u\n", obd->obd_num_exports);
751 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
752 int *eof, void *data)
754 struct obd_type *class = (struct obd_type*) data;
756 LASSERT(class != NULL);
758 return snprintf(page, count, "%d\n", class->typ_refcnt);
761 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
765 LASSERT(obd != NULL);
766 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
767 LASSERT(obd->obd_type->typ_procroot != NULL);
769 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
770 obd->obd_type->typ_procroot,
772 if (IS_ERR(obd->obd_proc_entry)) {
773 rc = PTR_ERR(obd->obd_proc_entry);
774 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
775 obd->obd_proc_entry = NULL;
780 int lprocfs_obd_cleanup(struct obd_device *obd)
784 if (obd->obd_proc_exports_entry) {
785 /* Should be no exports left */
786 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
787 lprocfs_remove(&obd->obd_proc_exports_entry);
789 lprocfs_remove(&obd->obd_proc_entry);
793 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
795 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
796 client_stat->nid_proc, client_stat->nid_stats,
797 client_stat->nid_brw_stats);
799 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
800 client_stat->nid_exp_ref_count);
802 hlist_del_init(&client_stat->nid_hash);
804 if (client_stat->nid_proc)
805 lprocfs_remove(&client_stat->nid_proc);
807 if (client_stat->nid_stats)
808 lprocfs_free_stats(&client_stat->nid_stats);
810 if (client_stat->nid_brw_stats)
811 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
813 OBD_FREE(client_stat, sizeof(*client_stat));
818 void lprocfs_free_per_client_stats(struct obd_device *obd)
820 struct nid_stat *stat;
823 /* we need extra list - because hash_exit called to early */
824 /* not need locking because all clients is died */
825 while(!list_empty(&obd->obd_nid_stats)) {
826 stat = list_entry(obd->obd_nid_stats.next,
827 struct nid_stat, nid_list);
828 list_del_init(&stat->nid_list);
829 lprocfs_free_client_stats(stat);
835 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
836 enum lprocfs_stats_flags flags)
838 struct lprocfs_stats *stats;
839 unsigned int percpusize;
841 unsigned int num_cpu;
846 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
849 num_cpu = num_possible_cpus();
851 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
855 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
856 stats->ls_flags = flags;
857 spin_lock_init(&stats->ls_lock);
858 /* Use this lock only if there are no percpu areas */
863 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
865 percpusize = L1_CACHE_ALIGN(percpusize);
867 for (i = 0; i < num_cpu; i++) {
868 OBD_ALLOC(stats->ls_percpu[i], percpusize);
869 if (stats->ls_percpu[i] == NULL) {
870 for (j = 0; j < i; j++) {
871 OBD_FREE(stats->ls_percpu[j], percpusize);
872 stats->ls_percpu[j] = NULL;
877 if (stats->ls_percpu[0] == NULL) {
878 OBD_FREE(stats, offsetof(typeof(*stats),
879 ls_percpu[num_cpu]));
887 void lprocfs_free_stats(struct lprocfs_stats **statsh)
889 struct lprocfs_stats *stats = *statsh;
890 unsigned int num_cpu;
891 unsigned int percpusize;
894 if (stats == NULL || stats->ls_num == 0)
898 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
901 num_cpu = num_possible_cpus();
903 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
905 percpusize = L1_CACHE_ALIGN(percpusize);
906 for (i = 0; i < num_cpu; i++)
907 OBD_FREE(stats->ls_percpu[i], percpusize);
908 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
911 void lprocfs_clear_stats(struct lprocfs_stats *stats)
913 struct lprocfs_counter *percpu_cntr;
915 unsigned int num_cpu;
917 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
919 for (i = 0; i < num_cpu; i++) {
920 for (j = 0; j < stats->ls_num; j++) {
921 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
922 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
923 percpu_cntr->lc_count = 0;
924 percpu_cntr->lc_sum = 0;
925 percpu_cntr->lc_min = LC_MIN_INIT;
926 percpu_cntr->lc_max = 0;
927 percpu_cntr->lc_sumsquare = 0;
928 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
932 lprocfs_stats_unlock(stats);
935 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
936 size_t len, loff_t *off)
938 struct seq_file *seq = file->private_data;
939 struct lprocfs_stats *stats = seq->private;
941 lprocfs_clear_stats(stats);
946 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
948 struct lprocfs_stats *stats = p->private;
949 /* return 1st cpu location */
950 return (*pos >= stats->ls_num) ? NULL :
951 &(stats->ls_percpu[0]->lp_cntr[*pos]);
954 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
958 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
960 struct lprocfs_stats *stats = p->private;
962 return (*pos >= stats->ls_num) ? NULL :
963 &(stats->ls_percpu[0]->lp_cntr[*pos]);
966 /* seq file export of one lprocfs counter */
967 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
969 struct lprocfs_stats *stats = p->private;
970 struct lprocfs_counter *cntr = v;
971 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
973 unsigned int num_cpu;
975 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
977 do_gettimeofday(&now);
978 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
979 "snapshot_time", now.tv_sec, now.tv_usec);
983 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
985 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
988 num_cpu = num_possible_cpus();
990 for (i = 0; i < num_cpu; i++) {
991 struct lprocfs_counter *percpu_cntr =
992 &(stats->ls_percpu[i])->lp_cntr[idx];
996 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
997 t.lc_count = percpu_cntr->lc_count;
998 t.lc_sum = percpu_cntr->lc_sum;
999 t.lc_min = percpu_cntr->lc_min;
1000 t.lc_max = percpu_cntr->lc_max;
1001 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1002 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1003 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1004 ret.lc_count += t.lc_count;
1005 ret.lc_sum += t.lc_sum;
1006 if (t.lc_min < ret.lc_min)
1007 ret.lc_min = t.lc_min;
1008 if (t.lc_max > ret.lc_max)
1009 ret.lc_max = t.lc_max;
1010 ret.lc_sumsquare += t.lc_sumsquare;
1013 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1014 ret.lc_count, cntr->lc_units);
1018 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1019 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1020 ret.lc_min, ret.lc_max, ret.lc_sum);
1023 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1024 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1028 rc = seq_printf(p, "\n");
1030 return (rc < 0) ? rc : 0;
1033 struct seq_operations lprocfs_stats_seq_sops = {
1034 start: lprocfs_stats_seq_start,
1035 stop: lprocfs_stats_seq_stop,
1036 next: lprocfs_stats_seq_next,
1037 show: lprocfs_stats_seq_show,
1040 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1042 struct proc_dir_entry *dp = PDE(inode);
1043 struct seq_file *seq;
1046 LPROCFS_ENTRY_AND_CHECK(dp);
1047 rc = seq_open(file, &lprocfs_stats_seq_sops);
1052 seq = file->private_data;
1053 seq->private = dp->data;
1057 struct file_operations lprocfs_stats_seq_fops = {
1058 .owner = THIS_MODULE,
1059 .open = lprocfs_stats_seq_open,
1061 .write = lprocfs_stats_seq_write,
1062 .llseek = seq_lseek,
1063 .release = lprocfs_seq_release,
1066 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1067 struct lprocfs_stats *stats)
1069 struct proc_dir_entry *entry;
1070 LASSERT(root != NULL);
1072 entry = create_proc_entry(name, 0644, root);
1075 entry->proc_fops = &lprocfs_stats_seq_fops;
1076 entry->data = (void *)stats;
1080 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1081 unsigned conf, const char *name, const char *units)
1083 struct lprocfs_counter *c;
1085 unsigned int num_cpu;
1087 LASSERT(stats != NULL);
1089 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1091 for (i = 0; i < num_cpu; i++) {
1092 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1093 c->lc_config = conf;
1096 c->lc_min = LC_MIN_INIT;
1099 c->lc_units = units;
1102 lprocfs_stats_unlock(stats);
1104 EXPORT_SYMBOL(lprocfs_counter_init);
1106 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1108 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1109 LASSERT(coffset < stats->ls_num); \
1110 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1113 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1115 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1116 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1117 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1118 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1119 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1120 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1121 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1122 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1123 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1124 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1125 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1126 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1127 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1128 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1129 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1130 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1131 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1132 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1133 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1134 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1135 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1136 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1137 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1138 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1139 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1140 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1141 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1142 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1143 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1144 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1145 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1146 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1147 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1148 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1149 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1150 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1151 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1152 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1153 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1154 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1155 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1156 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1157 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1158 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1159 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1160 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1161 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1162 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1163 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1164 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1165 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1166 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1167 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1168 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1169 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1170 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1171 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1172 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1173 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1174 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1175 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1176 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1177 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1178 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1179 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1180 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1181 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1182 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1183 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1184 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1185 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1186 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1187 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1188 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1189 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1192 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1194 struct lprocfs_stats *stats;
1195 unsigned int num_stats;
1198 LASSERT(obd->obd_stats == NULL);
1199 LASSERT(obd->obd_proc_entry != NULL);
1200 LASSERT(obd->obd_cntr_base == 0);
1202 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1203 num_private_stats - 1 /* o_owner */;
1204 stats = lprocfs_alloc_stats(num_stats, 0);
1208 lprocfs_init_ops_stats(num_private_stats, stats);
1210 for (i = num_private_stats; i < num_stats; i++) {
1211 /* If this LBUGs, it is likely that an obd
1212 * operation was added to struct obd_ops in
1213 * <obd.h>, and that the corresponding line item
1214 * LPROCFS_OBD_OP_INIT(.., .., opname)
1215 * is missing from the list above. */
1216 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1217 "Missing obd_stat initializer obd_op "
1218 "operation at offset %d.\n", i - num_private_stats);
1220 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1222 lprocfs_free_stats(&stats);
1224 obd->obd_stats = stats;
1225 obd->obd_cntr_base = num_private_stats;
1230 void lprocfs_free_obd_stats(struct obd_device *obd)
1233 lprocfs_free_stats(&obd->obd_stats);
1236 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1238 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1239 LASSERT(coffset < stats->ls_num); \
1240 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1243 int lprocfs_alloc_md_stats(struct obd_device *obd,
1244 unsigned num_private_stats)
1246 struct lprocfs_stats *stats;
1247 unsigned int num_stats;
1250 LASSERT(obd->md_stats == NULL);
1251 LASSERT(obd->obd_proc_entry != NULL);
1252 LASSERT(obd->md_cntr_base == 0);
1254 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1256 stats = lprocfs_alloc_stats(num_stats, 0);
1260 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1261 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1262 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1263 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1264 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1265 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1266 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1267 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1268 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1269 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1270 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1271 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1272 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1273 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1274 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1275 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1276 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1277 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1278 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1279 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1280 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1281 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1282 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1283 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1284 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1285 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1286 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1287 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1288 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1289 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1291 for (i = num_private_stats; i < num_stats; i++) {
1292 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1293 CERROR("Missing md_stat initializer md_op "
1294 "operation at offset %d. Aborting.\n",
1295 i - num_private_stats);
1299 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1301 lprocfs_free_stats(&stats);
1303 obd->md_stats = stats;
1304 obd->md_cntr_base = num_private_stats;
1309 void lprocfs_free_md_stats(struct obd_device *obd)
1311 struct lprocfs_stats *stats = obd->md_stats;
1313 if (stats != NULL) {
1314 obd->md_stats = NULL;
1315 lprocfs_free_stats(&stats);
1319 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1320 int *eof, void *data)
1322 struct obd_export *exp = (struct obd_export*)data;
1323 LASSERT(exp != NULL);
1325 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1328 struct exp_uuid_cb_data {
1335 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1337 struct obd_export *exp = (struct obd_export *)obj;
1338 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1340 if (exp->exp_nid_stats)
1341 *data->len += snprintf((data->page + *data->len),
1342 data->count, "%s\n",
1343 obd_uuid2str(&exp->exp_client_uuid));
1346 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1347 int *eof, void *data)
1349 struct nid_stat *stats = (struct nid_stat *)data;
1350 struct exp_uuid_cb_data cb_data;
1351 struct obd_device *obd = stats->nid_obd;
1356 LASSERT(obd != NULL);
1358 cb_data.page = page;
1359 cb_data.count = count;
1362 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1363 &stats->nid, lprocfs_exp_print_uuid,
1365 return (*cb_data.len);
1368 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1369 int count, int *eof, void *data)
1372 return snprintf(page, count, "%s\n",
1373 "Write into this file to clear all nid stats and "
1374 "stale nid entries");
1376 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1378 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1380 struct nid_stat *stat = obj;
1383 /* object has only hash + iterate_all references.
1384 * add/delete blocked by hash bucket lock */
1385 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1386 if(stat->nid_exp_ref_count == 2) {
1387 hlist_del_init(&stat->nid_hash);
1388 stat->nid_exp_ref_count--;
1389 spin_lock(&stat->nid_obd->obd_nid_lock);
1390 list_del_init(&stat->nid_list);
1391 spin_unlock(&stat->nid_obd->obd_nid_lock);
1392 list_add(&stat->nid_list, data);
1396 /* we has reference to object - only clear data*/
1397 if (stat->nid_stats)
1398 lprocfs_clear_stats(stat->nid_stats);
1400 if (stat->nid_brw_stats) {
1401 for (i = 0; i < BRW_LAST; i++)
1402 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1408 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1409 unsigned long count, void *data)
1411 struct obd_device *obd = (struct obd_device *)data;
1412 struct nid_stat *client_stat;
1413 CFS_LIST_HEAD(free_list);
1415 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1416 lprocfs_nid_stats_clear_write_cb, &free_list);
1418 while (!list_empty(&free_list)) {
1419 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1420 list_del_init(&client_stat->nid_list);
1421 lprocfs_free_client_stats(client_stat);
1426 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1428 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1431 struct nid_stat *tmp = NULL, *tmp1;
1432 struct obd_device *obd = NULL;
1437 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1438 !exp->exp_obd->obd_nid_stats_hash_body)
1441 /* not test against zero because eric say:
1442 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1444 if (!nid || *nid == LNET_NID_ANY)
1449 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1451 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1456 tmp->nid_obd = exp->exp_obd;
1457 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1459 /* protect competitive add to list, not need locking on destroy */
1460 spin_lock(&obd->obd_nid_lock);
1461 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1462 spin_unlock(&obd->obd_nid_lock);
1464 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1466 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1467 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1470 exp->exp_nid_stats = tmp1;
1471 GOTO(destroy_new, rc = 0);
1473 /* not found - create */
1474 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1475 obd->obd_proc_exports_entry, NULL, NULL);
1476 if (!tmp->nid_proc) {
1477 CERROR("Error making export directory for"
1478 " nid %s\n", libcfs_nid2str(*nid));
1479 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1481 GOTO(destroy_new, rc = -ENOMEM);
1484 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1485 lprocfs_exp_rd_uuid, NULL, tmp);
1487 CWARN("Error adding the uuid file\n");
1489 exp->exp_nid_stats = tmp;
1494 spin_lock(&obd->obd_nid_lock);
1495 list_del(&tmp->nid_list);
1496 spin_unlock(&obd->obd_nid_lock);
1497 OBD_FREE(tmp, sizeof(struct nid_stat));
1501 int lprocfs_exp_cleanup(struct obd_export *exp)
1503 struct nid_stat *stat = exp->exp_nid_stats;
1508 stat->nid_exp_ref_count--;
1509 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1511 exp->exp_nid_stats = NULL;
1515 int lprocfs_write_helper(const char *buffer, unsigned long count,
1518 return lprocfs_write_frac_helper(buffer, count, val, 1);
1521 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1524 char kernbuf[20], *end, *pbuf;
1526 if (count > (sizeof(kernbuf) - 1))
1529 if (copy_from_user(kernbuf, buffer, count))
1532 kernbuf[count] = '\0';
1539 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1543 if (end != NULL && *end == '.') {
1544 int temp_val, pow = 1;
1548 if (strlen(pbuf) > 5)
1549 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1551 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1554 for (i = 0; i < (end - pbuf); i++)
1557 *val += temp_val / pow;
1563 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1565 long decimal_val, frac_val;
1571 decimal_val = val / mult;
1572 prtn = snprintf(buffer, count, "%ld", decimal_val);
1573 frac_val = val % mult;
1575 if (prtn < (count - 4) && frac_val > 0) {
1577 int i, temp_mult = 1, frac_bits = 0;
1579 temp_frac = frac_val * 10;
1580 buffer[prtn++] = '.';
1581 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1582 buffer[prtn++] ='0';
1587 Need to think these cases :
1588 1. #echo x.00 > /proc/xxx output result : x
1589 2. #echo x.0x > /proc/xxx output result : x.0x
1590 3. #echo x.x0 > /proc/xxx output result : x.x
1591 4. #echo x.xx > /proc/xxx output result : x.xx
1592 Only reserved 2bits fraction.
1594 for (i = 0; i < (5 - prtn); i++)
1597 frac_bits = min((int)count - prtn, 3 - frac_bits);
1598 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1601 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1603 if (buffer[prtn] == '.') {
1610 buffer[prtn++] ='\n';
1614 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1616 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1619 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1620 __u64 *val, int mult)
1622 char kernbuf[22], *end, *pbuf;
1623 __u64 whole, frac = 0, units;
1624 unsigned frac_d = 1;
1626 if (count > (sizeof(kernbuf) - 1) )
1629 if (copy_from_user(kernbuf, buffer, count))
1632 kernbuf[count] = '\0';
1639 whole = simple_strtoull(pbuf, &end, 10);
1643 if (end != NULL && *end == '.') {
1647 /* need to limit frac_d to a __u32 */
1648 if (strlen(pbuf) > 10)
1651 frac = simple_strtoull(pbuf, &end, 10);
1652 /* count decimal places */
1653 for (i = 0; i < (end - pbuf); i++)
1670 /* Specified units override the multiplier */
1672 mult = mult < 0 ? -units : units;
1675 do_div(frac, frac_d);
1676 *val = whole * mult + frac;
1680 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1681 char *name, mode_t mode,
1682 struct file_operations *seq_fops, void *data)
1684 struct proc_dir_entry *entry;
1687 entry = create_proc_entry(name, mode, parent);
1690 entry->proc_fops = seq_fops;
1695 EXPORT_SYMBOL(lprocfs_seq_create);
1697 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1699 struct file_operations *seq_fops,
1702 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1703 mode, seq_fops, data));
1705 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1707 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1709 if (value >= OBD_HIST_MAX)
1710 value = OBD_HIST_MAX - 1;
1712 spin_lock(&oh->oh_lock);
1713 oh->oh_buckets[value]++;
1714 spin_unlock(&oh->oh_lock);
1716 EXPORT_SYMBOL(lprocfs_oh_tally);
1718 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1722 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1725 lprocfs_oh_tally(oh, val);
1727 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1729 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1731 unsigned long ret = 0;
1734 for (i = 0; i < OBD_HIST_MAX; i++)
1735 ret += oh->oh_buckets[i];
1738 EXPORT_SYMBOL(lprocfs_oh_sum);
1740 void lprocfs_oh_clear(struct obd_histogram *oh)
1742 spin_lock(&oh->oh_lock);
1743 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1744 spin_unlock(&oh->oh_lock);
1746 EXPORT_SYMBOL(lprocfs_oh_clear);
1748 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1749 int count, int *eof, void *data)
1751 struct obd_device *obd = data;
1754 LASSERT(obd != NULL);
1755 LASSERT(count >= 0);
1757 /* Set start of user data returned to
1758 page + off since the user may have
1759 requested to read much smaller than
1760 what we need to read */
1761 *start = page + off;
1763 /* We know we are allocated a page here.
1764 Also we know that this function will
1765 not need to write more than a page
1766 so we can truncate at CFS_PAGE_SIZE. */
1767 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1769 /* Initialize the page */
1770 memset(page, 0, size);
1772 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1774 if (obd->obd_max_recoverable_clients == 0) {
1775 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1781 /* sampled unlocked, but really... */
1782 if (obd->obd_recovering == 0) {
1783 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1785 if (lprocfs_obd_snprintf(&page, size, &len,
1786 "recovery_start: %lu\n",
1787 obd->obd_recovery_start) <= 0)
1789 if (lprocfs_obd_snprintf(&page, size, &len,
1790 "recovery_duration: %lu\n",
1791 obd->obd_recovery_end -
1792 obd->obd_recovery_start) <= 0)
1794 /* Number of clients that have completed recovery */
1795 if (lprocfs_obd_snprintf(&page, size, &len,
1796 "completed_clients: %d/%d\n",
1797 obd->obd_max_recoverable_clients -
1798 obd->obd_recoverable_clients,
1799 obd->obd_max_recoverable_clients) <= 0)
1801 if (lprocfs_obd_snprintf(&page, size, &len,
1802 "replayed_requests: %d\n",
1803 obd->obd_replayed_requests) <= 0)
1805 if (lprocfs_obd_snprintf(&page, size, &len,
1806 "last_transno: "LPD64"\n",
1807 obd->obd_next_recovery_transno - 1)<=0)
1812 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1814 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1815 obd->obd_recovery_start) <= 0)
1817 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1818 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1819 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1821 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1822 obd->obd_connected_clients,
1823 obd->obd_max_recoverable_clients) <= 0)
1825 /* Number of clients that have completed recovery */
1826 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1827 obd->obd_max_recoverable_clients -
1828 obd->obd_recoverable_clients,
1829 obd->obd_max_recoverable_clients) <= 0)
1831 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1832 obd->obd_replayed_requests) <= 0)
1834 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1835 obd->obd_requests_queued_for_recovery) <= 0)
1838 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1839 obd->obd_next_recovery_transno) <= 0)
1845 return min(count, len - (int)off);
1847 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1849 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1850 int count, int *eof, void *data)
1852 struct obd_device *obd = (struct obd_device *)data;
1853 LASSERT(obd != NULL);
1855 return snprintf(page, count, "%lu\n",
1856 obd->obd_recovery_max_time);
1858 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1860 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1861 unsigned long count, void *data)
1863 struct obd_device *obd = (struct obd_device *)data;
1865 LASSERT(obd != NULL);
1867 rc = lprocfs_write_helper(buffer, count, &val);
1871 obd->obd_recovery_max_time = val;
1874 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1876 EXPORT_SYMBOL(lprocfs_register);
1877 EXPORT_SYMBOL(lprocfs_srch);
1878 EXPORT_SYMBOL(lprocfs_remove);
1879 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1880 EXPORT_SYMBOL(lprocfs_add_vars);
1881 EXPORT_SYMBOL(lprocfs_obd_setup);
1882 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1883 EXPORT_SYMBOL(lprocfs_add_simple);
1884 EXPORT_SYMBOL(lprocfs_add_symlink);
1885 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1886 EXPORT_SYMBOL(lprocfs_alloc_stats);
1887 EXPORT_SYMBOL(lprocfs_free_stats);
1888 EXPORT_SYMBOL(lprocfs_clear_stats);
1889 EXPORT_SYMBOL(lprocfs_register_stats);
1890 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1891 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1892 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1893 EXPORT_SYMBOL(lprocfs_exp_setup);
1894 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1896 EXPORT_SYMBOL(lprocfs_rd_u64);
1897 EXPORT_SYMBOL(lprocfs_rd_atomic);
1898 EXPORT_SYMBOL(lprocfs_wr_atomic);
1899 EXPORT_SYMBOL(lprocfs_rd_uint);
1900 EXPORT_SYMBOL(lprocfs_wr_uint);
1901 EXPORT_SYMBOL(lprocfs_rd_uuid);
1902 EXPORT_SYMBOL(lprocfs_rd_name);
1903 EXPORT_SYMBOL(lprocfs_rd_fstype);
1904 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1905 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1906 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1907 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1908 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1909 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1910 EXPORT_SYMBOL(lprocfs_rd_blksize);
1911 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1912 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1913 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1914 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1915 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1917 EXPORT_SYMBOL(lprocfs_write_helper);
1918 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1919 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1920 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1921 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);