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 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
120 size_t size, loff_t *ppos)
122 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
123 char *page, *start = NULL;
124 int rc = 0, eof = 1, count;
126 if (*ppos >= CFS_PAGE_SIZE)
129 page = (char *)__get_free_page(GFP_KERNEL);
134 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
135 if (!dp->deleted && dp->read_proc)
136 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
142 /* for lustre proc read, the read count must be less than PAGE_SIZE */
151 start = page + *ppos;
152 } else if (start < page) {
156 count = (rc < size) ? rc : size;
157 if (copy_to_user(buf, start, count)) {
164 free_page((unsigned long)page);
168 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
170 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
174 if (!dp->deleted && dp->write_proc)
175 rc = dp->write_proc(f, buf, size, dp->data);
180 static struct file_operations lprocfs_generic_fops = {
181 .owner = THIS_MODULE,
182 .read = lprocfs_fops_read,
183 .write = lprocfs_fops_write,
186 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
188 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
189 struct obd_device *obd = dp->data;
191 atomic_inc(&obd->obd_evict_inprogress);
196 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
198 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
199 struct obd_device *obd = dp->data;
201 atomic_dec(&obd->obd_evict_inprogress);
202 wake_up(&obd->obd_evict_inprogress_waitq);
207 struct file_operations lprocfs_evict_client_fops = {
208 .owner = THIS_MODULE,
209 .read = lprocfs_fops_read,
210 .write = lprocfs_fops_write,
211 .open = lprocfs_evict_client_open,
212 .release = lprocfs_evict_client_release,
214 EXPORT_SYMBOL(lprocfs_evict_client_fops);
216 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
219 if (root == NULL || list == NULL)
222 while (list->name != NULL) {
223 struct proc_dir_entry *cur_root, *proc;
224 char *pathcopy, *cur, *next, pathbuf[64];
225 int pathsize = strlen(list->name) + 1;
230 /* need copy of path for strsep */
231 if (strlen(list->name) > sizeof(pathbuf) - 1) {
232 OBD_ALLOC(pathcopy, pathsize);
233 if (pathcopy == NULL)
240 strcpy(pathcopy, list->name);
242 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
243 if (*cur =='\0') /* skip double/trailing "/" */
246 proc = lprocfs_srch(cur_root, cur);
247 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
248 cur_root->name, cur, next,
249 (proc ? "exists" : "new"));
251 cur_root = (proc ? proc :
252 proc_mkdir(cur, cur_root));
253 } else if (proc == NULL) {
257 if (list->write_fptr)
259 proc = create_proc_entry(cur, mode, cur_root);
263 if (pathcopy != pathbuf)
264 OBD_FREE(pathcopy, pathsize);
266 if (cur_root == NULL || proc == NULL) {
267 CERROR("LprocFS: No memory to create /proc entry %s",
273 proc->proc_fops = list->fops;
275 proc->proc_fops = &lprocfs_generic_fops;
276 proc->read_proc = list->read_fptr;
277 proc->write_proc = list->write_fptr;
278 proc->data = (list->data ? list->data : data);
284 void lprocfs_remove(struct proc_dir_entry **rooth)
286 struct proc_dir_entry *root = *rooth;
287 struct proc_dir_entry *temp = root;
288 struct proc_dir_entry *rm_entry;
289 struct proc_dir_entry *parent;
295 parent = root->parent;
296 LASSERT(parent != NULL);
299 while (temp->subdir != NULL)
305 /* Memory corruption once caused this to fail, and
306 without this LASSERT we would loop here forever. */
307 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
308 "0x%p %s/%s len %d\n", rm_entry, temp->name,
309 rm_entry->name, (int)strlen(rm_entry->name));
311 /* Now, the rm_entry->deleted flags is protected
312 * by _lprocfs_lock. */
313 down_write(&_lprocfs_lock);
314 rm_entry->data = NULL;
315 remove_proc_entry(rm_entry->name, temp);
316 up_write(&_lprocfs_lock);
322 struct proc_dir_entry *lprocfs_register(const char *name,
323 struct proc_dir_entry *parent,
324 struct lprocfs_vars *list, void *data)
326 struct proc_dir_entry *newchild;
328 newchild = lprocfs_srch(parent, name);
329 if (newchild != NULL) {
330 CERROR(" Lproc: Attempting to register %s more than once \n",
332 return ERR_PTR(-EALREADY);
335 newchild = proc_mkdir(name, parent);
336 if (newchild != NULL && list != NULL) {
337 int rc = lprocfs_add_vars(newchild, list, data);
339 lprocfs_remove(&newchild);
346 /* Generic callbacks */
347 int lprocfs_rd_uint(char *page, char **start, off_t off,
348 int count, int *eof, void *data)
350 unsigned int *temp = (unsigned int *)data;
351 return snprintf(page, count, "%u\n", *temp);
354 int lprocfs_wr_uint(struct file *file, const char *buffer,
355 unsigned long count, void *data)
358 char dummy[MAX_STRING_SIZE + 1], *end;
361 dummy[MAX_STRING_SIZE] = '\0';
362 if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
365 tmp = simple_strtoul(dummy, &end, 0);
369 *p = (unsigned int)tmp;
373 int lprocfs_rd_u64(char *page, char **start, off_t off,
374 int count, int *eof, void *data)
376 LASSERT(data != NULL);
378 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
381 int lprocfs_rd_atomic(char *page, char **start, off_t off,
382 int count, int *eof, void *data)
384 atomic_t *atom = (atomic_t *)data;
385 LASSERT(atom != NULL);
387 return snprintf(page, count, "%d\n", atomic_read(atom));
390 int lprocfs_wr_atomic(struct file *file, const char *buffer,
391 unsigned long count, void *data)
393 atomic_t *atm = data;
397 rc = lprocfs_write_helper(buffer, count, &val);
404 atomic_set(atm, val);
408 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
409 int *eof, void *data)
411 struct obd_device *obd = (struct obd_device*)data;
413 LASSERT(obd != NULL);
415 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
418 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
419 int *eof, void* data)
421 struct obd_device *dev = (struct obd_device *)data;
423 LASSERT(dev != NULL);
424 LASSERT(dev->obd_name != NULL);
426 return snprintf(page, count, "%s\n", dev->obd_name);
429 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
432 struct obd_device *obd = (struct obd_device *)data;
434 LASSERT(obd != NULL);
435 LASSERT(obd->obd_fsops != NULL);
436 LASSERT(obd->obd_fsops->fs_type != NULL);
437 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
440 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
441 int *eof, void *data)
443 struct obd_statfs osfs;
444 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
448 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
453 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
454 int *eof, void *data)
456 struct obd_statfs osfs;
457 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
460 __u32 blk_size = osfs.os_bsize >> 10;
461 __u64 result = osfs.os_blocks;
463 while (blk_size >>= 1)
467 rc = snprintf(page, count, LPU64"\n", result);
472 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
473 int *eof, void *data)
475 struct obd_statfs osfs;
476 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
479 __u32 blk_size = osfs.os_bsize >> 10;
480 __u64 result = osfs.os_bfree;
482 while (blk_size >>= 1)
486 rc = snprintf(page, count, LPU64"\n", result);
491 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
492 int *eof, void *data)
494 struct obd_statfs osfs;
495 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
498 __u32 blk_size = osfs.os_bsize >> 10;
499 __u64 result = osfs.os_bavail;
501 while (blk_size >>= 1)
505 rc = snprintf(page, count, LPU64"\n", result);
510 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
511 int *eof, void *data)
513 struct obd_statfs osfs;
514 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
518 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
524 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
525 int *eof, void *data)
527 struct obd_statfs osfs;
528 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
532 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
537 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
538 int *eof, void *data)
540 struct obd_device *obd = (struct obd_device *)data;
541 struct obd_import *imp;
542 char *imp_state_name = NULL;
545 LASSERT(obd != NULL);
546 LPROCFS_CLIMP_CHECK(obd);
547 imp = obd->u.cli.cl_import;
548 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
550 rc = snprintf(page, count, "%s\t%s%s\n",
551 obd2cli_tgt(obd), imp_state_name,
552 imp->imp_deactive ? "\tDEACTIVATED" : "");
554 LPROCFS_CLIMP_EXIT(obd);
558 int lprocfs_rd_conn_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 ptlrpc_connection *conn;
565 LASSERT(obd != NULL);
567 LPROCFS_CLIMP_CHECK(obd);
568 conn = obd->u.cli.cl_import->imp_connection;
569 LASSERT(conn != NULL);
571 if (obd->u.cli.cl_import) {
572 rc = snprintf(page, count, "%s\n",
573 conn->c_remote_uuid.uuid);
575 rc = snprintf(page, count, "%s\n", "<none>");
578 LPROCFS_CLIMP_EXIT(obd);
582 static const char *obd_connect_names[] = {
609 "mds_mds_connection",
612 "alt_checksum_algorithm",
617 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
618 int count, int *eof, void *data)
620 struct obd_device *obd = data;
621 __u64 mask = 1, flags;
624 LPROCFS_CLIMP_CHECK(obd);
625 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
626 ret = snprintf(page, count, "flags="LPX64"\n", flags);
627 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
629 ret += snprintf(page + ret, count - ret, "%s\n",
630 obd_connect_names[i]);
632 if (flags & ~(mask - 1))
633 ret += snprintf(page + ret, count - ret,
634 "unknown flags "LPX64"\n", flags & ~(mask - 1));
636 LPROCFS_CLIMP_EXIT(obd);
639 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
641 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
642 int *eof, void *data)
644 struct obd_device *obd = (struct obd_device*)data;
646 LASSERT(obd != NULL);
648 return snprintf(page, count, "%u\n", obd->obd_num_exports);
651 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
652 int *eof, void *data)
654 struct obd_type *class = (struct obd_type*) data;
656 LASSERT(class != NULL);
658 return snprintf(page, count, "%d\n", class->typ_refcnt);
661 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
665 LASSERT(obd != NULL);
666 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
667 LASSERT(obd->obd_type->typ_procroot != NULL);
669 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
670 obd->obd_type->typ_procroot,
672 if (IS_ERR(obd->obd_proc_entry)) {
673 rc = PTR_ERR(obd->obd_proc_entry);
674 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
675 obd->obd_proc_entry = NULL;
680 int lprocfs_obd_cleanup(struct obd_device *obd)
684 if (obd->obd_proc_exports_entry) {
685 /* Should be no exports left */
686 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
687 lprocfs_remove(&obd->obd_proc_exports_entry);
689 lprocfs_remove(&obd->obd_proc_entry);
693 void lprocfs_free_client_stats(void *obj, void *data)
695 struct nid_stat *client_stat = obj;
697 CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
698 client_stat->nid_proc, client_stat->nid_stats,
699 client_stat->nid_brw_stats);
701 LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
702 client_stat->nid_exp_ref_count);
704 hlist_del_init(&client_stat->nid_hash);
705 list_del(&client_stat->nid_list);
707 if (client_stat->nid_proc)
708 lprocfs_remove(&client_stat->nid_proc);
710 if (client_stat->nid_stats)
711 lprocfs_free_stats(&client_stat->nid_stats);
713 if (client_stat->nid_brw_stats)
714 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
716 OBD_FREE(client_stat, sizeof(*client_stat));
721 void lprocfs_free_per_client_stats(struct obd_device *obd)
723 struct nid_stat *stat;
726 /* we need extra list - because hash_exit called to early */
727 while(!list_empty(&obd->obd_nid_stats)) {
728 stat = list_entry(obd->obd_nid_stats.next,
729 struct nid_stat, nid_list);
730 lprocfs_free_client_stats(stat, NULL);
736 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
737 enum lprocfs_stats_flags flags)
739 struct lprocfs_stats *stats;
740 struct lprocfs_percpu *percpu;
741 unsigned int percpusize;
743 unsigned int num_cpu;
748 if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
751 num_cpu = num_possible_cpus();
753 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
757 if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
758 stats->ls_flags = flags;
759 spin_lock_init(&stats->ls_lock);
760 /* Use this lock only if there are no percpu areas */
765 percpusize = offsetof(typeof(*percpu), lp_cntr[num]);
767 percpusize = L1_CACHE_ALIGN(percpusize);
769 stats->ls_percpu_size = num_cpu * percpusize;
770 OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
771 if (stats->ls_percpu[0] == NULL) {
772 OBD_FREE(stats, offsetof(typeof(*stats),
773 ls_percpu[num_cpu]));
778 for (i = 1; i < num_cpu; i++)
779 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
785 void lprocfs_free_stats(struct lprocfs_stats **statsh)
787 struct lprocfs_stats *stats = *statsh;
788 unsigned int num_cpu;
790 if (stats == NULL || stats->ls_num == 0)
794 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
797 num_cpu = num_possible_cpus();
799 OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
800 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
803 void lprocfs_clear_stats(struct lprocfs_stats *stats)
805 struct lprocfs_counter *percpu_cntr;
807 unsigned int num_cpu;
809 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
811 for (i = 0; i < num_cpu; i++) {
812 for (j = 0; j < stats->ls_num; j++) {
813 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
814 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
815 percpu_cntr->lc_count = 0;
816 percpu_cntr->lc_sum = 0;
817 percpu_cntr->lc_min = ~(__u64)0;
818 percpu_cntr->lc_max = 0;
819 percpu_cntr->lc_sumsquare = 0;
820 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
824 lprocfs_stats_unlock(stats);
827 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
828 size_t len, loff_t *off)
830 struct seq_file *seq = file->private_data;
831 struct lprocfs_stats *stats = seq->private;
833 lprocfs_clear_stats(stats);
838 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
840 struct lprocfs_stats *stats = p->private;
841 /* return 1st cpu location */
842 return (*pos >= stats->ls_num) ? NULL :
843 &(stats->ls_percpu[0]->lp_cntr[*pos]);
846 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
850 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
852 struct lprocfs_stats *stats = p->private;
854 return (*pos >= stats->ls_num) ? NULL :
855 &(stats->ls_percpu[0]->lp_cntr[*pos]);
858 /* seq file export of one lprocfs counter */
859 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
861 struct lprocfs_stats *stats = p->private;
862 struct lprocfs_counter *cntr = v;
863 struct lprocfs_counter t, ret = { .lc_min = ~(__u64)0 };
865 unsigned int num_cpu;
867 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
869 do_gettimeofday(&now);
870 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
871 "snapshot_time", now.tv_sec, now.tv_usec);
875 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
877 if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
880 num_cpu = num_possible_cpus();
882 for (i = 0; i < num_cpu; i++) {
883 struct lprocfs_counter *percpu_cntr =
884 &(stats->ls_percpu[i])->lp_cntr[idx];
888 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
889 t.lc_count = percpu_cntr->lc_count;
890 t.lc_sum = percpu_cntr->lc_sum;
891 t.lc_min = percpu_cntr->lc_min;
892 t.lc_max = percpu_cntr->lc_max;
893 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
894 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
895 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
896 ret.lc_count += t.lc_count;
897 ret.lc_sum += t.lc_sum;
898 if (t.lc_min < ret.lc_min)
899 ret.lc_min = t.lc_min;
900 if (t.lc_max > ret.lc_max)
901 ret.lc_max = t.lc_max;
902 ret.lc_sumsquare += t.lc_sumsquare;
905 rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
906 ret.lc_count, cntr->lc_units);
910 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
911 rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
912 ret.lc_min, ret.lc_max, ret.lc_sum);
915 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
916 rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
920 rc = seq_printf(p, "\n");
922 return (rc < 0) ? rc : 0;
925 struct seq_operations lprocfs_stats_seq_sops = {
926 start: lprocfs_stats_seq_start,
927 stop: lprocfs_stats_seq_stop,
928 next: lprocfs_stats_seq_next,
929 show: lprocfs_stats_seq_show,
932 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
934 struct proc_dir_entry *dp = PDE(inode);
935 struct seq_file *seq;
938 LPROCFS_ENTRY_AND_CHECK(dp);
939 rc = seq_open(file, &lprocfs_stats_seq_sops);
944 seq = file->private_data;
945 seq->private = dp->data;
949 struct file_operations lprocfs_stats_seq_fops = {
950 .owner = THIS_MODULE,
951 .open = lprocfs_stats_seq_open,
953 .write = lprocfs_stats_seq_write,
955 .release = lprocfs_seq_release,
958 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
959 struct lprocfs_stats *stats)
961 struct proc_dir_entry *entry;
962 LASSERT(root != NULL);
964 entry = create_proc_entry(name, 0644, root);
967 entry->proc_fops = &lprocfs_stats_seq_fops;
968 entry->data = (void *)stats;
972 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
973 unsigned conf, const char *name, const char *units)
975 struct lprocfs_counter *c;
977 unsigned int num_cpu;
979 LASSERT(stats != NULL);
981 num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
983 for (i = 0; i < num_cpu; i++) {
984 c = &(stats->ls_percpu[i]->lp_cntr[index]);
988 c->lc_min = ~(__u64)0;
994 lprocfs_stats_unlock(stats);
996 EXPORT_SYMBOL(lprocfs_counter_init);
998 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
1000 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
1001 LASSERT(coffset < stats->ls_num); \
1002 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1005 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1007 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1008 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1009 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1010 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1011 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1012 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1013 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1014 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1015 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1016 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1017 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1018 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1019 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1020 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1021 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1022 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1023 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1024 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1025 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1026 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1027 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1028 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1029 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1030 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1031 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1032 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1033 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1034 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1035 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1036 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1037 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1038 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1039 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1040 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1041 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1042 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1043 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1044 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1045 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1046 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1047 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1048 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1049 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1050 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1051 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1052 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1053 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1054 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1055 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1056 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1057 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1058 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1059 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1060 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1061 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1062 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1063 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1064 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1065 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1066 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1067 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1068 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1069 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1070 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1071 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1072 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1073 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1074 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1075 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1078 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1080 struct lprocfs_stats *stats;
1081 unsigned int num_stats;
1084 LASSERT(obd->obd_stats == NULL);
1085 LASSERT(obd->obd_proc_entry != NULL);
1086 LASSERT(obd->obd_cntr_base == 0);
1088 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1089 num_private_stats - 1 /* o_owner */;
1090 stats = lprocfs_alloc_stats(num_stats, 0);
1094 lprocfs_init_ops_stats(num_private_stats, stats);
1096 for (i = num_private_stats; i < num_stats; i++) {
1097 /* If this LBUGs, it is likely that an obd
1098 * operation was added to struct obd_ops in
1099 * <obd.h>, and that the corresponding line item
1100 * LPROCFS_OBD_OP_INIT(.., .., opname)
1101 * is missing from the list above. */
1102 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1103 "Missing obd_stat initializer obd_op "
1104 "operation at offset %d.\n", i - num_private_stats);
1106 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1108 lprocfs_free_stats(&stats);
1110 obd->obd_stats = stats;
1111 obd->obd_cntr_base = num_private_stats;
1116 void lprocfs_free_obd_stats(struct obd_device *obd)
1119 lprocfs_free_stats(&obd->obd_stats);
1122 #define LPROCFS_MD_OP_INIT(base, stats, op) \
1124 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
1125 LASSERT(coffset < stats->ls_num); \
1126 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
1129 int lprocfs_alloc_md_stats(struct obd_device *obd,
1130 unsigned num_private_stats)
1132 struct lprocfs_stats *stats;
1133 unsigned int num_stats;
1136 LASSERT(obd->md_stats == NULL);
1137 LASSERT(obd->obd_proc_entry != NULL);
1138 LASSERT(obd->md_cntr_base == 0);
1140 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1142 stats = lprocfs_alloc_stats(num_stats, 0);
1146 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1147 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1148 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1149 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1150 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1151 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1152 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1153 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1154 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1155 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1156 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1157 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1158 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1159 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1160 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1161 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1162 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1163 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1164 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1165 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1166 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1167 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1168 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1169 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1170 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1171 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1172 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1173 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1175 for (i = num_private_stats; i < num_stats; i++) {
1176 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1177 CERROR("Missing md_stat initializer md_op "
1178 "operation at offset %d. Aborting.\n",
1179 i - num_private_stats);
1183 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1185 lprocfs_free_stats(&stats);
1187 obd->md_stats = stats;
1188 obd->md_cntr_base = num_private_stats;
1193 void lprocfs_free_md_stats(struct obd_device *obd)
1195 struct lprocfs_stats *stats = obd->md_stats;
1197 if (stats != NULL) {
1198 obd->md_stats = NULL;
1199 lprocfs_free_stats(&stats);
1203 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1204 int *eof, void *data)
1206 struct obd_export *exp = (struct obd_export*)data;
1207 LASSERT(exp != NULL);
1209 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1212 struct exp_uuid_cb_data {
1219 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1221 struct obd_export *exp = (struct obd_export *)obj;
1222 struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1224 if (exp->exp_nid_stats)
1225 *data->len += snprintf((data->page + *data->len),
1226 data->count, "%s\n",
1227 obd_uuid2str(&exp->exp_client_uuid));
1230 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1231 int *eof, void *data)
1233 struct nid_stat *stats = (struct nid_stat *)data;
1234 struct exp_uuid_cb_data cb_data;
1235 struct obd_device *obd = stats->nid_obd;
1240 LASSERT(obd != NULL);
1242 cb_data.page = page;
1243 cb_data.count = count;
1246 lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1247 &stats->nid, lprocfs_exp_print_uuid,
1249 return (*cb_data.len);
1252 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1253 int count, int *eof, void *data)
1256 return snprintf(page, count, "%s\n",
1257 "Write into this file to clear all nid stats and "
1258 "stale nid entries");
1260 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1262 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1264 struct nid_stat *client_stat = obj;
1266 if(client_stat->nid_exp_ref_count == 1) {
1267 hlist_del_init(&client_stat->nid_hash);
1268 lprocfs_free_client_stats(client_stat, data);
1269 OBD_FREE(client_stat, sizeof(struct nid_stat));
1274 /* we has reference to object - only clear data*/
1275 if (client_stat->nid_stats) {
1276 lprocfs_clear_stats(client_stat->nid_stats);
1278 if (client_stat->nid_brw_stats) {
1279 for (i = 0; i < BRW_LAST; i++)
1280 lprocfs_oh_clear(&client_stat->nid_brw_stats->hist[i]);
1286 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1287 unsigned long count, void *data)
1289 struct obd_device *obd = (struct obd_device *)data;
1290 lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
1291 lprocfs_free_client_stats, NULL);
1294 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1296 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1299 struct nid_stat *tmp = NULL, *tmp1;
1300 struct obd_device *obd = NULL;
1305 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1306 !exp->exp_obd->obd_nid_stats_hash_body)
1309 /* not test against zero because eric say:
1310 * You may only test nid against another nid, or LNET_NID_ANY. Anything else is
1312 if (!nid || *nid == LNET_NID_ANY)
1317 CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
1319 OBD_ALLOC(tmp, sizeof(struct nid_stat));
1324 tmp->nid_obd = exp->exp_obd;
1325 tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1327 tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
1329 CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1330 tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1333 exp->exp_nid_stats = tmp1;
1334 GOTO(destroy_new, rc = 0);
1336 /* not found - create */
1337 tmp->nid_proc = proc_mkdir(libcfs_nid2str(*nid),
1338 obd->obd_proc_exports_entry);
1339 if (!tmp->nid_proc) {
1340 CERROR("Error making export directory for"
1341 " nid %s\n", libcfs_nid2str(*nid));
1342 lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
1344 GOTO(destroy_new, rc = -ENOMEM);
1347 rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1348 lprocfs_exp_rd_uuid, NULL, tmp);
1350 CWARN("Error adding the uuid file\n");
1352 spin_lock(&obd->obd_nid_lock);
1353 list_add(&tmp->nid_list, &obd->obd_nid_stats);
1354 spin_unlock(&obd->obd_nid_lock);
1356 exp->exp_nid_stats = tmp;
1361 OBD_FREE(tmp, sizeof(struct nid_stat));
1365 int lprocfs_exp_cleanup(struct obd_export *exp)
1367 struct nid_stat *stat = exp->exp_nid_stats;
1372 stat->nid_exp_ref_count--;
1373 CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1375 exp->exp_nid_stats = NULL;
1379 int lprocfs_write_helper(const char *buffer, unsigned long count,
1382 return lprocfs_write_frac_helper(buffer, count, val, 1);
1385 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1388 char kernbuf[20], *end, *pbuf;
1390 if (count > (sizeof(kernbuf) - 1))
1393 if (copy_from_user(kernbuf, buffer, count))
1396 kernbuf[count] = '\0';
1403 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1407 if (end != NULL && *end == '.') {
1408 int temp_val, pow = 1;
1412 if (strlen(pbuf) > 5)
1413 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1415 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1418 for (i = 0; i < (end - pbuf); i++)
1421 *val += temp_val / pow;
1427 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1429 long decimal_val, frac_val;
1435 decimal_val = val / mult;
1436 prtn = snprintf(buffer, count, "%ld", decimal_val);
1437 frac_val = val % mult;
1439 if (prtn < (count - 4) && frac_val > 0) {
1441 int i, temp_mult = 1, frac_bits = 0;
1443 temp_frac = frac_val * 10;
1444 buffer[prtn++] = '.';
1445 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1446 buffer[prtn++] ='0';
1451 Need to think these cases :
1452 1. #echo x.00 > /proc/xxx output result : x
1453 2. #echo x.0x > /proc/xxx output result : x.0x
1454 3. #echo x.x0 > /proc/xxx output result : x.x
1455 4. #echo x.xx > /proc/xxx output result : x.xx
1456 Only reserved 2bits fraction.
1458 for (i = 0; i < (5 - prtn); i++)
1461 frac_bits = min((int)count - prtn, 3 - frac_bits);
1462 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1465 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1467 if (buffer[prtn] == '.') {
1474 buffer[prtn++] ='\n';
1478 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1480 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1483 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1484 __u64 *val, int mult)
1486 char kernbuf[22], *end, *pbuf;
1487 __u64 whole, frac = 0, units;
1488 unsigned frac_d = 1;
1490 if (count > (sizeof(kernbuf) - 1) )
1493 if (copy_from_user(kernbuf, buffer, count))
1496 kernbuf[count] = '\0';
1503 whole = simple_strtoull(pbuf, &end, 10);
1507 if (end != NULL && *end == '.') {
1511 /* need to limit frac_d to a __u32 */
1512 if (strlen(pbuf) > 10)
1515 frac = simple_strtoull(pbuf, &end, 10);
1516 /* count decimal places */
1517 for (i = 0; i < (end - pbuf); i++)
1534 /* Specified units override the multiplier */
1536 mult = mult < 0 ? -units : units;
1539 do_div(frac, frac_d);
1540 *val = whole * mult + frac;
1544 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1545 char *name, mode_t mode,
1546 struct file_operations *seq_fops, void *data)
1548 struct proc_dir_entry *entry;
1551 entry = create_proc_entry(name, mode, parent);
1554 entry->proc_fops = seq_fops;
1559 EXPORT_SYMBOL(lprocfs_seq_create);
1561 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1563 struct file_operations *seq_fops,
1566 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1567 mode, seq_fops, data));
1569 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1571 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1573 if (value >= OBD_HIST_MAX)
1574 value = OBD_HIST_MAX - 1;
1576 spin_lock(&oh->oh_lock);
1577 oh->oh_buckets[value]++;
1578 spin_unlock(&oh->oh_lock);
1580 EXPORT_SYMBOL(lprocfs_oh_tally);
1582 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1586 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1589 lprocfs_oh_tally(oh, val);
1591 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1593 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1595 unsigned long ret = 0;
1598 for (i = 0; i < OBD_HIST_MAX; i++)
1599 ret += oh->oh_buckets[i];
1602 EXPORT_SYMBOL(lprocfs_oh_sum);
1604 void lprocfs_oh_clear(struct obd_histogram *oh)
1606 spin_lock(&oh->oh_lock);
1607 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1608 spin_unlock(&oh->oh_lock);
1610 EXPORT_SYMBOL(lprocfs_oh_clear);
1612 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1613 int count, int *eof, void *data)
1615 struct obd_device *obd = data;
1618 LASSERT(obd != NULL);
1619 LASSERT(count >= 0);
1621 /* Set start of user data returned to
1622 page + off since the user may have
1623 requested to read much smaller than
1624 what we need to read */
1625 *start = page + off;
1627 /* We know we are allocated a page here.
1628 Also we know that this function will
1629 not need to write more than a page
1630 so we can truncate at CFS_PAGE_SIZE. */
1631 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1633 /* Initialize the page */
1634 memset(page, 0, size);
1636 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1639 if (obd->obd_max_recoverable_clients == 0) {
1640 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1646 /* sampled unlocked, but really... */
1647 if (obd->obd_recovering == 0) {
1648 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1651 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1652 obd->obd_recovery_start) <= 0)
1655 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1656 obd->obd_recovery_end) <= 0)
1659 /* Number of clients have have completed recovery */
1660 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1661 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1664 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1665 obd->obd_recoverable_clients) <= 0)
1668 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1669 obd->obd_next_recovery_transno - 1) <= 0)
1672 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1676 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1679 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1680 obd->obd_recovery_start) <= 0)
1683 if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1684 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1685 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1688 if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1689 obd->obd_connected_clients,
1690 obd->obd_max_recoverable_clients) <= 0)
1693 /* Number of clients have have completed recovery */
1694 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1695 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1696 obd->obd_max_recoverable_clients) <= 0)
1699 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1700 obd->obd_replayed_requests) <= 0)
1703 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1704 obd->obd_requests_queued_for_recovery) <= 0)
1707 if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1708 obd->obd_next_recovery_transno) <= 0)
1714 return min(count, len - (int)off);
1716 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1718 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1719 int count, int *eof, void *data)
1721 struct obd_device *obd = (struct obd_device *)data;
1722 LASSERT(obd != NULL);
1724 return snprintf(page, count, "%lu\n",
1725 obd->obd_recovery_max_time);
1727 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1729 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1730 unsigned long count, void *data)
1732 struct obd_device *obd = (struct obd_device *)data;
1734 LASSERT(obd != NULL);
1736 rc = lprocfs_write_helper(buffer, count, &val);
1740 obd->obd_recovery_max_time = val;
1743 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1745 EXPORT_SYMBOL(lprocfs_register);
1746 EXPORT_SYMBOL(lprocfs_srch);
1747 EXPORT_SYMBOL(lprocfs_remove);
1748 EXPORT_SYMBOL(lprocfs_add_vars);
1749 EXPORT_SYMBOL(lprocfs_obd_setup);
1750 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1751 EXPORT_SYMBOL(lprocfs_add_simple);
1752 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1753 EXPORT_SYMBOL(lprocfs_alloc_stats);
1754 EXPORT_SYMBOL(lprocfs_free_stats);
1755 EXPORT_SYMBOL(lprocfs_clear_stats);
1756 EXPORT_SYMBOL(lprocfs_register_stats);
1757 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1758 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1759 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1760 EXPORT_SYMBOL(lprocfs_exp_setup);
1761 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1763 EXPORT_SYMBOL(lprocfs_rd_u64);
1764 EXPORT_SYMBOL(lprocfs_rd_atomic);
1765 EXPORT_SYMBOL(lprocfs_wr_atomic);
1766 EXPORT_SYMBOL(lprocfs_rd_uint);
1767 EXPORT_SYMBOL(lprocfs_wr_uint);
1768 EXPORT_SYMBOL(lprocfs_rd_uuid);
1769 EXPORT_SYMBOL(lprocfs_rd_name);
1770 EXPORT_SYMBOL(lprocfs_rd_fstype);
1771 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1772 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1773 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1774 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1776 EXPORT_SYMBOL(lprocfs_rd_blksize);
1777 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1778 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1779 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1780 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1781 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1783 EXPORT_SYMBOL(lprocfs_write_helper);
1784 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1785 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1786 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1787 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);