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 /* for bug 10866, global variable */
42 DECLARE_RWSEM(_lprocfs_lock);
43 EXPORT_SYMBOL(_lprocfs_lock);
45 int lprocfs_seq_release(struct inode *inode, struct file *file)
48 return seq_release(inode, file);
50 EXPORT_SYMBOL(lprocfs_seq_release);
52 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
55 struct proc_dir_entry *temp;
61 while (temp != NULL) {
62 if (strcmp(temp->name, name) == 0)
70 /* lprocfs API calls */
72 /* Function that emulates snprintf but also has the side effect of advancing
73 the page pointer for the next write into the buffer, incrementing the total
74 length written to the buffer, and decrementing the size left in the
76 static int lprocfs_obd_snprintf(char **page, int end, int *len,
77 const char *format, ...)
85 va_start(list, format);
86 n = vsnprintf(*page, end - *len, format, list);
89 *page += n; *len += n;
93 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
94 read_proc_t *read_proc, write_proc_t *write_proc,
97 struct proc_dir_entry *proc;
100 if (root == NULL || name == NULL)
106 proc = create_proc_entry(name, mode, root);
108 CERROR("LprocFS: No memory to create /proc entry %s", name);
111 proc->read_proc = read_proc;
112 proc->write_proc = write_proc;
118 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf, size_t size, loff_t *ppos)
120 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
121 char *page, *start = NULL;
122 int rc = 0, eof = 1, count;
124 if (*ppos >= PAGE_SIZE)
127 page = (char *)__get_free_page(GFP_KERNEL);
132 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
133 if (!dp->deleted && dp->read_proc)
134 rc = dp->read_proc(page, &start, *ppos, PAGE_SIZE,
140 /* for lustre proc read, the read count must be less than PAGE_SIZE */
149 start = page + *ppos;
150 } else if (start < page) {
154 count = (rc < size) ? rc : size;
155 if (copy_to_user(buf, start, count)) {
162 free_page((unsigned long)page);
166 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
168 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
172 if (!dp->deleted && dp->write_proc)
173 rc = dp->write_proc(f, buf, size, dp->data);
178 static struct file_operations lprocfs_generic_fops = {
179 .owner = THIS_MODULE,
180 .read = lprocfs_fops_read,
181 .write = lprocfs_fops_write,
185 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
188 if (root == NULL || list == NULL)
191 while (list->name != NULL) {
192 struct proc_dir_entry *cur_root, *proc;
193 char *pathcopy, *cur, *next, pathbuf[64];
194 int pathsize = strlen(list->name) + 1;
199 /* need copy of path for strsep */
200 if (strlen(list->name) > sizeof(pathbuf) - 1) {
201 OBD_ALLOC(pathcopy, pathsize);
202 if (pathcopy == NULL)
209 strcpy(pathcopy, list->name);
211 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
212 if (*cur =='\0') /* skip double/trailing "/" */
215 proc = lprocfs_srch(cur_root, cur);
216 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
217 cur_root->name, cur, next,
218 (proc ? "exists" : "new"));
220 cur_root = (proc ? proc :
221 proc_mkdir(cur, cur_root));
222 } else if (proc == NULL) {
226 if (list->write_fptr)
228 proc = create_proc_entry(cur, mode, cur_root);
232 if (pathcopy != pathbuf)
233 OBD_FREE(pathcopy, pathsize);
235 if (cur_root == NULL || proc == NULL) {
236 CERROR("LprocFS: No memory to create /proc entry %s",
241 proc->proc_fops = &lprocfs_generic_fops;
242 proc->read_proc = list->read_fptr;
243 proc->write_proc = list->write_fptr;
244 proc->data = (list->data ? list->data : data);
250 void lprocfs_remove(struct proc_dir_entry **rooth)
252 struct proc_dir_entry *root = *rooth;
253 struct proc_dir_entry *temp = root;
254 struct proc_dir_entry *rm_entry;
255 struct proc_dir_entry *parent;
261 parent = root->parent;
262 LASSERT(parent != NULL);
265 while (temp->subdir != NULL)
271 /* Memory corruption once caused this to fail, and
272 without this LASSERT we would loop here forever. */
273 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
274 "0x%p %s/%s len %d\n", rm_entry, temp->name,
275 rm_entry->name, (int)strlen(rm_entry->name));
277 /* Now, the rm_entry->deleted flags is protected
278 * by _lprocfs_lock. */
279 down_write(&_lprocfs_lock);
280 rm_entry->data = NULL;
281 remove_proc_entry(rm_entry->name, rm_entry->parent);
282 up_write(&_lprocfs_lock);
288 struct proc_dir_entry *lprocfs_register(const char *name,
289 struct proc_dir_entry *parent,
290 struct lprocfs_vars *list, void *data)
292 struct proc_dir_entry *newchild;
294 newchild = lprocfs_srch(parent, name);
295 if (newchild != NULL) {
296 CERROR(" Lproc: Attempting to register %s more than once \n",
298 return ERR_PTR(-EALREADY);
301 newchild = proc_mkdir(name, parent);
302 if (newchild != NULL && list != NULL) {
303 int rc = lprocfs_add_vars(newchild, list, data);
305 lprocfs_remove(&newchild);
312 /* Generic callbacks */
314 int lprocfs_rd_u64(char *page, char **start, off_t off,
315 int count, int *eof, void *data)
317 LASSERT(data != NULL);
319 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
322 int lprocfs_rd_atomic(char *page, char **start, off_t off,
323 int count, int *eof, void *data)
325 atomic_t *atom = (atomic_t *)data;
326 LASSERT(atom != NULL);
328 return snprintf(page, count, "%d\n", atomic_read(atom));
331 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
332 int *eof, void *data)
334 struct obd_device *obd = (struct obd_device*)data;
336 LASSERT(obd != NULL);
338 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
341 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
342 int *eof, void* data)
344 struct obd_device *dev = (struct obd_device *)data;
346 LASSERT(dev != NULL);
347 LASSERT(dev->obd_name != NULL);
349 return snprintf(page, count, "%s\n", dev->obd_name);
352 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
355 struct obd_device *obd = (struct obd_device *)data;
357 LASSERT(obd != NULL);
358 LASSERT(obd->obd_fsops != NULL);
359 LASSERT(obd->obd_fsops->fs_type != NULL);
360 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
363 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
364 int *eof, void *data)
366 struct obd_statfs osfs;
367 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
370 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
375 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
376 int *eof, void *data)
378 struct obd_statfs osfs;
379 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
381 __u32 blk_size = osfs.os_bsize >> 10;
382 __u64 result = osfs.os_blocks;
384 while (blk_size >>= 1)
388 rc = snprintf(page, count, LPU64"\n", result);
393 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
394 int *eof, void *data)
396 struct obd_statfs osfs;
397 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
399 __u32 blk_size = osfs.os_bsize >> 10;
400 __u64 result = osfs.os_bfree;
402 while (blk_size >>= 1)
406 rc = snprintf(page, count, LPU64"\n", result);
411 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
412 int *eof, void *data)
414 struct obd_statfs osfs;
415 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
417 __u32 blk_size = osfs.os_bsize >> 10;
418 __u64 result = osfs.os_bavail;
420 while (blk_size >>= 1)
424 rc = snprintf(page, count, LPU64"\n", result);
429 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
430 int *eof, void *data)
432 struct obd_statfs osfs;
433 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
436 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
442 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
443 int *eof, void *data)
445 struct obd_statfs osfs;
446 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
449 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
454 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
455 int *eof, void *data)
457 struct obd_device *obd = (struct obd_device *)data;
458 struct obd_import *imp;
459 char *imp_state_name = NULL;
462 LASSERT(obd != NULL);
463 LPROCFS_CLIMP_CHECK(obd);
464 imp = obd->u.cli.cl_import;
465 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
467 rc = snprintf(page, count, "%s\t%s%s\n",
468 obd2cli_tgt(obd), imp_state_name,
469 imp->imp_deactive ? "\tDEACTIVATED" : "");
471 LPROCFS_CLIMP_EXIT(obd);
475 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
476 int *eof, void *data)
478 struct obd_device *obd = (struct obd_device*)data;
479 struct ptlrpc_connection *conn;
482 LASSERT(obd != NULL);
483 LPROCFS_CLIMP_CHECK(obd);
484 conn = obd->u.cli.cl_import->imp_connection;
485 LASSERT(conn != NULL);
487 rc = snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
489 LPROCFS_CLIMP_EXIT(obd);
493 static const char *obd_connect_names[] = {
519 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
520 int count, int *eof, void *data)
522 struct obd_device *obd = data;
523 __u64 mask = 1, flags;
526 LPROCFS_CLIMP_CHECK(obd);
527 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
528 ret = snprintf(page, count, "flags="LPX64"\n", flags);
529 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
531 ret += snprintf(page + ret, count - ret, "%s\n",
532 obd_connect_names[i]);
534 if (flags & ~(mask - 1))
535 ret += snprintf(page + ret, count - ret,
536 "unknown flags "LPX64"\n", flags & ~(mask - 1));
538 LPROCFS_CLIMP_EXIT(obd);
541 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
543 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
544 int *eof, void *data)
546 struct obd_device *obd = (struct obd_device*)data;
548 LASSERT(obd != NULL);
550 return snprintf(page, count, "%u\n", obd->obd_num_exports);
553 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
554 int *eof, void *data)
556 struct obd_type *class = (struct obd_type*) data;
558 LASSERT(class != NULL);
560 return snprintf(page, count, "%d\n", class->typ_refcnt);
563 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
567 LASSERT(obd != NULL);
568 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
569 LASSERT(obd->obd_type->typ_procroot != NULL);
571 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
572 obd->obd_type->typ_procroot,
574 if (IS_ERR(obd->obd_proc_entry)) {
575 rc = PTR_ERR(obd->obd_proc_entry);
576 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
577 obd->obd_proc_entry = NULL;
582 int lprocfs_obd_cleanup(struct obd_device *obd)
586 if (obd->obd_proc_exports) {
587 /* Should be no exports left */
588 LASSERT(obd->obd_proc_exports->subdir == NULL);
589 lprocfs_remove(&obd->obd_proc_exports);
591 lprocfs_remove(&obd->obd_proc_entry);
595 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
597 struct lprocfs_stats *stats;
598 struct lprocfs_percpu *percpu;
599 unsigned int percpusize;
605 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
609 percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
610 stats->ls_percpu_size = num_online_cpus() * percpusize;
611 OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
612 if (stats->ls_percpu[0] == NULL) {
613 OBD_FREE(stats, offsetof(typeof(*stats),
614 ls_percpu[num_online_cpus()]));
619 for (i = 1; i < num_online_cpus(); i++)
620 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
626 void lprocfs_free_stats(struct lprocfs_stats **statsh)
628 struct lprocfs_stats *stats = *statsh;
630 if (!stats || (stats->ls_num == 0))
634 OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
635 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
638 void lprocfs_clear_stats(struct lprocfs_stats *stats)
640 struct lprocfs_counter *percpu_cntr;
643 for (i = 0; i < num_online_cpus(); i++) {
644 for (j = 0; j < stats->ls_num; j++) {
645 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
646 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
647 percpu_cntr->lc_count = 0;
648 percpu_cntr->lc_sum = 0;
649 percpu_cntr->lc_min = ~(__u64)0;
650 percpu_cntr->lc_max = 0;
651 percpu_cntr->lc_sumsquare = 0;
652 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
657 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
658 size_t len, loff_t *off)
660 struct seq_file *seq = file->private_data;
661 struct lprocfs_stats *stats = seq->private;
663 lprocfs_clear_stats(stats);
668 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
670 struct lprocfs_stats *stats = p->private;
671 /* return 1st cpu location */
672 return (*pos >= stats->ls_num) ? NULL :
673 &(stats->ls_percpu[0]->lp_cntr[*pos]);
676 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
680 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
682 struct lprocfs_stats *stats = p->private;
684 return (*pos >= stats->ls_num) ? NULL :
685 &(stats->ls_percpu[0]->lp_cntr[*pos]);
688 /* seq file export of one lprocfs counter */
689 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
691 struct lprocfs_stats *stats = p->private;
692 struct lprocfs_counter *cntr = v;
693 struct lprocfs_counter t, ret = { .lc_min = ~(__u64)0 };
696 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
698 do_gettimeofday(&now);
699 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
700 "snapshot_time", now.tv_sec, now.tv_usec);
704 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
706 for (i = 0; i < num_online_cpus(); i++) {
707 struct lprocfs_counter *percpu_cntr =
708 &(stats->ls_percpu[i])->lp_cntr[idx];
712 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
713 t.lc_count = percpu_cntr->lc_count;
714 t.lc_sum = percpu_cntr->lc_sum;
715 t.lc_min = percpu_cntr->lc_min;
716 t.lc_max = percpu_cntr->lc_max;
717 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
718 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
719 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
720 ret.lc_count += t.lc_count;
721 ret.lc_sum += t.lc_sum;
722 if (t.lc_min < ret.lc_min)
723 ret.lc_min = t.lc_min;
724 if (t.lc_max > ret.lc_max)
725 ret.lc_max = t.lc_max;
726 ret.lc_sumsquare += t.lc_sumsquare;
729 rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
730 ret.lc_count, cntr->lc_units);
734 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
735 rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
736 ret.lc_min, ret.lc_max, ret.lc_sum);
739 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
740 rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
744 rc = seq_printf(p, "\n");
746 return (rc < 0) ? rc : 0;
749 struct seq_operations lprocfs_stats_seq_sops = {
750 start: lprocfs_stats_seq_start,
751 stop: lprocfs_stats_seq_stop,
752 next: lprocfs_stats_seq_next,
753 show: lprocfs_stats_seq_show,
756 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
758 struct proc_dir_entry *dp = PDE(inode);
759 struct seq_file *seq;
762 LPROCFS_ENTRY_AND_CHECK(dp);
763 rc = seq_open(file, &lprocfs_stats_seq_sops);
769 seq = file->private_data;
770 seq->private = dp->data;
774 struct file_operations lprocfs_stats_seq_fops = {
775 .owner = THIS_MODULE,
776 .open = lprocfs_stats_seq_open,
778 .write = lprocfs_stats_seq_write,
780 .release = lprocfs_seq_release,
783 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
784 struct lprocfs_stats *stats)
786 struct proc_dir_entry *entry;
787 LASSERT(root != NULL);
789 entry = create_proc_entry(name, 0644, root);
792 entry->proc_fops = &lprocfs_stats_seq_fops;
793 entry->data = (void *)stats;
797 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
798 unsigned conf, const char *name, const char *units)
800 struct lprocfs_counter *c;
803 LASSERT(stats != NULL);
804 for (i = 0; i < num_online_cpus(); i++) {
805 c = &(stats->ls_percpu[i]->lp_cntr[index]);
809 c->lc_min = ~(__u64)0;
815 EXPORT_SYMBOL(lprocfs_counter_init);
817 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
819 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
820 LASSERT(coffset < stats->ls_num); \
821 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
824 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
826 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
827 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
828 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
829 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
830 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
831 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
832 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
833 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
834 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
835 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
836 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
837 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
838 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
839 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
840 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
841 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
842 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
843 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
844 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
845 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
846 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
847 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
848 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
849 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
850 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
851 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
852 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
853 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
854 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
855 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
856 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
857 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
858 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
859 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
860 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
861 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
862 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
863 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
864 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
865 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
866 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
867 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
868 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
869 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
870 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
871 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
872 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
873 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
874 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
875 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
876 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
877 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
878 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
879 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
880 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
881 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
882 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
883 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
884 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
885 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
886 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
887 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
888 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
891 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
893 struct lprocfs_stats *stats;
894 unsigned int num_stats;
897 LASSERT(obd->obd_stats == NULL);
898 LASSERT(obd->obd_proc_entry != NULL);
899 LASSERT(obd->obd_cntr_base == 0);
901 num_stats = ((int)sizeof(*obd->obd_type->typ_ops) / sizeof(void *)) +
902 num_private_stats - 1 /* o_owner */;
903 stats = lprocfs_alloc_stats(num_stats);
907 lprocfs_init_ops_stats(num_private_stats, stats);
909 for (i = num_private_stats; i < num_stats; i++) {
910 /* If this LBUGs, it is likely that an obd
911 * operation was added to struct obd_ops in
912 * <obd.h>, and that the corresponding line item
913 * LPROCFS_OBD_OP_INIT(.., .., opname)
914 * is missing from the list above. */
915 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
916 "Missing obd_stat initializer obd_op "
917 "operation at offset %d.\n", i - num_private_stats);
919 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
921 lprocfs_free_stats(&stats);
923 obd->obd_stats = stats;
924 obd->obd_cntr_base = num_private_stats;
929 void lprocfs_free_obd_stats(struct obd_device *obd)
932 lprocfs_free_stats(&obd->obd_stats);
935 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
936 int *eof, void *data)
938 struct obd_export *exp = (struct obd_export*)data;
939 LASSERT(exp != NULL);
941 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
944 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
945 int *eof, void *data)
947 struct obd_export *exp = (struct obd_export*)data;
948 LASSERT(exp != NULL);
950 return snprintf(page, count, "%s\n",
951 obd_uuid2str(&exp->exp_client_uuid));
954 int lprocfs_exp_setup(struct obd_export *exp)
956 char name[sizeof (exp->exp_client_uuid.uuid) + 3];
960 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
963 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
964 sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
965 while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
966 /* We might add a new export before deleting the old one during
967 an eviction (recovery-small 19a). Suckage. We
968 could block, or come up with a new name, or just give up. */
970 GOTO(out, rc = -EEXIST);
971 sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
974 /* Create a proc entry for this export */
975 exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
976 if (!exp->exp_proc) {
977 CERROR("Error making export directory for %s\n", name);
978 GOTO(out, rc = -ENOMEM);
981 /* Always add nid and uuid */
982 rc = lprocfs_add_simple(exp->exp_proc, "nid",
983 lprocfs_exp_rd_nid, NULL, exp);
986 rc = lprocfs_add_simple(exp->exp_proc, "uuid",
987 lprocfs_exp_rd_uuid, NULL, exp);
991 /* Always add ldlm stats */
992 exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC
994 if (exp->exp_ldlm_stats == NULL) {
995 lprocfs_remove(&exp->exp_proc);
996 GOTO(out, rc = -ENOMEM);
999 lprocfs_counter_init(exp->exp_ldlm_stats,
1000 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1001 0, "ldlm_enqueue", "reqs");
1002 lprocfs_counter_init(exp->exp_ldlm_stats,
1003 LDLM_CONVERT - LDLM_FIRST_OPC,
1004 0, "ldlm_convert", "reqs");
1005 lprocfs_counter_init(exp->exp_ldlm_stats,
1006 LDLM_CANCEL - LDLM_FIRST_OPC,
1007 0, "ldlm_cancel", "reqs");
1008 lprocfs_counter_init(exp->exp_ldlm_stats,
1009 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1010 0, "ldlm_bl_callback", "reqs");
1011 lprocfs_counter_init(exp->exp_ldlm_stats,
1012 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1013 0, "ldlm_cp_callback", "reqs");
1014 lprocfs_counter_init(exp->exp_ldlm_stats,
1015 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1016 0, "ldlm_gl_callback", "reqs");
1017 lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
1018 exp->exp_ldlm_stats);
1020 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1024 int lprocfs_exp_cleanup(struct obd_export *exp)
1026 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1027 lprocfs_remove(&exp->exp_proc);
1028 lprocfs_free_stats(&exp->exp_ops_stats);
1029 lprocfs_free_stats(&exp->exp_ldlm_stats);
1030 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1034 int lprocfs_write_helper(const char *buffer, unsigned long count,
1037 return lprocfs_write_frac_helper(buffer, count, val, 1);
1040 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1043 char kernbuf[20], *end, *pbuf;
1045 if (count > (sizeof(kernbuf) - 1))
1048 if (copy_from_user(kernbuf, buffer, count))
1051 kernbuf[count] = '\0';
1058 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1062 if (end != NULL && *end == '.') {
1063 int temp_val, pow = 1;
1067 if (strlen(pbuf) > 5)
1068 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1070 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1073 for (i = 0; i < (end - pbuf); i++)
1076 *val += temp_val / pow;
1082 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1084 long decimal_val, frac_val;
1090 decimal_val = val / mult;
1091 prtn = snprintf(buffer, count, "%ld", decimal_val);
1092 frac_val = val % mult;
1094 if (prtn < (count - 4) && frac_val > 0) {
1096 int i, temp_mult = 1, frac_bits = 0;
1098 temp_frac = frac_val * 10;
1099 buffer[prtn++] = '.';
1100 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1101 buffer[prtn++] ='0';
1106 Need to think these cases :
1107 1. #echo x.00 > /proc/xxx output result : x
1108 2. #echo x.0x > /proc/xxx output result : x.0x
1109 3. #echo x.x0 > /proc/xxx output result : x.x
1110 4. #echo x.xx > /proc/xxx output result : x.xx
1111 Only reserved 2bits fraction.
1113 for (i = 0; i < (5 - prtn); i++)
1116 frac_bits = min((int)count - prtn, 3 - frac_bits);
1117 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1120 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1122 if (buffer[prtn] == '.') {
1129 buffer[prtn++] ='\n';
1133 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1135 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1138 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1139 __u64 *val, int mult)
1141 char kernbuf[22], *end, *pbuf;
1142 __u64 whole, frac = 0, units;
1143 unsigned frac_d = 1;
1145 if (count > (sizeof(kernbuf) - 1) )
1148 if (copy_from_user(kernbuf, buffer, count))
1151 kernbuf[count] = '\0';
1158 whole = simple_strtoull(pbuf, &end, 10);
1162 if (end != NULL && *end == '.') {
1166 /* need to limit frac_d to a __u32 */
1167 if (strlen(pbuf) > 10)
1170 frac = simple_strtoull(pbuf, &end, 10);
1171 /* count decimal places */
1172 for (i = 0; i < (end - pbuf); i++)
1189 /* Specified units override the multiplier */
1191 mult = mult < 0 ? -units : units;
1194 do_div(frac, frac_d);
1195 *val = whole * mult + frac;
1199 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1200 char *name, mode_t mode,
1201 struct file_operations *seq_fops, void *data)
1203 struct proc_dir_entry *entry;
1206 entry = create_proc_entry(name, mode, parent);
1209 entry->proc_fops = seq_fops;
1214 EXPORT_SYMBOL(lprocfs_seq_create);
1216 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1218 struct file_operations *seq_fops,
1221 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1222 mode, seq_fops, data));
1224 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1226 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1228 if (value >= OBD_HIST_MAX)
1229 value = OBD_HIST_MAX - 1;
1231 spin_lock(&oh->oh_lock);
1232 oh->oh_buckets[value]++;
1233 spin_unlock(&oh->oh_lock);
1235 EXPORT_SYMBOL(lprocfs_oh_tally);
1237 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1241 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1244 lprocfs_oh_tally(oh, val);
1246 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1248 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1250 unsigned long ret = 0;
1253 for (i = 0; i < OBD_HIST_MAX; i++)
1254 ret += oh->oh_buckets[i];
1257 EXPORT_SYMBOL(lprocfs_oh_sum);
1259 void lprocfs_oh_clear(struct obd_histogram *oh)
1261 spin_lock(&oh->oh_lock);
1262 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1263 spin_unlock(&oh->oh_lock);
1265 EXPORT_SYMBOL(lprocfs_oh_clear);
1267 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1268 int count, int *eof, void *data)
1270 struct obd_device *obd = data;
1273 LASSERT(obd != NULL);
1274 LASSERT(count >= 0);
1276 /* Set start of user data returned to
1277 page + off since the user may have
1278 requested to read much smaller than
1279 what we need to read */
1280 *start = page + off;
1282 /* We know we are allocated a page here.
1283 Also we know that this function will
1284 not need to write more than a page
1285 so we can truncate at CFS_PAGE_SIZE. */
1286 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1288 /* Initialize the page */
1289 memset(page, 0, size);
1291 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1294 if (obd->obd_max_recoverable_clients == 0) {
1295 lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n");
1299 /* sampled unlocked, but really... */
1300 if (obd->obd_recovering == 0) {
1301 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1304 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1305 obd->obd_recovery_start) <= 0)
1308 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1309 obd->obd_recovery_end) <= 0)
1312 /* Number of clients have have completed recovery */
1313 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1314 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1317 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1318 obd->obd_recoverable_clients) <= 0)
1321 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1322 obd->obd_next_recovery_transno - 1) <= 0)
1325 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1329 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1332 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1333 obd->obd_recovery_start) <= 0)
1336 if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1337 CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
1338 obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
1341 if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1342 obd->obd_connected_clients,
1343 obd->obd_max_recoverable_clients) <= 0)
1346 /* Number of clients have have completed recovery */
1347 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1348 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1349 obd->obd_max_recoverable_clients) <= 0)
1352 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1353 obd->obd_replayed_requests) <= 0)
1356 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1357 obd->obd_requests_queued_for_recovery) <= 0)
1360 lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", obd->obd_next_recovery_transno);
1365 return min(count, len - (int)off);
1367 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1369 EXPORT_SYMBOL(lprocfs_register);
1370 EXPORT_SYMBOL(lprocfs_srch);
1371 EXPORT_SYMBOL(lprocfs_remove);
1372 EXPORT_SYMBOL(lprocfs_add_vars);
1373 EXPORT_SYMBOL(lprocfs_obd_setup);
1374 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1375 EXPORT_SYMBOL(lprocfs_alloc_stats);
1376 EXPORT_SYMBOL(lprocfs_free_stats);
1377 EXPORT_SYMBOL(lprocfs_clear_stats);
1378 EXPORT_SYMBOL(lprocfs_register_stats);
1379 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1380 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1381 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1382 EXPORT_SYMBOL(lprocfs_exp_setup);
1383 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1385 EXPORT_SYMBOL(lprocfs_rd_u64);
1386 EXPORT_SYMBOL(lprocfs_rd_atomic);
1387 EXPORT_SYMBOL(lprocfs_rd_uuid);
1388 EXPORT_SYMBOL(lprocfs_rd_name);
1389 EXPORT_SYMBOL(lprocfs_rd_fstype);
1390 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1391 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1392 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1393 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1395 EXPORT_SYMBOL(lprocfs_rd_blksize);
1396 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1397 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1398 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1399 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1400 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1402 EXPORT_SYMBOL(lprocfs_write_helper);
1403 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1404 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1405 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1406 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);