1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
7 * This file is part of the Lustre file system, http://www.lustre.org
8 * Lustre is a trademark of Cluster File Systems, Inc.
10 * You may have signed or agreed to another license before downloading
11 * this software. If so, you are bound by the terms and conditions
12 * of that agreement, and the following does not apply to you. See the
13 * LICENSE file included with this distribution for more information.
15 * If you did not agree to a different license, then this copy of Lustre
16 * is open source software; you can redistribute it and/or modify it
17 * under the terms of version 2 of the GNU General Public License as
18 * published by the Free Software Foundation.
20 * In either case, Lustre is distributed in the hope that it will be
21 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * license text for more details.
27 # define EXPORT_SYMTAB
29 #define DEBUG_SUBSYSTEM S_CLASS
32 # include <liblustre.h>
35 #include <obd_class.h>
36 #include <lprocfs_status.h>
37 #include <lustre_fsfilt.h>
41 #define MAX_STRING_SIZE 128
43 /* for bug 10866, global variable */
44 DECLARE_RWSEM(_lprocfs_lock);
45 EXPORT_SYMBOL(_lprocfs_lock);
47 int lprocfs_seq_release(struct inode *inode, struct file *file)
50 return seq_release(inode, file);
52 EXPORT_SYMBOL(lprocfs_seq_release);
54 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
57 struct proc_dir_entry *temp;
63 while (temp != NULL) {
64 if (strcmp(temp->name, name) == 0)
72 /* lprocfs API calls */
74 /* Function that emulates snprintf but also has the side effect of advancing
75 the page pointer for the next write into the buffer, incrementing the total
76 length written to the buffer, and decrementing the size left in the
78 static int lprocfs_obd_snprintf(char **page, int end, int *len,
79 const char *format, ...)
87 va_start(list, format);
88 n = vsnprintf(*page, end - *len, format, list);
91 *page += n; *len += n;
95 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
96 read_proc_t *read_proc, write_proc_t *write_proc,
99 struct proc_dir_entry *proc;
102 if (root == NULL || name == NULL)
108 proc = create_proc_entry(name, mode, root);
110 CERROR("LprocFS: No memory to create /proc entry %s", name);
113 proc->read_proc = read_proc;
114 proc->write_proc = write_proc;
119 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
120 struct proc_dir_entry *parent, const char *dest)
122 struct proc_dir_entry *entry;
124 if (parent == NULL || dest == NULL)
127 entry = proc_symlink(name, parent, dest);
129 CERROR("LprocFS: Could not create symbolic link from %s to %s",
134 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
135 size_t size, loff_t *ppos)
137 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
138 char *page, *start = NULL;
139 int rc = 0, eof = 1, count;
141 if (*ppos >= CFS_PAGE_SIZE)
144 page = (char *)__get_free_page(GFP_KERNEL);
149 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
150 if (!dp->deleted && dp->read_proc)
151 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
157 /* for lustre proc read, the read count must be less than PAGE_SIZE */
166 start = page + *ppos;
167 } else if (start < page) {
171 count = (rc < size) ? rc : size;
172 if (copy_to_user(buf, start, count)) {
179 free_page((unsigned long)page);
183 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
185 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
189 if (!dp->deleted && dp->write_proc)
190 rc = dp->write_proc(f, buf, size, dp->data);
195 static struct file_operations lprocfs_generic_fops = {
196 .owner = THIS_MODULE,
197 .read = lprocfs_fops_read,
198 .write = lprocfs_fops_write,
201 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
203 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
204 struct obd_device *obd = dp->data;
206 atomic_inc(&obd->obd_evict_inprogress);
211 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
213 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
214 struct obd_device *obd = dp->data;
216 atomic_dec(&obd->obd_evict_inprogress);
217 wake_up(&obd->obd_evict_inprogress_waitq);
222 struct file_operations lprocfs_evict_client_fops = {
223 .owner = THIS_MODULE,
224 .read = lprocfs_fops_read,
225 .write = lprocfs_fops_write,
226 .open = lprocfs_evict_client_open,
227 .release = lprocfs_evict_client_release,
229 EXPORT_SYMBOL(lprocfs_evict_client_fops);
231 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
234 if (root == NULL || list == NULL)
237 while (list->name != NULL) {
238 struct proc_dir_entry *cur_root, *proc;
239 char *pathcopy, *cur, *next, pathbuf[64];
240 int pathsize = strlen(list->name) + 1;
245 /* need copy of path for strsep */
246 if (strlen(list->name) > sizeof(pathbuf) - 1) {
247 OBD_ALLOC(pathcopy, pathsize);
248 if (pathcopy == NULL)
255 strcpy(pathcopy, list->name);
257 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
258 if (*cur =='\0') /* skip double/trailing "/" */
261 proc = lprocfs_srch(cur_root, cur);
262 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
263 cur_root->name, cur, next,
264 (proc ? "exists" : "new"));
266 cur_root = (proc ? proc :
267 proc_mkdir(cur, cur_root));
268 } else if (proc == NULL) {
272 if (list->write_fptr)
274 proc = create_proc_entry(cur, mode, cur_root);
278 if (pathcopy != pathbuf)
279 OBD_FREE(pathcopy, pathsize);
281 if (cur_root == NULL || proc == NULL) {
282 CERROR("LprocFS: No memory to create /proc entry %s",
288 proc->proc_fops = list->fops;
290 proc->proc_fops = &lprocfs_generic_fops;
291 proc->read_proc = list->read_fptr;
292 proc->write_proc = list->write_fptr;
293 proc->data = (list->data ? list->data : data);
299 void lprocfs_remove(struct proc_dir_entry **rooth)
301 struct proc_dir_entry *root = *rooth;
302 struct proc_dir_entry *temp = root;
303 struct proc_dir_entry *rm_entry;
304 struct proc_dir_entry *parent;
310 parent = root->parent;
311 LASSERT(parent != NULL);
314 while (temp->subdir != NULL)
320 /* Memory corruption once caused this to fail, and
321 without this LASSERT we would loop here forever. */
322 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
323 "0x%p %s/%s len %d\n", rm_entry, temp->name,
324 rm_entry->name, (int)strlen(rm_entry->name));
326 /* Now, the rm_entry->deleted flags is protected
327 * by _lprocfs_lock. */
328 down_write(&_lprocfs_lock);
329 rm_entry->data = NULL;
330 remove_proc_entry(rm_entry->name, temp);
331 up_write(&_lprocfs_lock);
337 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
339 LASSERT(parent != NULL);
340 remove_proc_entry(name, parent);
343 struct proc_dir_entry *lprocfs_register(const char *name,
344 struct proc_dir_entry *parent,
345 struct lprocfs_vars *list, void *data)
347 struct proc_dir_entry *newchild;
349 newchild = lprocfs_srch(parent, name);
350 if (newchild != NULL) {
351 CERROR(" Lproc: Attempting to register %s more than once \n",
353 return ERR_PTR(-EALREADY);
356 newchild = proc_mkdir(name, parent);
357 if (newchild != NULL && list != NULL) {
358 int rc = lprocfs_add_vars(newchild, list, data);
360 lprocfs_remove(&newchild);
367 /* Generic callbacks */
368 int lprocfs_rd_uint(char *page, char **start, off_t off,
369 int count, int *eof, void *data)
371 unsigned int *temp = (unsigned int *)data;
372 return snprintf(page, count, "%u\n", *temp);
375 int lprocfs_wr_uint(struct file *file, const char *buffer,
376 unsigned long count, void *data)
379 char dummy[MAX_STRING_SIZE + 1], *end;
382 dummy[MAX_STRING_SIZE] = '\0';
383 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
386 tmp = simple_strtoul(dummy, &end, 0);
390 *p = (unsigned int)tmp;
394 int lprocfs_rd_u64(char *page, char **start, off_t off,
395 int count, int *eof, void *data)
397 LASSERT(data != NULL);
399 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
402 int lprocfs_rd_atomic(char *page, char **start, off_t off,
403 int count, int *eof, void *data)
405 atomic_t *atom = (atomic_t *)data;
406 LASSERT(atom != NULL);
408 return snprintf(page, count, "%d\n", atomic_read(atom));
411 int lprocfs_wr_atomic(struct file *file, const char *buffer,
412 unsigned long count, void *data)
414 atomic_t *atm = data;
418 rc = lprocfs_write_helper(buffer, count, &val);
425 atomic_set(atm, val);
429 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
430 int *eof, void *data)
432 struct obd_device *obd = (struct obd_device*)data;
434 LASSERT(obd != NULL);
436 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
439 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
440 int *eof, void* data)
442 struct obd_device *dev = (struct obd_device *)data;
444 LASSERT(dev != NULL);
445 LASSERT(dev->obd_name != NULL);
447 return snprintf(page, count, "%s\n", dev->obd_name);
450 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
453 struct obd_device *obd = (struct obd_device *)data;
455 LASSERT(obd != NULL);
456 LASSERT(obd->obd_fsops != NULL);
457 LASSERT(obd->obd_fsops->fs_type != NULL);
458 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
461 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
462 int *eof, void *data)
464 struct obd_statfs osfs;
465 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
469 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
474 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
475 int *eof, void *data)
477 struct obd_statfs osfs;
478 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
481 __u32 blk_size = osfs.os_bsize >> 10;
482 __u64 result = osfs.os_blocks;
484 while (blk_size >>= 1)
488 rc = snprintf(page, count, LPU64"\n", result);
493 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
494 int *eof, void *data)
496 struct obd_statfs osfs;
497 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
500 __u32 blk_size = osfs.os_bsize >> 10;
501 __u64 result = osfs.os_bfree;
503 while (blk_size >>= 1)
507 rc = snprintf(page, count, LPU64"\n", result);
512 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
513 int *eof, void *data)
515 struct obd_statfs osfs;
516 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
519 __u32 blk_size = osfs.os_bsize >> 10;
520 __u64 result = osfs.os_bavail;
522 while (blk_size >>= 1)
526 rc = snprintf(page, count, LPU64"\n", result);
531 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
532 int *eof, void *data)
534 struct obd_statfs osfs;
535 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
539 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
545 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
546 int *eof, void *data)
548 struct obd_statfs osfs;
549 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
553 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
558 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
559 int *eof, void *data)
561 struct obd_device *obd = (struct obd_device *)data;
562 struct obd_import *imp;
563 char *imp_state_name = NULL;
566 LASSERT(obd != NULL);
567 LPROCFS_CLIMP_CHECK(obd);
568 imp = obd->u.cli.cl_import;
569 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
571 rc = snprintf(page, count, "%s\t%s%s\n",
572 obd2cli_tgt(obd), imp_state_name,
573 imp->imp_deactive ? "\tDEACTIVATED" : "");
575 LPROCFS_CLIMP_EXIT(obd);
579 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
580 int *eof, void *data)
582 struct obd_device *obd = (struct obd_device*)data;
583 struct ptlrpc_connection *conn;
586 LASSERT(obd != NULL);
588 LPROCFS_CLIMP_CHECK(obd);
589 conn = obd->u.cli.cl_import->imp_connection;
590 LASSERT(conn != NULL);
592 if (obd->u.cli.cl_import) {
593 rc = snprintf(page, count, "%s\n",
594 conn->c_remote_uuid.uuid);
596 rc = snprintf(page, count, "%s\n", "<none>");
599 LPROCFS_CLIMP_EXIT(obd);
603 int lprocfs_at_hist_helper(char *page, int count, int rc,
604 struct adaptive_timeout *at)
607 for (i = 0; i < AT_BINS; i++)
608 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
609 rc += snprintf(page + rc, count - rc, "\n");
613 /* See also ptlrpc_lprocfs_rd_timeouts */
614 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
615 int *eof, void *data)
617 struct obd_device *obd = (struct obd_device *)data;
618 struct obd_import *imp;
619 unsigned int cur, worst;
624 LASSERT(obd != NULL);
625 LPROCFS_CLIMP_CHECK(obd);
626 imp = obd->u.cli.cl_import;
629 now = cfs_time_current_sec();
631 /* Some network health info for kicks */
632 s2dhms(&ts, now - imp->imp_last_reply_time);
633 rc += snprintf(page + rc, count - rc,
634 "%-10s : %ld, "DHMS_FMT" ago\n",
635 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
638 cur = at_get(&imp->imp_at.iat_net_latency);
639 worst = imp->imp_at.iat_net_latency.at_worst_ever;
640 worstt = imp->imp_at.iat_net_latency.at_worst_time;
641 s2dhms(&ts, now - worstt);
642 rc += snprintf(page + rc, count - rc,
643 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
644 "network", cur, worst, worstt, DHMS_VARS(&ts));
645 rc = lprocfs_at_hist_helper(page, count, rc,
646 &imp->imp_at.iat_net_latency);
648 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
649 if (imp->imp_at.iat_portal[i] == 0)
651 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
652 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
653 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
654 s2dhms(&ts, now - worstt);
655 rc += snprintf(page + rc, count - rc,
656 "portal %-2d : cur %3u worst %3u (at %ld, "
657 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
658 cur, worst, worstt, DHMS_VARS(&ts));
659 rc = lprocfs_at_hist_helper(page, count, rc,
660 &imp->imp_at.iat_service_estimate[i]);
663 LPROCFS_CLIMP_EXIT(obd);
667 static const char *obd_connect_names[] = {
694 "mds_mds_connection",
697 "alt_checksum_algorithm",
702 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
703 int count, int *eof, void *data)
705 struct obd_device *obd = data;
706 __u64 mask = 1, flags;
709 LPROCFS_CLIMP_CHECK(obd);
710 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
711 ret = snprintf(page, count, "flags="LPX64"\n", flags);
712 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
714 ret += snprintf(page + ret, count - ret, "%s\n",
715 obd_connect_names[i]);
717 if (flags & ~(mask - 1))
718 ret += snprintf(page + ret, count - ret,
719 "unknown flags "LPX64"\n", flags & ~(mask - 1));
721 LPROCFS_CLIMP_EXIT(obd);
724 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
726 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
727 int *eof, void *data)
729 struct obd_device *obd = (struct obd_device*)data;
731 LASSERT(obd != NULL);
733 return snprintf(page, count, "%u\n", obd->obd_num_exports);
736 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
737 int *eof, void *data)
739 struct obd_type *class = (struct obd_type*) data;
741 LASSERT(class != NULL);
743 return snprintf(page, count, "%d\n", class->typ_refcnt);
746 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
750 LASSERT(obd != NULL);
751 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
752 LASSERT(obd->obd_type->typ_procroot != NULL);
754 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
755 obd->obd_type->typ_procroot,
757 if (IS_ERR(obd->obd_proc_entry)) {
758 rc = PTR_ERR(obd->obd_proc_entry);
759 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
760 obd->obd_proc_entry = NULL;
765 int lprocfs_obd_cleanup(struct obd_device *obd)
769 if (obd->obd_proc_exports_entry) {
770 /* Should be no exports left */
771 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
772 lprocfs_remove(&obd->obd_proc_exports_entry);
774 lprocfs_remove(&obd->obd_proc_entry);
778 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
780 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
781 client_stat->nid_proc, client_stat->nid_stats,
782 client_stat->nid_brw_stats);
784 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
785 client_stat->nid_exp_ref_count);
787 hlist_del_init(&client_stat->nid_hash);
789 if (client_stat->nid_proc)
790 lprocfs_remove(&client_stat->nid_proc);
792 if (client_stat->nid_stats)
793 lprocfs_free_stats(&client_stat->nid_stats);
795 if (client_stat->nid_brw_stats)
796 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
798 OBD_FREE(client_stat, sizeof(*client_stat));
803 void lprocfs_free_per_client_stats(struct obd_device *obd)
805 struct nid_stat *stat;
808 /* we need extra list - because hash_exit called to early */
809 /* not need locking because all clients is died */
810 while(!list_empty(&obd->obd_nid_stats)) {
811 stat = list_entry(obd->obd_nid_stats.next,
812 struct nid_stat, nid_list);
813 list_del_init(&stat->nid_list);
814 lprocfs_free_client_stats(stat);
820 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
821 enum lprocfs_stats_flags flags)
823 struct lprocfs_stats *stats;
824 unsigned int percpusize;
826 unsigned int num_cpu;
831 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
834 num_cpu = num_possible_cpus();
836 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
840 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
841 stats->ls_flags = flags;
842 spin_lock_init(&stats->ls_lock);
843 /* Use this lock only if there are no percpu areas */
848 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
850 percpusize = L1_CACHE_ALIGN(percpusize);
852 for (i = 0; i < num_cpu; i++) {
853 OBD_ALLOC(stats->ls_percpu[i], percpusize);
854 if (stats->ls_percpu[i] == NULL) {
855 for (j = 0; j < i; j++) {
856 OBD_FREE(stats->ls_percpu[j], percpusize);
857 stats->ls_percpu[j] = NULL;
862 if (stats->ls_percpu[0] == NULL) {
863 OBD_FREE(stats, offsetof(typeof(*stats),
864 ls_percpu[num_cpu]));
872 void lprocfs_free_stats(struct lprocfs_stats **statsh)
874 struct lprocfs_stats *stats = *statsh;
875 unsigned int num_cpu;
876 unsigned int percpusize;
879 if (stats == NULL || stats->ls_num == 0)
883 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
886 num_cpu = num_possible_cpus();
888 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
890 percpusize = L1_CACHE_ALIGN(percpusize);
891 for (i = 0; i < num_cpu; i++)
892 OBD_FREE(stats->ls_percpu[i], percpusize);
893 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
896 void lprocfs_clear_stats(struct lprocfs_stats *stats)
898 struct lprocfs_counter *percpu_cntr;
900 unsigned int num_cpu;
902 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
904 for (i = 0; i < num_cpu; i++) {
905 for (j = 0; j < stats->ls_num; j++) {
906 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
907 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
908 percpu_cntr->lc_count = 0;
909 percpu_cntr->lc_sum = 0;
910 percpu_cntr->lc_min = LC_MIN_INIT;
911 percpu_cntr->lc_max = 0;
912 percpu_cntr->lc_sumsquare = 0;
913 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
917 lprocfs_stats_unlock(stats);
920 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
921 size_t len, loff_t *off)
923 struct seq_file *seq = file->private_data;
924 struct lprocfs_stats *stats = seq->private;
926 lprocfs_clear_stats(stats);
931 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
933 struct lprocfs_stats *stats = p->private;
934 /* return 1st cpu location */
935 return (*pos >= stats->ls_num) ? NULL :
936 &(stats->ls_percpu[0]->lp_cntr[*pos]);
939 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
943 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
945 struct lprocfs_stats *stats = p->private;
947 return (*pos >= stats->ls_num) ? NULL :
948 &(stats->ls_percpu[0]->lp_cntr[*pos]);
951 /* seq file export of one lprocfs counter */
952 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
954 struct lprocfs_stats *stats = p->private;
955 struct lprocfs_counter *cntr = v;
956 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
958 unsigned int num_cpu;
960 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
962 do_gettimeofday(&now);
963 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
964 "snapshot_time", now.tv_sec, now.tv_usec);
968 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
970 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
973 num_cpu = num_possible_cpus();
975 for (i = 0; i < num_cpu; i++) {
976 struct lprocfs_counter *percpu_cntr =
977 &(stats->ls_percpu[i])->lp_cntr[idx];
981 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
982 t.lc_count = percpu_cntr->lc_count;
983 t.lc_sum = percpu_cntr->lc_sum;
984 t.lc_min = percpu_cntr->lc_min;
985 t.lc_max = percpu_cntr->lc_max;
986 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
987 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
988 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
989 ret.lc_count += t.lc_count;
990 ret.lc_sum += t.lc_sum;
991 if (t.lc_min < ret.lc_min)
992 ret.lc_min = t.lc_min;
993 if (t.lc_max > ret.lc_max)
994 ret.lc_max = t.lc_max;
995 ret.lc_sumsquare += t.lc_sumsquare;
998 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
999 ret.lc_count, cntr->lc_units);
1003 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1004 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1005 ret.lc_min, ret.lc_max, ret.lc_sum);
1008 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1009 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1013 rc = seq_printf(p, "\n");
1015 return (rc < 0) ? rc : 0;
1018 struct seq_operations lprocfs_stats_seq_sops = {
1019 start: lprocfs_stats_seq_start,
1020 stop: lprocfs_stats_seq_stop,
1021 next: lprocfs_stats_seq_next,
1022 show: lprocfs_stats_seq_show,
1025 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1027 struct proc_dir_entry *dp = PDE(inode);
1028 struct seq_file *seq;
1031 LPROCFS_ENTRY_AND_CHECK(dp);
1032 rc = seq_open(file, &lprocfs_stats_seq_sops);
1037 seq = file->private_data;
1038 seq->private = dp->data;
1042 struct file_operations lprocfs_stats_seq_fops = {
1043 .owner = THIS_MODULE,
1044 .open = lprocfs_stats_seq_open,
1046 .write = lprocfs_stats_seq_write,
1047 .llseek = seq_lseek,
1048 .release = lprocfs_seq_release,
1051 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1052 struct lprocfs_stats *stats)
1054 struct proc_dir_entry *entry;
1055 LASSERT(root != NULL);
1057 entry = create_proc_entry(name, 0644, root);
1060 entry->proc_fops = &lprocfs_stats_seq_fops;
1061 entry->data = (void *)stats;
1065 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1066 unsigned conf, const char *name, const char *units)
1068 struct lprocfs_counter *c;
1070 unsigned int num_cpu;
1072 LASSERT(stats != NULL);
1074 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1076 for (i = 0; i < num_cpu; i++) {
1077 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1078 c->lc_config = conf;
1081 c->lc_min = LC_MIN_INIT;
1084 c->lc_units = units;
1087 lprocfs_stats_unlock(stats);
1089 EXPORT_SYMBOL(lprocfs_counter_init);
1091 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1093 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1094 LASSERT(coffset < stats->ls_num); \
1095 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1098 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1100 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1101 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1102 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1103 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1104 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1105 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1106 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1107 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1108 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1109 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1110 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1111 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1112 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1113 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1114 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1115 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1116 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1117 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1118 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1119 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1120 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1121 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1122 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1123 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1124 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1125 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1126 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1127 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1128 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1129 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1130 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1131 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1132 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1133 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1134 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1135 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1136 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1137 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1138 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1139 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1140 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1141 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1142 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1143 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1144 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1145 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1146 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1147 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1148 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1149 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1150 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1151 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1152 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1153 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1154 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1155 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1156 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1157 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1158 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1159 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1160 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1161 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1162 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1163 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1164 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1165 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1166 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1167 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1168 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1169 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1170 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1171 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1172 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1173 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1174 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1177 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1179 struct lprocfs_stats *stats;
1180 unsigned int num_stats;
1183 LASSERT(obd->obd_stats == NULL);
1184 LASSERT(obd->obd_proc_entry != NULL);
1185 LASSERT(obd->obd_cntr_base == 0);
1187 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1188 num_private_stats - 1 /* o_owner */;
1189 stats = lprocfs_alloc_stats(num_stats, 0);
1193 lprocfs_init_ops_stats(num_private_stats, stats);
1195 for (i = num_private_stats; i < num_stats; i++) {
1196 /* If this LBUGs, it is likely that an obd
1197 * operation was added to struct obd_ops in
1198 * <obd.h>, and that the corresponding line item
1199 * LPROCFS_OBD_OP_INIT(.., .., opname)
1200 * is missing from the list above. */
1201 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1202 "Missing obd_stat initializer obd_op "
1203 "operation at offset %d.\n", i - num_private_stats);
1205 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1207 lprocfs_free_stats(&stats);
1209 obd->obd_stats = stats;
1210 obd->obd_cntr_base = num_private_stats;
1215 void lprocfs_free_obd_stats(struct obd_device *obd)
1218 lprocfs_free_stats(&obd->obd_stats);
1221 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1223 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1224 LASSERT(coffset < stats->ls_num); \
1225 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1228 int lprocfs_alloc_md_stats(struct obd_device *obd,
1229 unsigned num_private_stats)
1231 struct lprocfs_stats *stats;
1232 unsigned int num_stats;
1235 LASSERT(obd->md_stats == NULL);
1236 LASSERT(obd->obd_proc_entry != NULL);
1237 LASSERT(obd->md_cntr_base == 0);
1239 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1241 stats = lprocfs_alloc_stats(num_stats, 0);
1245 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1246 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1247 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1248 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1249 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1250 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1251 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1252 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1253 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1254 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1255 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1256 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1257 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1258 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1259 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1260 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1261 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1262 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1263 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1264 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1265 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1266 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1267 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1268 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1269 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1270 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1271 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1272 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1273 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1274 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1276 for (i = num_private_stats; i < num_stats; i++) {
1277 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1278 CERROR("Missing md_stat initializer md_op "
1279 "operation at offset %d. Aborting.\n",
1280 i - num_private_stats);
1284 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1286 lprocfs_free_stats(&stats);
1288 obd->md_stats = stats;
1289 obd->md_cntr_base = num_private_stats;
1294 void lprocfs_free_md_stats(struct obd_device *obd)
1296 struct lprocfs_stats *stats = obd->md_stats;
1298 if (stats != NULL) {
1299 obd->md_stats = NULL;
1300 lprocfs_free_stats(&stats);
1304 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1305 int *eof, void *data)
1307 struct obd_export *exp = (struct obd_export*)data;
1308 LASSERT(exp != NULL);
1310 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1313 struct exp_uuid_cb_data {
1320 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1322 struct obd_export *exp = (struct obd_export *)obj;
1323 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1325 if (exp->exp_nid_stats)
1326 *data->len += snprintf((data->page + *data->len),
1327 data->count, "%s\n",
1328 obd_uuid2str(&exp->exp_client_uuid));
1331 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1332 int *eof, void *data)
1334 struct nid_stat *stats = (struct nid_stat *)data;
1335 struct exp_uuid_cb_data cb_data;
1336 struct obd_device *obd = stats->nid_obd;
1341 LASSERT(obd != NULL);
1343 cb_data.page = page;
1344 cb_data.count = count;
1347 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1348 &stats->nid, lprocfs_exp_print_uuid,
1350 return (*cb_data.len);
1353 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1354 int count, int *eof, void *data)
1357 return snprintf(page, count, "%s\n",
1358 "Write into this file to clear all nid stats and "
1359 "stale nid entries");
1361 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1363 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1365 struct nid_stat *stat = obj;
1368 /* object has only hash + iterate_all references.
1369 * add/delete blocked by hash bucket lock */
1370 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1371 if(stat->nid_exp_ref_count == 2) {
1372 hlist_del_init(&stat->nid_hash);
1373 stat->nid_exp_ref_count--;
1374 spin_lock(&stat->nid_obd->obd_nid_lock);
1375 list_del_init(&stat->nid_list);
1376 spin_unlock(&stat->nid_obd->obd_nid_lock);
1377 list_add(&stat->nid_list, data);
1381 /* we has reference to object - only clear data*/
1382 if (stat->nid_stats)
1383 lprocfs_clear_stats(stat->nid_stats);
1385 if (stat->nid_brw_stats) {
1386 for (i = 0; i < BRW_LAST; i++)
1387 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1393 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1394 unsigned long count, void *data)
1396 struct obd_device *obd = (struct obd_device *)data;
1397 struct nid_stat *client_stat;
1398 CFS_LIST_HEAD(free_list);
1400 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1401 lprocfs_nid_stats_clear_write_cb, &free_list);
1403 while (!list_empty(&free_list)) {
1404 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1405 list_del_init(&client_stat->nid_list);
1406 lprocfs_free_client_stats(client_stat);
1411 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1413 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1416 struct nid_stat *tmp = NULL, *tmp1;
1417 struct obd_device *obd = NULL;
1422 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1423 !exp->exp_obd->obd_nid_stats_hash_body)
1426 /* not test against zero because eric say:
1427 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1429 if (!nid || *nid == LNET_NID_ANY)
1434 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1436 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1441 tmp->nid_obd = exp->exp_obd;
1442 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1444 /* protect competitive add to list, not need locking on destroy */
1445 spin_lock(&obd->obd_nid_lock);
1446 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1447 spin_unlock(&obd->obd_nid_lock);
1449 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1451 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1452 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1455 exp->exp_nid_stats = tmp1;
1456 GOTO(destroy_new, rc = 0);
1458 /* not found - create */
1459 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1460 obd->obd_proc_exports_entry, NULL, NULL);
1461 if (!tmp->nid_proc) {
1462 CERROR("Error making export directory for"
1463 " nid %s\n", libcfs_nid2str(*nid));
1464 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1466 GOTO(destroy_new, rc = -ENOMEM);
1469 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1470 lprocfs_exp_rd_uuid, NULL, tmp);
1472 CWARN("Error adding the uuid file\n");
1474 exp->exp_nid_stats = tmp;
1479 spin_lock(&obd->obd_nid_lock);
1480 list_del(&tmp->nid_list);
1481 spin_unlock(&obd->obd_nid_lock);
1482 OBD_FREE(tmp, sizeof(struct nid_stat));
1486 int lprocfs_exp_cleanup(struct obd_export *exp)
1488 struct nid_stat *stat = exp->exp_nid_stats;
1493 stat->nid_exp_ref_count--;
1494 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1496 exp->exp_nid_stats = NULL;
1500 int lprocfs_write_helper(const char *buffer, unsigned long count,
1503 return lprocfs_write_frac_helper(buffer, count, val, 1);
1506 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1509 char kernbuf[20], *end, *pbuf;
1511 if (count > (sizeof(kernbuf) - 1))
1514 if (copy_from_user(kernbuf, buffer, count))
1517 kernbuf[count] = '\0';
1524 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1528 if (end != NULL && *end == '.') {
1529 int temp_val, pow = 1;
1533 if (strlen(pbuf) > 5)
1534 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1536 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1539 for (i = 0; i < (end - pbuf); i++)
1542 *val += temp_val / pow;
1548 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1550 long decimal_val, frac_val;
1556 decimal_val = val / mult;
1557 prtn = snprintf(buffer, count, "%ld", decimal_val);
1558 frac_val = val % mult;
1560 if (prtn < (count - 4) && frac_val > 0) {
1562 int i, temp_mult = 1, frac_bits = 0;
1564 temp_frac = frac_val * 10;
1565 buffer[prtn++] = '.';
1566 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1567 buffer[prtn++] ='0';
1572 Need to think these cases :
1573 1. #echo x.00 > /proc/xxx output result : x
1574 2. #echo x.0x > /proc/xxx output result : x.0x
1575 3. #echo x.x0 > /proc/xxx output result : x.x
1576 4. #echo x.xx > /proc/xxx output result : x.xx
1577 Only reserved 2bits fraction.
1579 for (i = 0; i < (5 - prtn); i++)
1582 frac_bits = min((int)count - prtn, 3 - frac_bits);
1583 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1586 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1588 if (buffer[prtn] == '.') {
1595 buffer[prtn++] ='\n';
1599 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1601 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1604 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1605 __u64 *val, int mult)
1607 char kernbuf[22], *end, *pbuf;
1608 __u64 whole, frac = 0, units;
1609 unsigned frac_d = 1;
1611 if (count > (sizeof(kernbuf) - 1) )
1614 if (copy_from_user(kernbuf, buffer, count))
1617 kernbuf[count] = '\0';
1624 whole = simple_strtoull(pbuf, &end, 10);
1628 if (end != NULL && *end == '.') {
1632 /* need to limit frac_d to a __u32 */
1633 if (strlen(pbuf) > 10)
1636 frac = simple_strtoull(pbuf, &end, 10);
1637 /* count decimal places */
1638 for (i = 0; i < (end - pbuf); i++)
1655 /* Specified units override the multiplier */
1657 mult = mult < 0 ? -units : units;
1660 do_div(frac, frac_d);
1661 *val = whole * mult + frac;
1665 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1666 char *name, mode_t mode,
1667 struct file_operations *seq_fops, void *data)
1669 struct proc_dir_entry *entry;
1672 entry = create_proc_entry(name, mode, parent);
1675 entry->proc_fops = seq_fops;
1680 EXPORT_SYMBOL(lprocfs_seq_create);
1682 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1684 struct file_operations *seq_fops,
1687 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1688 mode, seq_fops, data));
1690 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1692 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1694 if (value >= OBD_HIST_MAX)
1695 value = OBD_HIST_MAX - 1;
1697 spin_lock(&oh->oh_lock);
1698 oh->oh_buckets[value]++;
1699 spin_unlock(&oh->oh_lock);
1701 EXPORT_SYMBOL(lprocfs_oh_tally);
1703 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1707 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1710 lprocfs_oh_tally(oh, val);
1712 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1714 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1716 unsigned long ret = 0;
1719 for (i = 0; i < OBD_HIST_MAX; i++)
1720 ret += oh->oh_buckets[i];
1723 EXPORT_SYMBOL(lprocfs_oh_sum);
1725 void lprocfs_oh_clear(struct obd_histogram *oh)
1727 spin_lock(&oh->oh_lock);
1728 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1729 spin_unlock(&oh->oh_lock);
1731 EXPORT_SYMBOL(lprocfs_oh_clear);
1733 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1734 int count, int *eof, void *data)
1736 struct obd_device *obd = data;
1739 LASSERT(obd != NULL);
1740 LASSERT(count >= 0);
1742 /* Set start of user data returned to
1743 page + off since the user may have
1744 requested to read much smaller than
1745 what we need to read */
1746 *start = page + off;
1748 /* We know we are allocated a page here.
1749 Also we know that this function will
1750 not need to write more than a page
1751 so we can truncate at CFS_PAGE_SIZE. */
1752 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1754 /* Initialize the page */
1755 memset(page, 0, size);
1757 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1759 if (obd->obd_max_recoverable_clients == 0) {
1760 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1766 /* sampled unlocked, but really... */
1767 if (obd->obd_recovering == 0) {
1768 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1770 if (lprocfs_obd_snprintf(&page, size, &len,
1771 "recovery_start: %lu\n",
1772 obd->obd_recovery_start) <= 0)
1774 if (lprocfs_obd_snprintf(&page, size, &len,
1775 "recovery_duration: %lu\n",
1776 obd->obd_recovery_end -
1777 obd->obd_recovery_start) <= 0)
1779 /* Number of clients that have completed recovery */
1780 if (lprocfs_obd_snprintf(&page, size, &len,
1781 "completed_clients: %d/%d\n",
1782 obd->obd_max_recoverable_clients -
1783 obd->obd_recoverable_clients,
1784 obd->obd_max_recoverable_clients) <= 0)
1786 if (lprocfs_obd_snprintf(&page, size, &len,
1787 "replayed_requests: %d\n",
1788 obd->obd_replayed_requests) <= 0)
1790 if (lprocfs_obd_snprintf(&page, size, &len,
1791 "last_transno: "LPD64"\n",
1792 obd->obd_next_recovery_transno - 1)<=0)
1797 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1799 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1800 obd->obd_recovery_start) <= 0)
1802 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1803 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1804 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1806 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1807 obd->obd_connected_clients,
1808 obd->obd_max_recoverable_clients) <= 0)
1810 /* Number of clients that have completed recovery */
1811 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1812 obd->obd_max_recoverable_clients -
1813 obd->obd_recoverable_clients,
1814 obd->obd_max_recoverable_clients) <= 0)
1816 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1817 obd->obd_replayed_requests) <= 0)
1819 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1820 obd->obd_requests_queued_for_recovery) <= 0)
1823 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1824 obd->obd_next_recovery_transno) <= 0)
1830 return min(count, len - (int)off);
1832 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1834 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1835 int count, int *eof, void *data)
1837 struct obd_device *obd = (struct obd_device *)data;
1838 LASSERT(obd != NULL);
1840 return snprintf(page, count, "%lu\n",
1841 obd->obd_recovery_max_time);
1843 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1845 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1846 unsigned long count, void *data)
1848 struct obd_device *obd = (struct obd_device *)data;
1850 LASSERT(obd != NULL);
1852 rc = lprocfs_write_helper(buffer, count, &val);
1856 obd->obd_recovery_max_time = val;
1859 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1861 EXPORT_SYMBOL(lprocfs_register);
1862 EXPORT_SYMBOL(lprocfs_srch);
1863 EXPORT_SYMBOL(lprocfs_remove);
1864 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1865 EXPORT_SYMBOL(lprocfs_add_vars);
1866 EXPORT_SYMBOL(lprocfs_obd_setup);
1867 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1868 EXPORT_SYMBOL(lprocfs_add_simple);
1869 EXPORT_SYMBOL(lprocfs_add_symlink);
1870 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1871 EXPORT_SYMBOL(lprocfs_alloc_stats);
1872 EXPORT_SYMBOL(lprocfs_free_stats);
1873 EXPORT_SYMBOL(lprocfs_clear_stats);
1874 EXPORT_SYMBOL(lprocfs_register_stats);
1875 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1876 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1877 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1878 EXPORT_SYMBOL(lprocfs_exp_setup);
1879 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1881 EXPORT_SYMBOL(lprocfs_rd_u64);
1882 EXPORT_SYMBOL(lprocfs_rd_atomic);
1883 EXPORT_SYMBOL(lprocfs_wr_atomic);
1884 EXPORT_SYMBOL(lprocfs_rd_uint);
1885 EXPORT_SYMBOL(lprocfs_wr_uint);
1886 EXPORT_SYMBOL(lprocfs_rd_uuid);
1887 EXPORT_SYMBOL(lprocfs_rd_name);
1888 EXPORT_SYMBOL(lprocfs_rd_fstype);
1889 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1890 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1891 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1892 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1893 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1894 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1895 EXPORT_SYMBOL(lprocfs_rd_blksize);
1896 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1897 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1898 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1899 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1900 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1902 EXPORT_SYMBOL(lprocfs_write_helper);
1903 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1904 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1905 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1906 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);