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 static const char *obd_connect_names[] = {
630 "mds_mds_connection",
633 "alt_checksum_algorithm",
638 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
639 int count, int *eof, void *data)
641 struct obd_device *obd = data;
642 __u64 mask = 1, flags;
645 LPROCFS_CLIMP_CHECK(obd);
646 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
647 ret = snprintf(page, count, "flags="LPX64"\n", flags);
648 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
650 ret += snprintf(page + ret, count - ret, "%s\n",
651 obd_connect_names[i]);
653 if (flags & ~(mask - 1))
654 ret += snprintf(page + ret, count - ret,
655 "unknown flags "LPX64"\n", flags & ~(mask - 1));
657 LPROCFS_CLIMP_EXIT(obd);
660 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
662 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
663 int *eof, void *data)
665 struct obd_device *obd = (struct obd_device*)data;
667 LASSERT(obd != NULL);
669 return snprintf(page, count, "%u\n", obd->obd_num_exports);
672 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
673 int *eof, void *data)
675 struct obd_type *class = (struct obd_type*) data;
677 LASSERT(class != NULL);
679 return snprintf(page, count, "%d\n", class->typ_refcnt);
682 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
686 LASSERT(obd != NULL);
687 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
688 LASSERT(obd->obd_type->typ_procroot != NULL);
690 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
691 obd->obd_type->typ_procroot,
693 if (IS_ERR(obd->obd_proc_entry)) {
694 rc = PTR_ERR(obd->obd_proc_entry);
695 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
696 obd->obd_proc_entry = NULL;
701 int lprocfs_obd_cleanup(struct obd_device *obd)
705 if (obd->obd_proc_exports_entry) {
706 /* Should be no exports left */
707 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
708 lprocfs_remove(&obd->obd_proc_exports_entry);
710 lprocfs_remove(&obd->obd_proc_entry);
714 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
716 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
717 client_stat->nid_proc, client_stat->nid_stats,
718 client_stat->nid_brw_stats);
720 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
721 client_stat->nid_exp_ref_count);
723 hlist_del_init(&client_stat->nid_hash);
725 if (client_stat->nid_proc)
726 lprocfs_remove(&client_stat->nid_proc);
728 if (client_stat->nid_stats)
729 lprocfs_free_stats(&client_stat->nid_stats);
731 if (client_stat->nid_brw_stats)
732 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
734 OBD_FREE(client_stat, sizeof(*client_stat));
739 void lprocfs_free_per_client_stats(struct obd_device *obd)
741 struct nid_stat *stat;
744 /* we need extra list - because hash_exit called to early */
745 /* not need locking because all clients is died */
746 while(!list_empty(&obd->obd_nid_stats)) {
747 stat = list_entry(obd->obd_nid_stats.next,
748 struct nid_stat, nid_list);
749 list_del_init(&stat->nid_list);
750 lprocfs_free_client_stats(stat);
756 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
757 enum lprocfs_stats_flags flags)
759 struct lprocfs_stats *stats;
760 unsigned int percpusize;
762 unsigned int num_cpu;
767 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
770 num_cpu = num_possible_cpus();
772 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
776 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
777 stats->ls_flags = flags;
778 spin_lock_init(&stats->ls_lock);
779 /* Use this lock only if there are no percpu areas */
784 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
786 percpusize = L1_CACHE_ALIGN(percpusize);
788 for (i = 0; i < num_cpu; i++) {
789 OBD_ALLOC(stats->ls_percpu[i], percpusize);
790 if (stats->ls_percpu[i] == NULL) {
791 for (j = 0; j < i; j++) {
792 OBD_FREE(stats->ls_percpu[j], percpusize);
793 stats->ls_percpu[j] = NULL;
798 if (stats->ls_percpu[0] == NULL) {
799 OBD_FREE(stats, offsetof(typeof(*stats),
800 ls_percpu[num_cpu]));
808 void lprocfs_free_stats(struct lprocfs_stats **statsh)
810 struct lprocfs_stats *stats = *statsh;
811 unsigned int num_cpu;
812 unsigned int percpusize;
815 if (stats == NULL || stats->ls_num == 0)
819 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
822 num_cpu = num_possible_cpus();
824 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
826 percpusize = L1_CACHE_ALIGN(percpusize);
827 for (i = 0; i < num_cpu; i++)
828 OBD_FREE(stats->ls_percpu[i], percpusize);
829 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
832 void lprocfs_clear_stats(struct lprocfs_stats *stats)
834 struct lprocfs_counter *percpu_cntr;
836 unsigned int num_cpu;
838 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
840 for (i = 0; i < num_cpu; i++) {
841 for (j = 0; j < stats->ls_num; j++) {
842 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
843 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
844 percpu_cntr->lc_count = 0;
845 percpu_cntr->lc_sum = 0;
846 percpu_cntr->lc_min = LC_MIN_INIT;
847 percpu_cntr->lc_max = 0;
848 percpu_cntr->lc_sumsquare = 0;
849 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
853 lprocfs_stats_unlock(stats);
856 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
857 size_t len, loff_t *off)
859 struct seq_file *seq = file->private_data;
860 struct lprocfs_stats *stats = seq->private;
862 lprocfs_clear_stats(stats);
867 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
869 struct lprocfs_stats *stats = p->private;
870 /* return 1st cpu location */
871 return (*pos >= stats->ls_num) ? NULL :
872 &(stats->ls_percpu[0]->lp_cntr[*pos]);
875 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
879 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
881 struct lprocfs_stats *stats = p->private;
883 return (*pos >= stats->ls_num) ? NULL :
884 &(stats->ls_percpu[0]->lp_cntr[*pos]);
887 /* seq file export of one lprocfs counter */
888 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
890 struct lprocfs_stats *stats = p->private;
891 struct lprocfs_counter *cntr = v;
892 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
894 unsigned int num_cpu;
896 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
898 do_gettimeofday(&now);
899 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
900 "snapshot_time", now.tv_sec, now.tv_usec);
904 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
906 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
909 num_cpu = num_possible_cpus();
911 for (i = 0; i < num_cpu; i++) {
912 struct lprocfs_counter *percpu_cntr =
913 &(stats->ls_percpu[i])->lp_cntr[idx];
917 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
918 t.lc_count = percpu_cntr->lc_count;
919 t.lc_sum = percpu_cntr->lc_sum;
920 t.lc_min = percpu_cntr->lc_min;
921 t.lc_max = percpu_cntr->lc_max;
922 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
923 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
924 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
925 ret.lc_count += t.lc_count;
926 ret.lc_sum += t.lc_sum;
927 if (t.lc_min < ret.lc_min)
928 ret.lc_min = t.lc_min;
929 if (t.lc_max > ret.lc_max)
930 ret.lc_max = t.lc_max;
931 ret.lc_sumsquare += t.lc_sumsquare;
934 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
935 ret.lc_count, cntr->lc_units);
939 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
940 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
941 ret.lc_min, ret.lc_max, ret.lc_sum);
944 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
945 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
949 rc = seq_printf(p, "\n");
951 return (rc < 0) ? rc : 0;
954 struct seq_operations lprocfs_stats_seq_sops = {
955 start: lprocfs_stats_seq_start,
956 stop: lprocfs_stats_seq_stop,
957 next: lprocfs_stats_seq_next,
958 show: lprocfs_stats_seq_show,
961 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
963 struct proc_dir_entry *dp = PDE(inode);
964 struct seq_file *seq;
967 LPROCFS_ENTRY_AND_CHECK(dp);
968 rc = seq_open(file, &lprocfs_stats_seq_sops);
973 seq = file->private_data;
974 seq->private = dp->data;
978 struct file_operations lprocfs_stats_seq_fops = {
979 .owner = THIS_MODULE,
980 .open = lprocfs_stats_seq_open,
982 .write = lprocfs_stats_seq_write,
984 .release = lprocfs_seq_release,
987 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
988 struct lprocfs_stats *stats)
990 struct proc_dir_entry *entry;
991 LASSERT(root != NULL);
993 entry = create_proc_entry(name, 0644, root);
996 entry->proc_fops = &lprocfs_stats_seq_fops;
997 entry->data = (void *)stats;
1001 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1002 unsigned conf, const char *name, const char *units)
1004 struct lprocfs_counter *c;
1006 unsigned int num_cpu;
1008 LASSERT(stats != NULL);
1010 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1012 for (i = 0; i < num_cpu; i++) {
1013 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1014 c->lc_config = conf;
1017 c->lc_min = LC_MIN_INIT;
1020 c->lc_units = units;
1023 lprocfs_stats_unlock(stats);
1025 EXPORT_SYMBOL(lprocfs_counter_init);
1027 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1029 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1030 LASSERT(coffset < stats->ls_num); \
1031 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1034 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1036 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1037 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1038 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1039 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1040 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1041 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1042 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1043 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1044 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1045 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1046 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1047 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1048 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1049 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1050 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1051 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1052 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1053 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1054 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1055 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1056 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1057 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1058 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1059 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1060 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1061 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1062 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1063 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1064 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1065 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1066 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1067 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1068 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1069 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1070 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1071 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1072 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1073 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1074 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1075 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1076 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1077 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1078 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1079 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1080 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1081 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1082 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1083 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1084 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1085 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1086 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1087 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1088 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1089 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1090 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1091 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1092 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1093 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1094 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1095 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1096 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1097 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1098 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1099 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1100 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1101 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1102 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1103 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1104 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1105 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1106 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1107 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1108 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1109 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1110 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1113 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1115 struct lprocfs_stats *stats;
1116 unsigned int num_stats;
1119 LASSERT(obd->obd_stats == NULL);
1120 LASSERT(obd->obd_proc_entry != NULL);
1121 LASSERT(obd->obd_cntr_base == 0);
1123 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1124 num_private_stats - 1 /* o_owner */;
1125 stats = lprocfs_alloc_stats(num_stats, 0);
1129 lprocfs_init_ops_stats(num_private_stats, stats);
1131 for (i = num_private_stats; i < num_stats; i++) {
1132 /* If this LBUGs, it is likely that an obd
1133 * operation was added to struct obd_ops in
1134 * <obd.h>, and that the corresponding line item
1135 * LPROCFS_OBD_OP_INIT(.., .., opname)
1136 * is missing from the list above. */
1137 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1138 "Missing obd_stat initializer obd_op "
1139 "operation at offset %d.\n", i - num_private_stats);
1141 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1143 lprocfs_free_stats(&stats);
1145 obd->obd_stats = stats;
1146 obd->obd_cntr_base = num_private_stats;
1151 void lprocfs_free_obd_stats(struct obd_device *obd)
1154 lprocfs_free_stats(&obd->obd_stats);
1157 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1159 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1160 LASSERT(coffset < stats->ls_num); \
1161 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1164 int lprocfs_alloc_md_stats(struct obd_device *obd,
1165 unsigned num_private_stats)
1167 struct lprocfs_stats *stats;
1168 unsigned int num_stats;
1171 LASSERT(obd->md_stats == NULL);
1172 LASSERT(obd->obd_proc_entry != NULL);
1173 LASSERT(obd->md_cntr_base == 0);
1175 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1177 stats = lprocfs_alloc_stats(num_stats, 0);
1181 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1182 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1183 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1184 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1185 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1186 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1187 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1188 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1189 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1190 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1191 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1192 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1193 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1194 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1195 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1196 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1197 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1198 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1199 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1200 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1201 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1202 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1203 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1204 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1205 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1206 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1207 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1208 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1209 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1210 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1212 for (i = num_private_stats; i < num_stats; i++) {
1213 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1214 CERROR("Missing md_stat initializer md_op "
1215 "operation at offset %d. Aborting.\n",
1216 i - num_private_stats);
1220 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1222 lprocfs_free_stats(&stats);
1224 obd->md_stats = stats;
1225 obd->md_cntr_base = num_private_stats;
1230 void lprocfs_free_md_stats(struct obd_device *obd)
1232 struct lprocfs_stats *stats = obd->md_stats;
1234 if (stats != NULL) {
1235 obd->md_stats = NULL;
1236 lprocfs_free_stats(&stats);
1240 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1241 int *eof, void *data)
1243 struct obd_export *exp = (struct obd_export*)data;
1244 LASSERT(exp != NULL);
1246 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1249 struct exp_uuid_cb_data {
1256 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1258 struct obd_export *exp = (struct obd_export *)obj;
1259 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1261 if (exp->exp_nid_stats)
1262 *data->len += snprintf((data->page + *data->len),
1263 data->count, "%s\n",
1264 obd_uuid2str(&exp->exp_client_uuid));
1267 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1268 int *eof, void *data)
1270 struct nid_stat *stats = (struct nid_stat *)data;
1271 struct exp_uuid_cb_data cb_data;
1272 struct obd_device *obd = stats->nid_obd;
1277 LASSERT(obd != NULL);
1279 cb_data.page = page;
1280 cb_data.count = count;
1283 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1284 &stats->nid, lprocfs_exp_print_uuid,
1286 return (*cb_data.len);
1289 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1290 int count, int *eof, void *data)
1293 return snprintf(page, count, "%s\n",
1294 "Write into this file to clear all nid stats and "
1295 "stale nid entries");
1297 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1299 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1301 struct nid_stat *stat = obj;
1304 /* object has only hash + iterate_all references.
1305 * add/delete blocked by hash bucket lock */
1306 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1307 if(stat->nid_exp_ref_count == 2) {
1308 hlist_del_init(&stat->nid_hash);
1309 stat->nid_exp_ref_count--;
1310 spin_lock(&stat->nid_obd->obd_nid_lock);
1311 list_del_init(&stat->nid_list);
1312 spin_unlock(&stat->nid_obd->obd_nid_lock);
1313 list_add(&stat->nid_list, data);
1317 /* we has reference to object - only clear data*/
1318 if (stat->nid_stats)
1319 lprocfs_clear_stats(stat->nid_stats);
1321 if (stat->nid_brw_stats) {
1322 for (i = 0; i < BRW_LAST; i++)
1323 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1329 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1330 unsigned long count, void *data)
1332 struct obd_device *obd = (struct obd_device *)data;
1333 struct nid_stat *client_stat;
1334 CFS_LIST_HEAD(free_list);
1336 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1337 lprocfs_nid_stats_clear_write_cb, &free_list);
1339 while (!list_empty(&free_list)) {
1340 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1341 list_del_init(&client_stat->nid_list);
1342 lprocfs_free_client_stats(client_stat);
1347 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1349 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1352 struct nid_stat *tmp = NULL, *tmp1;
1353 struct obd_device *obd = NULL;
1358 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1359 !exp->exp_obd->obd_nid_stats_hash_body)
1362 /* not test against zero because eric say:
1363 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1365 if (!nid || *nid == LNET_NID_ANY)
1370 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1372 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1377 tmp->nid_obd = exp->exp_obd;
1378 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1380 /* protect competitive add to list, not need locking on destroy */
1381 spin_lock(&obd->obd_nid_lock);
1382 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1383 spin_unlock(&obd->obd_nid_lock);
1385 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1387 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1388 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1391 exp->exp_nid_stats = tmp1;
1392 GOTO(destroy_new, rc = 0);
1394 /* not found - create */
1395 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1396 obd->obd_proc_exports_entry, NULL, NULL);
1397 if (!tmp->nid_proc) {
1398 CERROR("Error making export directory for"
1399 " nid %s\n", libcfs_nid2str(*nid));
1400 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1402 GOTO(destroy_new, rc = -ENOMEM);
1405 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1406 lprocfs_exp_rd_uuid, NULL, tmp);
1408 CWARN("Error adding the uuid file\n");
1410 exp->exp_nid_stats = tmp;
1415 spin_lock(&obd->obd_nid_lock);
1416 list_del(&tmp->nid_list);
1417 spin_unlock(&obd->obd_nid_lock);
1418 OBD_FREE(tmp, sizeof(struct nid_stat));
1422 int lprocfs_exp_cleanup(struct obd_export *exp)
1424 struct nid_stat *stat = exp->exp_nid_stats;
1429 stat->nid_exp_ref_count--;
1430 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1432 exp->exp_nid_stats = NULL;
1436 int lprocfs_write_helper(const char *buffer, unsigned long count,
1439 return lprocfs_write_frac_helper(buffer, count, val, 1);
1442 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1445 char kernbuf[20], *end, *pbuf;
1447 if (count > (sizeof(kernbuf) - 1))
1450 if (copy_from_user(kernbuf, buffer, count))
1453 kernbuf[count] = '\0';
1460 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1464 if (end != NULL && *end == '.') {
1465 int temp_val, pow = 1;
1469 if (strlen(pbuf) > 5)
1470 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1472 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1475 for (i = 0; i < (end - pbuf); i++)
1478 *val += temp_val / pow;
1484 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1486 long decimal_val, frac_val;
1492 decimal_val = val / mult;
1493 prtn = snprintf(buffer, count, "%ld", decimal_val);
1494 frac_val = val % mult;
1496 if (prtn < (count - 4) && frac_val > 0) {
1498 int i, temp_mult = 1, frac_bits = 0;
1500 temp_frac = frac_val * 10;
1501 buffer[prtn++] = '.';
1502 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1503 buffer[prtn++] ='0';
1508 Need to think these cases :
1509 1. #echo x.00 > /proc/xxx output result : x
1510 2. #echo x.0x > /proc/xxx output result : x.0x
1511 3. #echo x.x0 > /proc/xxx output result : x.x
1512 4. #echo x.xx > /proc/xxx output result : x.xx
1513 Only reserved 2bits fraction.
1515 for (i = 0; i < (5 - prtn); i++)
1518 frac_bits = min((int)count - prtn, 3 - frac_bits);
1519 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1522 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1524 if (buffer[prtn] == '.') {
1531 buffer[prtn++] ='\n';
1535 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1537 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1540 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1541 __u64 *val, int mult)
1543 char kernbuf[22], *end, *pbuf;
1544 __u64 whole, frac = 0, units;
1545 unsigned frac_d = 1;
1547 if (count > (sizeof(kernbuf) - 1) )
1550 if (copy_from_user(kernbuf, buffer, count))
1553 kernbuf[count] = '\0';
1560 whole = simple_strtoull(pbuf, &end, 10);
1564 if (end != NULL && *end == '.') {
1568 /* need to limit frac_d to a __u32 */
1569 if (strlen(pbuf) > 10)
1572 frac = simple_strtoull(pbuf, &end, 10);
1573 /* count decimal places */
1574 for (i = 0; i < (end - pbuf); i++)
1591 /* Specified units override the multiplier */
1593 mult = mult < 0 ? -units : units;
1596 do_div(frac, frac_d);
1597 *val = whole * mult + frac;
1601 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1602 char *name, mode_t mode,
1603 struct file_operations *seq_fops, void *data)
1605 struct proc_dir_entry *entry;
1608 entry = create_proc_entry(name, mode, parent);
1611 entry->proc_fops = seq_fops;
1616 EXPORT_SYMBOL(lprocfs_seq_create);
1618 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1620 struct file_operations *seq_fops,
1623 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1624 mode, seq_fops, data));
1626 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1628 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1630 if (value >= OBD_HIST_MAX)
1631 value = OBD_HIST_MAX - 1;
1633 spin_lock(&oh->oh_lock);
1634 oh->oh_buckets[value]++;
1635 spin_unlock(&oh->oh_lock);
1637 EXPORT_SYMBOL(lprocfs_oh_tally);
1639 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1643 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1646 lprocfs_oh_tally(oh, val);
1648 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1650 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1652 unsigned long ret = 0;
1655 for (i = 0; i < OBD_HIST_MAX; i++)
1656 ret += oh->oh_buckets[i];
1659 EXPORT_SYMBOL(lprocfs_oh_sum);
1661 void lprocfs_oh_clear(struct obd_histogram *oh)
1663 spin_lock(&oh->oh_lock);
1664 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1665 spin_unlock(&oh->oh_lock);
1667 EXPORT_SYMBOL(lprocfs_oh_clear);
1669 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1670 int count, int *eof, void *data)
1672 struct obd_device *obd = data;
1675 LASSERT(obd != NULL);
1676 LASSERT(count >= 0);
1678 /* Set start of user data returned to
1679 page + off since the user may have
1680 requested to read much smaller than
1681 what we need to read */
1682 *start = page + off;
1684 /* We know we are allocated a page here.
1685 Also we know that this function will
1686 not need to write more than a page
1687 so we can truncate at CFS_PAGE_SIZE. */
1688 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1690 /* Initialize the page */
1691 memset(page, 0, size);
1693 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1696 if (obd->obd_max_recoverable_clients == 0) {
1697 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1703 /* sampled unlocked, but really... */
1704 if (obd->obd_recovering == 0) {
1705 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1708 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1709 obd->obd_recovery_start) <= 0)
1712 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1713 obd->obd_recovery_end) <= 0)
1716 /* Number of clients have have completed recovery */
1717 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1718 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1721 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1722 obd->obd_recoverable_clients) <= 0)
1725 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1726 obd->obd_next_recovery_transno - 1) <= 0)
1729 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1733 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1736 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1737 obd->obd_recovery_start) <= 0)
1740 if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1741 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1742 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1745 if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1746 obd->obd_connected_clients,
1747 obd->obd_max_recoverable_clients) <= 0)
1750 /* Number of clients have have completed recovery */
1751 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1752 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1753 obd->obd_max_recoverable_clients) <= 0)
1756 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1757 obd->obd_replayed_requests) <= 0)
1760 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1761 obd->obd_requests_queued_for_recovery) <= 0)
1764 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1765 obd->obd_next_recovery_transno) <= 0)
1771 return min(count, len - (int)off);
1773 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1775 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1776 int count, int *eof, void *data)
1778 struct obd_device *obd = (struct obd_device *)data;
1779 LASSERT(obd != NULL);
1781 return snprintf(page, count, "%lu\n",
1782 obd->obd_recovery_max_time);
1784 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1786 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1787 unsigned long count, void *data)
1789 struct obd_device *obd = (struct obd_device *)data;
1791 LASSERT(obd != NULL);
1793 rc = lprocfs_write_helper(buffer, count, &val);
1797 obd->obd_recovery_max_time = val;
1800 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1802 EXPORT_SYMBOL(lprocfs_register);
1803 EXPORT_SYMBOL(lprocfs_srch);
1804 EXPORT_SYMBOL(lprocfs_remove);
1805 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1806 EXPORT_SYMBOL(lprocfs_add_vars);
1807 EXPORT_SYMBOL(lprocfs_obd_setup);
1808 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1809 EXPORT_SYMBOL(lprocfs_add_simple);
1810 EXPORT_SYMBOL(lprocfs_add_symlink);
1811 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1812 EXPORT_SYMBOL(lprocfs_alloc_stats);
1813 EXPORT_SYMBOL(lprocfs_free_stats);
1814 EXPORT_SYMBOL(lprocfs_clear_stats);
1815 EXPORT_SYMBOL(lprocfs_register_stats);
1816 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1817 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1818 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1819 EXPORT_SYMBOL(lprocfs_exp_setup);
1820 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1822 EXPORT_SYMBOL(lprocfs_rd_u64);
1823 EXPORT_SYMBOL(lprocfs_rd_atomic);
1824 EXPORT_SYMBOL(lprocfs_wr_atomic);
1825 EXPORT_SYMBOL(lprocfs_rd_uint);
1826 EXPORT_SYMBOL(lprocfs_wr_uint);
1827 EXPORT_SYMBOL(lprocfs_rd_uuid);
1828 EXPORT_SYMBOL(lprocfs_rd_name);
1829 EXPORT_SYMBOL(lprocfs_rd_fstype);
1830 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1831 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1832 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1833 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1835 EXPORT_SYMBOL(lprocfs_rd_blksize);
1836 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1837 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1838 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1839 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1840 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1842 EXPORT_SYMBOL(lprocfs_write_helper);
1843 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1844 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1845 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1846 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);