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;
64 while (temp != NULL) {
65 if (strcmp(temp->name, name) == 0)
74 /* lprocfs API calls */
76 /* Function that emulates snprintf but also has the side effect of advancing
77 the page pointer for the next write into the buffer, incrementing the total
78 length written to the buffer, and decrementing the size left in the
80 static int lprocfs_obd_snprintf(char **page, int end, int *len,
81 const char *format, ...)
89 va_start(list, format);
90 n = vsnprintf(*page, end - *len, format, list);
93 *page += n; *len += n;
97 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
98 read_proc_t *read_proc, write_proc_t *write_proc,
101 struct proc_dir_entry *proc;
104 if (root == NULL || name == NULL)
110 proc = create_proc_entry(name, mode, root);
112 CERROR("LprocFS: No memory to create /proc entry %s", name);
115 proc->read_proc = read_proc;
116 proc->write_proc = write_proc;
121 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
122 struct proc_dir_entry *parent, const char *dest)
124 struct proc_dir_entry *entry;
126 if (parent == NULL || dest == NULL)
129 entry = proc_symlink(name, parent, dest);
131 CERROR("LprocFS: Could not create symbolic link from %s to %s",
136 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
137 size_t size, loff_t *ppos)
139 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
140 char *page, *start = NULL;
141 int rc = 0, eof = 1, count;
143 if (*ppos >= CFS_PAGE_SIZE)
146 page = (char *)__get_free_page(GFP_KERNEL);
151 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
152 if (!dp->deleted && dp->read_proc)
153 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
159 /* for lustre proc read, the read count must be less than PAGE_SIZE */
168 start = page + *ppos;
169 } else if (start < page) {
173 count = (rc < size) ? rc : size;
174 if (copy_to_user(buf, start, count)) {
181 free_page((unsigned long)page);
185 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
187 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
191 if (!dp->deleted && dp->write_proc)
192 rc = dp->write_proc(f, buf, size, dp->data);
197 static struct file_operations lprocfs_generic_fops = {
198 .owner = THIS_MODULE,
199 .read = lprocfs_fops_read,
200 .write = lprocfs_fops_write,
203 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
205 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
206 struct obd_device *obd = dp->data;
208 atomic_inc(&obd->obd_evict_inprogress);
213 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
215 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
216 struct obd_device *obd = dp->data;
218 atomic_dec(&obd->obd_evict_inprogress);
219 wake_up(&obd->obd_evict_inprogress_waitq);
224 struct file_operations lprocfs_evict_client_fops = {
225 .owner = THIS_MODULE,
226 .read = lprocfs_fops_read,
227 .write = lprocfs_fops_write,
228 .open = lprocfs_evict_client_open,
229 .release = lprocfs_evict_client_release,
231 EXPORT_SYMBOL(lprocfs_evict_client_fops);
233 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
236 if (root == NULL || list == NULL)
239 while (list->name != NULL) {
240 struct proc_dir_entry *cur_root, *proc;
241 char *pathcopy, *cur, *next, pathbuf[64];
242 int pathsize = strlen(list->name) + 1;
247 /* need copy of path for strsep */
248 if (strlen(list->name) > sizeof(pathbuf) - 1) {
249 OBD_ALLOC(pathcopy, pathsize);
250 if (pathcopy == NULL)
257 strcpy(pathcopy, list->name);
259 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
260 if (*cur =='\0') /* skip double/trailing "/" */
263 proc = lprocfs_srch(cur_root, cur);
264 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
265 cur_root->name, cur, next,
266 (proc ? "exists" : "new"));
268 cur_root = (proc ? proc :
269 proc_mkdir(cur, cur_root));
270 } else if (proc == NULL) {
274 if (list->write_fptr)
276 proc = create_proc_entry(cur, mode, cur_root);
280 if (pathcopy != pathbuf)
281 OBD_FREE(pathcopy, pathsize);
283 if (cur_root == NULL || proc == NULL) {
284 CERROR("LprocFS: No memory to create /proc entry %s",
290 proc->proc_fops = list->fops;
292 proc->proc_fops = &lprocfs_generic_fops;
293 proc->read_proc = list->read_fptr;
294 proc->write_proc = list->write_fptr;
295 proc->data = (list->data ? list->data : data);
301 void lprocfs_remove(struct proc_dir_entry **rooth)
303 struct proc_dir_entry *root = *rooth;
304 struct proc_dir_entry *temp = root;
305 struct proc_dir_entry *rm_entry;
306 struct proc_dir_entry *parent;
312 parent = root->parent;
313 LASSERT(parent != NULL);
314 LPROCFS_ENTRY(); /* search vs remove race */
317 while (temp->subdir != NULL)
323 /* Memory corruption once caused this to fail, and
324 without this LASSERT we would loop here forever. */
325 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
326 "0x%p %s/%s len %d\n", rm_entry, temp->name,
327 rm_entry->name, (int)strlen(rm_entry->name));
329 /* Now, the rm_entry->deleted flags is protected
330 * by _lprocfs_lock. */
331 down_write(&_lprocfs_lock);
332 rm_entry->data = NULL;
333 remove_proc_entry(rm_entry->name, temp);
334 up_write(&_lprocfs_lock);
341 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
343 LASSERT(parent != NULL);
344 remove_proc_entry(name, parent);
347 struct proc_dir_entry *lprocfs_register(const char *name,
348 struct proc_dir_entry *parent,
349 struct lprocfs_vars *list, void *data)
351 struct proc_dir_entry *newchild;
353 newchild = lprocfs_srch(parent, name);
354 if (newchild != NULL) {
355 CERROR(" Lproc: Attempting to register %s more than once \n",
357 return ERR_PTR(-EALREADY);
360 newchild = proc_mkdir(name, parent);
361 if (newchild != NULL && list != NULL) {
362 int rc = lprocfs_add_vars(newchild, list, data);
364 lprocfs_remove(&newchild);
371 /* Generic callbacks */
372 int lprocfs_rd_uint(char *page, char **start, off_t off,
373 int count, int *eof, void *data)
375 unsigned int *temp = (unsigned int *)data;
376 return snprintf(page, count, "%u\n", *temp);
379 int lprocfs_wr_uint(struct file *file, const char *buffer,
380 unsigned long count, void *data)
383 char dummy[MAX_STRING_SIZE + 1], *end;
386 dummy[MAX_STRING_SIZE] = '\0';
387 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
390 tmp = simple_strtoul(dummy, &end, 0);
394 *p = (unsigned int)tmp;
398 int lprocfs_rd_u64(char *page, char **start, off_t off,
399 int count, int *eof, void *data)
401 LASSERT(data != NULL);
403 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
406 int lprocfs_rd_atomic(char *page, char **start, off_t off,
407 int count, int *eof, void *data)
409 atomic_t *atom = (atomic_t *)data;
410 LASSERT(atom != NULL);
412 return snprintf(page, count, "%d\n", atomic_read(atom));
415 int lprocfs_wr_atomic(struct file *file, const char *buffer,
416 unsigned long count, void *data)
418 atomic_t *atm = data;
422 rc = lprocfs_write_helper(buffer, count, &val);
429 atomic_set(atm, val);
433 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
434 int *eof, void *data)
436 struct obd_device *obd = (struct obd_device*)data;
438 LASSERT(obd != NULL);
440 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
443 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
444 int *eof, void* data)
446 struct obd_device *dev = (struct obd_device *)data;
448 LASSERT(dev != NULL);
449 LASSERT(dev->obd_name != NULL);
451 return snprintf(page, count, "%s\n", dev->obd_name);
454 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
457 struct obd_device *obd = (struct obd_device *)data;
459 LASSERT(obd != NULL);
460 LASSERT(obd->obd_fsops != NULL);
461 LASSERT(obd->obd_fsops->fs_type != NULL);
462 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
465 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
466 int *eof, void *data)
468 struct obd_statfs osfs;
469 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
473 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
478 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
479 int *eof, void *data)
481 struct obd_statfs osfs;
482 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
485 __u32 blk_size = osfs.os_bsize >> 10;
486 __u64 result = osfs.os_blocks;
488 while (blk_size >>= 1)
492 rc = snprintf(page, count, LPU64"\n", result);
497 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
498 int *eof, void *data)
500 struct obd_statfs osfs;
501 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
504 __u32 blk_size = osfs.os_bsize >> 10;
505 __u64 result = osfs.os_bfree;
507 while (blk_size >>= 1)
511 rc = snprintf(page, count, LPU64"\n", result);
516 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
517 int *eof, void *data)
519 struct obd_statfs osfs;
520 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
523 __u32 blk_size = osfs.os_bsize >> 10;
524 __u64 result = osfs.os_bavail;
526 while (blk_size >>= 1)
530 rc = snprintf(page, count, LPU64"\n", result);
535 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
536 int *eof, void *data)
538 struct obd_statfs osfs;
539 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
543 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
549 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
550 int *eof, void *data)
552 struct obd_statfs osfs;
553 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
557 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
562 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
563 int *eof, void *data)
565 struct obd_device *obd = (struct obd_device *)data;
566 struct obd_import *imp;
567 char *imp_state_name = NULL;
570 LASSERT(obd != NULL);
571 LPROCFS_CLIMP_CHECK(obd);
572 imp = obd->u.cli.cl_import;
573 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
575 rc = snprintf(page, count, "%s\t%s%s\n",
576 obd2cli_tgt(obd), imp_state_name,
577 imp->imp_deactive ? "\tDEACTIVATED" : "");
579 LPROCFS_CLIMP_EXIT(obd);
583 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
584 int *eof, void *data)
586 struct obd_device *obd = (struct obd_device*)data;
587 struct ptlrpc_connection *conn;
590 LASSERT(obd != NULL);
592 LPROCFS_CLIMP_CHECK(obd);
593 conn = obd->u.cli.cl_import->imp_connection;
594 LASSERT(conn != NULL);
596 if (obd->u.cli.cl_import) {
597 rc = snprintf(page, count, "%s\n",
598 conn->c_remote_uuid.uuid);
600 rc = snprintf(page, count, "%s\n", "<none>");
603 LPROCFS_CLIMP_EXIT(obd);
607 int lprocfs_at_hist_helper(char *page, int count, int rc,
608 struct adaptive_timeout *at)
611 for (i = 0; i < AT_BINS; i++)
612 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
613 rc += snprintf(page + rc, count - rc, "\n");
617 /* See also ptlrpc_lprocfs_rd_timeouts */
618 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
619 int *eof, void *data)
621 struct obd_device *obd = (struct obd_device *)data;
622 struct obd_import *imp;
623 unsigned int cur, worst;
628 LASSERT(obd != NULL);
629 LPROCFS_CLIMP_CHECK(obd);
630 imp = obd->u.cli.cl_import;
633 now = cfs_time_current_sec();
635 /* Some network health info for kicks */
636 s2dhms(&ts, now - imp->imp_last_reply_time);
637 rc += snprintf(page + rc, count - rc,
638 "%-10s : %ld, "DHMS_FMT" ago\n",
639 "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
642 cur = at_get(&imp->imp_at.iat_net_latency);
643 worst = imp->imp_at.iat_net_latency.at_worst_ever;
644 worstt = imp->imp_at.iat_net_latency.at_worst_time;
645 s2dhms(&ts, now - worstt);
646 rc += snprintf(page + rc, count - rc,
647 "%-10s : cur %3u worst %3u (at %ld, "DHMS_FMT" ago) ",
648 "network", cur, worst, worstt, DHMS_VARS(&ts));
649 rc = lprocfs_at_hist_helper(page, count, rc,
650 &imp->imp_at.iat_net_latency);
652 for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
653 if (imp->imp_at.iat_portal[i] == 0)
655 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
656 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
657 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
658 s2dhms(&ts, now - worstt);
659 rc += snprintf(page + rc, count - rc,
660 "portal %-2d : cur %3u worst %3u (at %ld, "
661 DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
662 cur, worst, worstt, DHMS_VARS(&ts));
663 rc = lprocfs_at_hist_helper(page, count, rc,
664 &imp->imp_at.iat_service_estimate[i]);
667 LPROCFS_CLIMP_EXIT(obd);
671 static const char *obd_connect_names[] = {
698 "mds_mds_connection",
701 "alt_checksum_algorithm",
706 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
707 int count, int *eof, void *data)
709 struct obd_device *obd = data;
710 __u64 mask = 1, flags;
713 LPROCFS_CLIMP_CHECK(obd);
714 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
715 ret = snprintf(page, count, "flags="LPX64"\n", flags);
716 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
718 ret += snprintf(page + ret, count - ret, "%s\n",
719 obd_connect_names[i]);
721 if (flags & ~(mask - 1))
722 ret += snprintf(page + ret, count - ret,
723 "unknown flags "LPX64"\n", flags & ~(mask - 1));
725 LPROCFS_CLIMP_EXIT(obd);
728 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
730 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
731 int *eof, void *data)
733 struct obd_device *obd = (struct obd_device*)data;
735 LASSERT(obd != NULL);
737 return snprintf(page, count, "%u\n", obd->obd_num_exports);
740 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
741 int *eof, void *data)
743 struct obd_type *class = (struct obd_type*) data;
745 LASSERT(class != NULL);
747 return snprintf(page, count, "%d\n", class->typ_refcnt);
750 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
754 LASSERT(obd != NULL);
755 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
756 LASSERT(obd->obd_type->typ_procroot != NULL);
758 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
759 obd->obd_type->typ_procroot,
761 if (IS_ERR(obd->obd_proc_entry)) {
762 rc = PTR_ERR(obd->obd_proc_entry);
763 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
764 obd->obd_proc_entry = NULL;
769 int lprocfs_obd_cleanup(struct obd_device *obd)
773 if (obd->obd_proc_exports_entry) {
774 /* Should be no exports left */
775 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
776 lprocfs_remove(&obd->obd_proc_exports_entry);
778 lprocfs_remove(&obd->obd_proc_entry);
782 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
784 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
785 client_stat->nid_proc, client_stat->nid_stats,
786 client_stat->nid_brw_stats);
788 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
789 client_stat->nid_exp_ref_count);
791 hlist_del_init(&client_stat->nid_hash);
793 if (client_stat->nid_proc)
794 lprocfs_remove(&client_stat->nid_proc);
796 if (client_stat->nid_stats)
797 lprocfs_free_stats(&client_stat->nid_stats);
799 if (client_stat->nid_brw_stats)
800 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
802 OBD_FREE(client_stat, sizeof(*client_stat));
807 void lprocfs_free_per_client_stats(struct obd_device *obd)
809 struct nid_stat *stat;
812 /* we need extra list - because hash_exit called to early */
813 /* not need locking because all clients is died */
814 while(!list_empty(&obd->obd_nid_stats)) {
815 stat = list_entry(obd->obd_nid_stats.next,
816 struct nid_stat, nid_list);
817 list_del_init(&stat->nid_list);
818 lprocfs_free_client_stats(stat);
824 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
825 enum lprocfs_stats_flags flags)
827 struct lprocfs_stats *stats;
828 unsigned int percpusize;
830 unsigned int num_cpu;
835 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
838 num_cpu = num_possible_cpus();
840 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
844 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
845 stats->ls_flags = flags;
846 spin_lock_init(&stats->ls_lock);
847 /* Use this lock only if there are no percpu areas */
852 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
854 percpusize = L1_CACHE_ALIGN(percpusize);
856 for (i = 0; i < num_cpu; i++) {
857 OBD_ALLOC(stats->ls_percpu[i], percpusize);
858 if (stats->ls_percpu[i] == NULL) {
859 for (j = 0; j < i; j++) {
860 OBD_FREE(stats->ls_percpu[j], percpusize);
861 stats->ls_percpu[j] = NULL;
866 if (stats->ls_percpu[0] == NULL) {
867 OBD_FREE(stats, offsetof(typeof(*stats),
868 ls_percpu[num_cpu]));
876 void lprocfs_free_stats(struct lprocfs_stats **statsh)
878 struct lprocfs_stats *stats = *statsh;
879 unsigned int num_cpu;
880 unsigned int percpusize;
883 if (stats == NULL || stats->ls_num == 0)
887 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
890 num_cpu = num_possible_cpus();
892 percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
894 percpusize = L1_CACHE_ALIGN(percpusize);
895 for (i = 0; i < num_cpu; i++)
896 OBD_FREE(stats->ls_percpu[i], percpusize);
897 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
900 void lprocfs_clear_stats(struct lprocfs_stats *stats)
902 struct lprocfs_counter *percpu_cntr;
904 unsigned int num_cpu;
906 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
908 for (i = 0; i < num_cpu; i++) {
909 for (j = 0; j < stats->ls_num; j++) {
910 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
911 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
912 percpu_cntr->lc_count = 0;
913 percpu_cntr->lc_sum = 0;
914 percpu_cntr->lc_min = LC_MIN_INIT;
915 percpu_cntr->lc_max = 0;
916 percpu_cntr->lc_sumsquare = 0;
917 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
921 lprocfs_stats_unlock(stats);
924 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
925 size_t len, loff_t *off)
927 struct seq_file *seq = file->private_data;
928 struct lprocfs_stats *stats = seq->private;
930 lprocfs_clear_stats(stats);
935 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
937 struct lprocfs_stats *stats = p->private;
938 /* return 1st cpu location */
939 return (*pos >= stats->ls_num) ? NULL :
940 &(stats->ls_percpu[0]->lp_cntr[*pos]);
943 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
947 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
949 struct lprocfs_stats *stats = p->private;
951 return (*pos >= stats->ls_num) ? NULL :
952 &(stats->ls_percpu[0]->lp_cntr[*pos]);
955 /* seq file export of one lprocfs counter */
956 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
958 struct lprocfs_stats *stats = p->private;
959 struct lprocfs_counter *cntr = v;
960 struct lprocfs_counter t, ret = { .lc_min = LC_MIN_INIT };
962 unsigned int num_cpu;
964 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
966 do_gettimeofday(&now);
967 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
968 "snapshot_time", now.tv_sec, now.tv_usec);
972 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
974 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
977 num_cpu = num_possible_cpus();
979 for (i = 0; i < num_cpu; i++) {
980 struct lprocfs_counter *percpu_cntr =
981 &(stats->ls_percpu[i])->lp_cntr[idx];
985 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
986 t.lc_count = percpu_cntr->lc_count;
987 t.lc_sum = percpu_cntr->lc_sum;
988 t.lc_min = percpu_cntr->lc_min;
989 t.lc_max = percpu_cntr->lc_max;
990 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
991 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
992 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
993 ret.lc_count += t.lc_count;
994 ret.lc_sum += t.lc_sum;
995 if (t.lc_min < ret.lc_min)
996 ret.lc_min = t.lc_min;
997 if (t.lc_max > ret.lc_max)
998 ret.lc_max = t.lc_max;
999 ret.lc_sumsquare += t.lc_sumsquare;
1002 rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1003 ret.lc_count, cntr->lc_units);
1007 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1008 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1009 ret.lc_min, ret.lc_max, ret.lc_sum);
1012 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1013 rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1017 rc = seq_printf(p, "\n");
1019 return (rc < 0) ? rc : 0;
1022 struct seq_operations lprocfs_stats_seq_sops = {
1023 start: lprocfs_stats_seq_start,
1024 stop: lprocfs_stats_seq_stop,
1025 next: lprocfs_stats_seq_next,
1026 show: lprocfs_stats_seq_show,
1029 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1031 struct proc_dir_entry *dp = PDE(inode);
1032 struct seq_file *seq;
1035 LPROCFS_ENTRY_AND_CHECK(dp);
1036 rc = seq_open(file, &lprocfs_stats_seq_sops);
1041 seq = file->private_data;
1042 seq->private = dp->data;
1046 struct file_operations lprocfs_stats_seq_fops = {
1047 .owner = THIS_MODULE,
1048 .open = lprocfs_stats_seq_open,
1050 .write = lprocfs_stats_seq_write,
1051 .llseek = seq_lseek,
1052 .release = lprocfs_seq_release,
1055 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1056 struct lprocfs_stats *stats)
1058 struct proc_dir_entry *entry;
1059 LASSERT(root != NULL);
1061 entry = create_proc_entry(name, 0644, root);
1064 entry->proc_fops = &lprocfs_stats_seq_fops;
1065 entry->data = (void *)stats;
1069 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1070 unsigned conf, const char *name, const char *units)
1072 struct lprocfs_counter *c;
1074 unsigned int num_cpu;
1076 LASSERT(stats != NULL);
1078 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1080 for (i = 0; i < num_cpu; i++) {
1081 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1082 c->lc_config = conf;
1085 c->lc_min = LC_MIN_INIT;
1088 c->lc_units = units;
1091 lprocfs_stats_unlock(stats);
1093 EXPORT_SYMBOL(lprocfs_counter_init);
1095 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1097 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1098 LASSERT(coffset < stats->ls_num); \
1099 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1102 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1104 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1105 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1106 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1107 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1108 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1109 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1110 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1111 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1112 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1113 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1114 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1115 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1116 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1117 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1118 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1119 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1120 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1121 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1122 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1123 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1124 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1125 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1126 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1127 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1128 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1129 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1130 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1131 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1132 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1133 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1134 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1135 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1136 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1137 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1138 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1139 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1140 LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1141 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1142 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1143 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1144 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1145 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1146 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1147 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1148 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1149 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1150 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1151 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1152 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1153 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1154 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1155 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1156 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1157 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1158 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1159 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1160 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1161 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1162 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1163 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1164 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1165 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1166 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1167 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1168 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1169 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1170 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1171 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1172 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1173 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1174 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1175 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1176 LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1177 LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1178 LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1181 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1183 struct lprocfs_stats *stats;
1184 unsigned int num_stats;
1187 LASSERT(obd->obd_stats == NULL);
1188 LASSERT(obd->obd_proc_entry != NULL);
1189 LASSERT(obd->obd_cntr_base == 0);
1191 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1192 num_private_stats - 1 /* o_owner */;
1193 stats = lprocfs_alloc_stats(num_stats, 0);
1197 lprocfs_init_ops_stats(num_private_stats, stats);
1199 for (i = num_private_stats; i < num_stats; i++) {
1200 /* If this LBUGs, it is likely that an obd
1201 * operation was added to struct obd_ops in
1202 * <obd.h>, and that the corresponding line item
1203 * LPROCFS_OBD_OP_INIT(.., .., opname)
1204 * is missing from the list above. */
1205 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1206 "Missing obd_stat initializer obd_op "
1207 "operation at offset %d.\n", i - num_private_stats);
1209 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1211 lprocfs_free_stats(&stats);
1213 obd->obd_stats = stats;
1214 obd->obd_cntr_base = num_private_stats;
1219 void lprocfs_free_obd_stats(struct obd_device *obd)
1222 lprocfs_free_stats(&obd->obd_stats);
1225 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1227 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1228 LASSERT(coffset < stats->ls_num); \
1229 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1232 int lprocfs_alloc_md_stats(struct obd_device *obd,
1233 unsigned num_private_stats)
1235 struct lprocfs_stats *stats;
1236 unsigned int num_stats;
1239 LASSERT(obd->md_stats == NULL);
1240 LASSERT(obd->obd_proc_entry != NULL);
1241 LASSERT(obd->md_cntr_base == 0);
1243 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1245 stats = lprocfs_alloc_stats(num_stats, 0);
1249 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1250 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1251 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1252 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1253 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1254 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1255 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1256 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1257 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1258 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1259 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1260 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1261 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1262 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1263 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1264 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1265 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1266 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1267 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1268 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1269 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1270 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1271 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1272 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1273 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1274 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1275 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1276 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1277 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1278 LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1280 for (i = num_private_stats; i < num_stats; i++) {
1281 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1282 CERROR("Missing md_stat initializer md_op "
1283 "operation at offset %d. Aborting.\n",
1284 i - num_private_stats);
1288 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1290 lprocfs_free_stats(&stats);
1292 obd->md_stats = stats;
1293 obd->md_cntr_base = num_private_stats;
1298 void lprocfs_free_md_stats(struct obd_device *obd)
1300 struct lprocfs_stats *stats = obd->md_stats;
1302 if (stats != NULL) {
1303 obd->md_stats = NULL;
1304 lprocfs_free_stats(&stats);
1308 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1309 int *eof, void *data)
1311 struct obd_export *exp = (struct obd_export*)data;
1312 LASSERT(exp != NULL);
1314 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1317 struct exp_uuid_cb_data {
1324 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1326 struct obd_export *exp = (struct obd_export *)obj;
1327 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1329 if (exp->exp_nid_stats)
1330 *data->len += snprintf((data->page + *data->len),
1331 data->count, "%s\n",
1332 obd_uuid2str(&exp->exp_client_uuid));
1335 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1336 int *eof, void *data)
1338 struct nid_stat *stats = (struct nid_stat *)data;
1339 struct exp_uuid_cb_data cb_data;
1340 struct obd_device *obd = stats->nid_obd;
1345 LASSERT(obd != NULL);
1347 cb_data.page = page;
1348 cb_data.count = count;
1351 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1352 &stats->nid, lprocfs_exp_print_uuid,
1354 return (*cb_data.len);
1357 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1358 int count, int *eof, void *data)
1361 return snprintf(page, count, "%s\n",
1362 "Write into this file to clear all nid stats and "
1363 "stale nid entries");
1365 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1367 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1369 struct nid_stat *stat = obj;
1372 /* object has only hash + iterate_all references.
1373 * add/delete blocked by hash bucket lock */
1374 CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1375 if(stat->nid_exp_ref_count == 2) {
1376 hlist_del_init(&stat->nid_hash);
1377 stat->nid_exp_ref_count--;
1378 spin_lock(&stat->nid_obd->obd_nid_lock);
1379 list_del_init(&stat->nid_list);
1380 spin_unlock(&stat->nid_obd->obd_nid_lock);
1381 list_add(&stat->nid_list, data);
1385 /* we has reference to object - only clear data*/
1386 if (stat->nid_stats)
1387 lprocfs_clear_stats(stat->nid_stats);
1389 if (stat->nid_brw_stats) {
1390 for (i = 0; i < BRW_LAST; i++)
1391 lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1397 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1398 unsigned long count, void *data)
1400 struct obd_device *obd = (struct obd_device *)data;
1401 struct nid_stat *client_stat;
1402 CFS_LIST_HEAD(free_list);
1404 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1405 lprocfs_nid_stats_clear_write_cb, &free_list);
1407 while (!list_empty(&free_list)) {
1408 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1409 list_del_init(&client_stat->nid_list);
1410 lprocfs_free_client_stats(client_stat);
1415 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1417 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1420 struct nid_stat *tmp = NULL, *tmp1;
1421 struct obd_device *obd = NULL;
1426 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1427 !exp->exp_obd->obd_nid_stats_hash_body)
1430 /* not test against zero because eric say:
1431 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1433 if (!nid || *nid == LNET_NID_ANY)
1438 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1440 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1445 tmp->nid_obd = exp->exp_obd;
1446 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1448 /* protect competitive add to list, not need locking on destroy */
1449 spin_lock(&obd->obd_nid_lock);
1450 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1451 spin_unlock(&obd->obd_nid_lock);
1453 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1455 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1456 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1459 exp->exp_nid_stats = tmp1;
1460 GOTO(destroy_new, rc = 0);
1462 /* not found - create */
1463 tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1464 obd->obd_proc_exports_entry, NULL, NULL);
1465 if (!tmp->nid_proc) {
1466 CERROR("Error making export directory for"
1467 " nid %s\n", libcfs_nid2str(*nid));
1468 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1470 GOTO(destroy_new, rc = -ENOMEM);
1473 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1474 lprocfs_exp_rd_uuid, NULL, tmp);
1476 CWARN("Error adding the uuid file\n");
1478 exp->exp_nid_stats = tmp;
1483 spin_lock(&obd->obd_nid_lock);
1484 list_del(&tmp->nid_list);
1485 spin_unlock(&obd->obd_nid_lock);
1486 OBD_FREE(tmp, sizeof(struct nid_stat));
1490 int lprocfs_exp_cleanup(struct obd_export *exp)
1492 struct nid_stat *stat = exp->exp_nid_stats;
1497 stat->nid_exp_ref_count--;
1498 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1500 exp->exp_nid_stats = NULL;
1504 int lprocfs_write_helper(const char *buffer, unsigned long count,
1507 return lprocfs_write_frac_helper(buffer, count, val, 1);
1510 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1513 char kernbuf[20], *end, *pbuf;
1515 if (count > (sizeof(kernbuf) - 1))
1518 if (copy_from_user(kernbuf, buffer, count))
1521 kernbuf[count] = '\0';
1528 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1532 if (end != NULL && *end == '.') {
1533 int temp_val, pow = 1;
1537 if (strlen(pbuf) > 5)
1538 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1540 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1543 for (i = 0; i < (end - pbuf); i++)
1546 *val += temp_val / pow;
1552 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1554 long decimal_val, frac_val;
1560 decimal_val = val / mult;
1561 prtn = snprintf(buffer, count, "%ld", decimal_val);
1562 frac_val = val % mult;
1564 if (prtn < (count - 4) && frac_val > 0) {
1566 int i, temp_mult = 1, frac_bits = 0;
1568 temp_frac = frac_val * 10;
1569 buffer[prtn++] = '.';
1570 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1571 buffer[prtn++] ='0';
1576 Need to think these cases :
1577 1. #echo x.00 > /proc/xxx output result : x
1578 2. #echo x.0x > /proc/xxx output result : x.0x
1579 3. #echo x.x0 > /proc/xxx output result : x.x
1580 4. #echo x.xx > /proc/xxx output result : x.xx
1581 Only reserved 2bits fraction.
1583 for (i = 0; i < (5 - prtn); i++)
1586 frac_bits = min((int)count - prtn, 3 - frac_bits);
1587 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1590 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1592 if (buffer[prtn] == '.') {
1599 buffer[prtn++] ='\n';
1603 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1605 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1608 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1609 __u64 *val, int mult)
1611 char kernbuf[22], *end, *pbuf;
1612 __u64 whole, frac = 0, units;
1613 unsigned frac_d = 1;
1615 if (count > (sizeof(kernbuf) - 1) )
1618 if (copy_from_user(kernbuf, buffer, count))
1621 kernbuf[count] = '\0';
1628 whole = simple_strtoull(pbuf, &end, 10);
1632 if (end != NULL && *end == '.') {
1636 /* need to limit frac_d to a __u32 */
1637 if (strlen(pbuf) > 10)
1640 frac = simple_strtoull(pbuf, &end, 10);
1641 /* count decimal places */
1642 for (i = 0; i < (end - pbuf); i++)
1659 /* Specified units override the multiplier */
1661 mult = mult < 0 ? -units : units;
1664 do_div(frac, frac_d);
1665 *val = whole * mult + frac;
1669 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1670 char *name, mode_t mode,
1671 struct file_operations *seq_fops, void *data)
1673 struct proc_dir_entry *entry;
1676 entry = create_proc_entry(name, mode, parent);
1679 entry->proc_fops = seq_fops;
1684 EXPORT_SYMBOL(lprocfs_seq_create);
1686 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1688 struct file_operations *seq_fops,
1691 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1692 mode, seq_fops, data));
1694 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1696 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1698 if (value >= OBD_HIST_MAX)
1699 value = OBD_HIST_MAX - 1;
1701 spin_lock(&oh->oh_lock);
1702 oh->oh_buckets[value]++;
1703 spin_unlock(&oh->oh_lock);
1705 EXPORT_SYMBOL(lprocfs_oh_tally);
1707 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1711 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1714 lprocfs_oh_tally(oh, val);
1716 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1718 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1720 unsigned long ret = 0;
1723 for (i = 0; i < OBD_HIST_MAX; i++)
1724 ret += oh->oh_buckets[i];
1727 EXPORT_SYMBOL(lprocfs_oh_sum);
1729 void lprocfs_oh_clear(struct obd_histogram *oh)
1731 spin_lock(&oh->oh_lock);
1732 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1733 spin_unlock(&oh->oh_lock);
1735 EXPORT_SYMBOL(lprocfs_oh_clear);
1737 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1738 int count, int *eof, void *data)
1740 struct obd_device *obd = data;
1743 LASSERT(obd != NULL);
1744 LASSERT(count >= 0);
1746 /* Set start of user data returned to
1747 page + off since the user may have
1748 requested to read much smaller than
1749 what we need to read */
1750 *start = page + off;
1752 /* We know we are allocated a page here.
1753 Also we know that this function will
1754 not need to write more than a page
1755 so we can truncate at CFS_PAGE_SIZE. */
1756 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1758 /* Initialize the page */
1759 memset(page, 0, size);
1761 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1763 if (obd->obd_max_recoverable_clients == 0) {
1764 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1770 /* sampled unlocked, but really... */
1771 if (obd->obd_recovering == 0) {
1772 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1774 if (lprocfs_obd_snprintf(&page, size, &len,
1775 "recovery_start: %lu\n",
1776 obd->obd_recovery_start) <= 0)
1778 if (lprocfs_obd_snprintf(&page, size, &len,
1779 "recovery_duration: %lu\n",
1780 obd->obd_recovery_end -
1781 obd->obd_recovery_start) <= 0)
1783 /* Number of clients that have completed recovery */
1784 if (lprocfs_obd_snprintf(&page, size, &len,
1785 "completed_clients: %d/%d\n",
1786 obd->obd_max_recoverable_clients -
1787 obd->obd_recoverable_clients,
1788 obd->obd_max_recoverable_clients) <= 0)
1790 if (lprocfs_obd_snprintf(&page, size, &len,
1791 "replayed_requests: %d\n",
1792 obd->obd_replayed_requests) <= 0)
1794 if (lprocfs_obd_snprintf(&page, size, &len,
1795 "last_transno: "LPD64"\n",
1796 obd->obd_next_recovery_transno - 1)<=0)
1801 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1803 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1804 obd->obd_recovery_start) <= 0)
1806 if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1807 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1808 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1810 if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1811 obd->obd_connected_clients,
1812 obd->obd_max_recoverable_clients) <= 0)
1814 /* Number of clients that have completed recovery */
1815 if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1816 obd->obd_max_recoverable_clients -
1817 obd->obd_recoverable_clients,
1818 obd->obd_max_recoverable_clients) <= 0)
1820 if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1821 obd->obd_replayed_requests) <= 0)
1823 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1824 obd->obd_requests_queued_for_recovery) <= 0)
1827 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1828 obd->obd_next_recovery_transno) <= 0)
1834 return min(count, len - (int)off);
1836 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1838 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1839 int count, int *eof, void *data)
1841 struct obd_device *obd = (struct obd_device *)data;
1842 LASSERT(obd != NULL);
1844 return snprintf(page, count, "%lu\n",
1845 obd->obd_recovery_max_time);
1847 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1849 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1850 unsigned long count, void *data)
1852 struct obd_device *obd = (struct obd_device *)data;
1854 LASSERT(obd != NULL);
1856 rc = lprocfs_write_helper(buffer, count, &val);
1860 obd->obd_recovery_max_time = val;
1863 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1865 EXPORT_SYMBOL(lprocfs_register);
1866 EXPORT_SYMBOL(lprocfs_srch);
1867 EXPORT_SYMBOL(lprocfs_remove);
1868 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1869 EXPORT_SYMBOL(lprocfs_add_vars);
1870 EXPORT_SYMBOL(lprocfs_obd_setup);
1871 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1872 EXPORT_SYMBOL(lprocfs_add_simple);
1873 EXPORT_SYMBOL(lprocfs_add_symlink);
1874 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1875 EXPORT_SYMBOL(lprocfs_alloc_stats);
1876 EXPORT_SYMBOL(lprocfs_free_stats);
1877 EXPORT_SYMBOL(lprocfs_clear_stats);
1878 EXPORT_SYMBOL(lprocfs_register_stats);
1879 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1880 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1881 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1882 EXPORT_SYMBOL(lprocfs_exp_setup);
1883 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1885 EXPORT_SYMBOL(lprocfs_rd_u64);
1886 EXPORT_SYMBOL(lprocfs_rd_atomic);
1887 EXPORT_SYMBOL(lprocfs_wr_atomic);
1888 EXPORT_SYMBOL(lprocfs_rd_uint);
1889 EXPORT_SYMBOL(lprocfs_wr_uint);
1890 EXPORT_SYMBOL(lprocfs_rd_uuid);
1891 EXPORT_SYMBOL(lprocfs_rd_name);
1892 EXPORT_SYMBOL(lprocfs_rd_fstype);
1893 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1894 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1895 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1896 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1897 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1898 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1899 EXPORT_SYMBOL(lprocfs_rd_blksize);
1900 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1901 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1902 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1903 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1904 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1906 EXPORT_SYMBOL(lprocfs_write_helper);
1907 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1908 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1909 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1910 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);