Whamcloud - gitweb
65440346ac8468ceef0a19e61994b0ecd201581c
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lprocfs_status.c
37  *
38  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
39  */
40
41 #define DEBUG_SUBSYSTEM S_CLASS
42
43 #ifndef __KERNEL__
44 # include <liblustre.h>
45 #endif
46
47 #include <obd_class.h>
48 #include <lprocfs_status.h>
49 #include <lustre/lustre_idl.h>
50
51 #if defined(LPROCFS)
52
53 static int lprocfs_no_percpu_stats = 0;
54 CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
55                 "Do not alloc percpu data for lprocfs stats");
56
57 #define MAX_STRING_SIZE 128
58
59 /* for bug 10866, global variable */
60 DECLARE_RWSEM(_lprocfs_lock);
61 EXPORT_SYMBOL(_lprocfs_lock);
62
63 int lprocfs_single_release(struct inode *inode, struct file *file)
64 {
65         return single_release(inode, file);
66 }
67 EXPORT_SYMBOL(lprocfs_single_release);
68
69 int lprocfs_seq_release(struct inode *inode, struct file *file)
70 {
71         return seq_release(inode, file);
72 }
73 EXPORT_SYMBOL(lprocfs_seq_release);
74
75 static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
76                                              const char *name)
77 {
78         struct proc_dir_entry *temp;
79
80         if (head == NULL)
81                 return NULL;
82
83         temp = head->subdir;
84         while (temp != NULL) {
85                 if (strcmp(temp->name, name) == 0) {
86                         return temp;
87                 }
88
89                 temp = temp->next;
90         }
91         return NULL;
92 }
93
94 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
95                                     const char *name)
96 {
97         struct proc_dir_entry *temp;
98
99         LPROCFS_SRCH_ENTRY();
100         temp = __lprocfs_srch(head, name);
101         LPROCFS_SRCH_EXIT();
102         return temp;
103 }
104 EXPORT_SYMBOL(lprocfs_srch);
105
106 /* lprocfs API calls */
107
108 /* Function that emulates snprintf but also has the side effect of advancing
109    the page pointer for the next write into the buffer, incrementing the total
110    length written to the buffer, and decrementing the size left in the
111    buffer. */
112 static int lprocfs_obd_snprintf(char **page, int end, int *len,
113                                 const char *format, ...)
114 {
115         va_list list;
116         int n;
117
118         if (*len >= end)
119                 return 0;
120
121         va_start(list, format);
122         n = vsnprintf(*page, end - *len, format, list);
123         va_end(list);
124
125         *page += n; *len += n;
126         return n;
127 }
128
129 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
130                                          char *name,
131                                          read_proc_t *read_proc,
132                                          write_proc_t *write_proc,
133                                          void *data,
134                                          struct file_operations *fops)
135 {
136         cfs_proc_dir_entry_t *proc;
137         mode_t mode = 0;
138
139         if (root == NULL || name == NULL)
140                 return ERR_PTR(-EINVAL);
141         if (read_proc)
142                 mode = 0444;
143         if (write_proc)
144                 mode |= 0200;
145         if (fops)
146                 mode = 0644;
147         LPROCFS_WRITE_ENTRY();
148         proc = create_proc_entry(name, mode, root);
149         if (!proc) {
150                 CERROR("LprocFS: No memory to create /proc entry %s", name);
151                 LPROCFS_WRITE_EXIT();
152                 return ERR_PTR(-ENOMEM);
153         }
154         proc->read_proc = read_proc;
155         proc->write_proc = write_proc;
156         proc->data = data;
157         if (fops)
158                 proc->proc_fops = fops;
159         LPROCFS_WRITE_EXIT();
160         return proc;
161 }
162 EXPORT_SYMBOL(lprocfs_add_simple);
163
164 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
165                         struct proc_dir_entry *parent, const char *format, ...)
166 {
167         struct proc_dir_entry *entry;
168         char *dest;
169         va_list ap;
170
171         if (parent == NULL || format == NULL)
172                 return NULL;
173
174         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
175         if (dest == NULL)
176                 return NULL;
177
178         va_start(ap, format);
179         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
180         va_end(ap);
181
182         entry = proc_symlink(name, parent, dest);
183         if (entry == NULL)
184                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
185                         name, dest);
186
187         OBD_FREE(dest, MAX_STRING_SIZE + 1);
188         return entry;
189 }
190 EXPORT_SYMBOL(lprocfs_add_symlink);
191
192 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
193                                  size_t size, loff_t *ppos)
194 {
195         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
196         char *page, *start = NULL;
197         int rc = 0, eof = 1, count;
198
199         if (*ppos >= PAGE_CACHE_SIZE)
200                 return 0;
201
202         page = (char *)__get_free_page(GFP_KERNEL);
203         if (page == NULL)
204                 return -ENOMEM;
205
206         if (LPROCFS_ENTRY_CHECK(dp)) {
207                 rc = -ENOENT;
208                 goto out;
209         }
210
211         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
212         if (dp->read_proc)
213                 rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
214                                    &eof, dp->data);
215         if (rc <= 0)
216                 goto out;
217
218         /* for lustre proc read, the read count must be less than PAGE_SIZE */
219         LASSERT(eof == 1);
220
221         if (start == NULL) {
222                 rc -= *ppos;
223                 if (rc < 0)
224                         rc = 0;
225                 if (rc == 0)
226                         goto out;
227                 start = page + *ppos;
228         } else if (start < page) {
229                 start = page;
230         }
231
232         count = (rc < size) ? rc : size;
233         if (copy_to_user(buf, start, count)) {
234                 rc = -EFAULT;
235                 goto out;
236         }
237         *ppos += count;
238
239 out:
240         free_page((unsigned long)page);
241         return rc;
242 }
243
244 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
245                                   size_t size, loff_t *ppos)
246 {
247         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
248         int rc = -EIO;
249
250         if (LPROCFS_ENTRY_CHECK(dp))
251                 return -ENOENT;
252         if (dp->write_proc)
253                 rc = dp->write_proc(f, buf, size, dp->data);
254         return rc;
255 }
256
257 static struct file_operations lprocfs_generic_fops = {
258         .owner = THIS_MODULE,
259         .read = lprocfs_fops_read,
260         .write = lprocfs_fops_write,
261 };
262
263 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
264 {
265         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
266         struct obd_device *obd = dp->data;
267
268         cfs_atomic_inc(&obd->obd_evict_inprogress);
269
270         return 0;
271 }
272
273 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
274 {
275         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
276         struct obd_device *obd = dp->data;
277
278         cfs_atomic_dec(&obd->obd_evict_inprogress);
279         cfs_waitq_signal(&obd->obd_evict_inprogress_waitq);
280
281         return 0;
282 }
283
284 struct file_operations lprocfs_evict_client_fops = {
285         .owner = THIS_MODULE,
286         .read = lprocfs_fops_read,
287         .write = lprocfs_fops_write,
288         .open = lprocfs_evict_client_open,
289         .release = lprocfs_evict_client_release,
290 };
291 EXPORT_SYMBOL(lprocfs_evict_client_fops);
292
293 static int __lprocfs_add_vars(struct proc_dir_entry *root,
294                               struct lprocfs_vars *list,
295                               void *data)
296 {
297         int rc = 0;
298
299         if (root == NULL || list == NULL)
300                 return -EINVAL;
301
302         while (list->name != NULL) {
303                 struct proc_dir_entry *cur_root, *proc;
304                 char *pathcopy, *cur, *next, pathbuf[64];
305                 int pathsize = strlen(list->name) + 1;
306
307                 proc = NULL;
308                 cur_root = root;
309
310                 /* need copy of path for strsep */
311                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
312                         OBD_ALLOC(pathcopy, pathsize);
313                         if (pathcopy == NULL)
314                                 GOTO(out, rc = -ENOMEM);
315                 } else {
316                         pathcopy = pathbuf;
317                 }
318
319                 next = pathcopy;
320                 strcpy(pathcopy, list->name);
321
322                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
323                         if (*cur =='\0') /* skip double/trailing "/" */
324                                 continue;
325
326                         proc = __lprocfs_srch(cur_root, cur);
327                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
328                                cur_root->name, cur, next,
329                                (proc ? "exists" : "new"));
330                         if (next != NULL) {
331                                 cur_root = (proc ? proc :
332                                             proc_mkdir(cur, cur_root));
333                         } else if (proc == NULL) {
334                                 mode_t mode = 0;
335                                 if (list->proc_mode != 0000) {
336                                         mode = list->proc_mode;
337                                 } else {
338                                         if (list->read_fptr)
339                                                 mode = 0444;
340                                         if (list->write_fptr)
341                                                 mode |= 0200;
342                                 }
343                                 proc = create_proc_entry(cur, mode, cur_root);
344                         }
345                 }
346
347                 if (pathcopy != pathbuf)
348                         OBD_FREE(pathcopy, pathsize);
349
350                 if (cur_root == NULL || proc == NULL) {
351                         CERROR("LprocFS: No memory to create /proc entry %s",
352                                list->name);
353                         GOTO(out, rc = -ENOMEM);
354                 }
355
356                 if (list->fops)
357                         proc->proc_fops = list->fops;
358                 else
359                         proc->proc_fops = &lprocfs_generic_fops;
360                 proc->read_proc = list->read_fptr;
361                 proc->write_proc = list->write_fptr;
362                 proc->data = (list->data ? list->data : data);
363                 list++;
364         }
365 out:
366         return rc;
367 }
368
369 /**
370  * Add /proc entries.
371  *
372  * \param root [in]  The parent proc entry on which new entry will be added.
373  * \param list [in]  Array of proc entries to be added.
374  * \param data [in]  The argument to be passed when entries read/write routines
375  *                   are called through /proc file.
376  *
377  * \retval 0   on success
378  *         < 0 on error
379  */
380 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
381                      void *data)
382 {
383         int rc;
384
385         LPROCFS_WRITE_ENTRY();
386         rc = __lprocfs_add_vars(root, list, data);
387         LPROCFS_WRITE_EXIT();
388
389         return rc;
390 }
391 EXPORT_SYMBOL(lprocfs_add_vars);
392
393 void lprocfs_remove_nolock(struct proc_dir_entry **proot)
394 {
395         struct proc_dir_entry *root = *proot;
396         struct proc_dir_entry *temp = root;
397         struct proc_dir_entry *rm_entry;
398         struct proc_dir_entry *parent;
399
400         *proot = NULL;
401         if (root == NULL || IS_ERR(root))
402                 return;
403
404         parent = root->parent;
405         LASSERT(parent != NULL);
406
407         while (1) {
408                 while (temp->subdir != NULL)
409                         temp = temp->subdir;
410
411                 rm_entry = temp;
412                 temp = temp->parent;
413
414                 /* Memory corruption once caused this to fail, and
415                    without this LASSERT we would loop here forever. */
416                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
417                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
418                          rm_entry->name, (int)strlen(rm_entry->name));
419
420                 remove_proc_entry(rm_entry->name, temp);
421                 if (temp == parent)
422                         break;
423         }
424 }
425
426 void lprocfs_remove(struct proc_dir_entry **rooth)
427 {
428         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
429         lprocfs_remove_nolock(rooth);
430         LPROCFS_WRITE_EXIT();
431 }
432 EXPORT_SYMBOL(lprocfs_remove);
433
434 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
435 {
436         LASSERT(parent != NULL);
437         remove_proc_entry(name, parent);
438 }
439 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
440
441 void lprocfs_try_remove_proc_entry(const char *name,
442                                    struct proc_dir_entry *parent)
443 {
444         struct proc_dir_entry    *t = NULL;
445         struct proc_dir_entry   **p;
446         int                       len, busy = 0;
447
448         LASSERT(parent != NULL);
449         len = strlen(name);
450
451         LPROCFS_WRITE_ENTRY();
452
453         /* lookup target name */
454         for (p = &parent->subdir; *p; p = &(*p)->next) {
455                 if ((*p)->namelen != len)
456                         continue;
457                 if (memcmp(name, (*p)->name, len))
458                         continue;
459                 t = *p;
460                 break;
461         }
462
463         if (t) {
464                 /* verify it's empty: do not count "num_refs" */
465                 for (p = &t->subdir; *p; p = &(*p)->next) {
466                         if ((*p)->namelen != strlen("num_refs")) {
467                                 busy = 1;
468                                 break;
469                         }
470                         if (memcmp("num_refs", (*p)->name,
471                                    strlen("num_refs"))) {
472                                 busy = 1;
473                                 break;
474                         }
475                 }
476         }
477
478         if (busy == 0)
479                 lprocfs_remove_nolock(&t);
480
481         LPROCFS_WRITE_EXIT();
482
483         return;
484 }
485 EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
486
487 struct proc_dir_entry *lprocfs_register(const char *name,
488                                         struct proc_dir_entry *parent,
489                                         struct lprocfs_vars *list, void *data)
490 {
491         struct proc_dir_entry *entry;
492         int rc;
493
494         LPROCFS_WRITE_ENTRY();
495         entry = __lprocfs_srch(parent, name);
496         if (entry != NULL) {
497                 CERROR("entry '%s' already registered\n", name);
498                 GOTO(out, entry = ERR_PTR(-EALREADY));
499         }
500
501         entry = proc_mkdir(name, parent);
502         if (entry == NULL)
503                 GOTO(out, entry = ERR_PTR(-ENOMEM));
504
505         if (list != NULL) {
506                 rc = __lprocfs_add_vars(entry, list, data);
507                 if (rc != 0) {
508                         lprocfs_remove_nolock(&entry);
509                         GOTO(out, entry = ERR_PTR(rc));
510                 }
511         }
512 out:
513         LPROCFS_WRITE_EXIT();
514
515         return entry;
516 }
517 EXPORT_SYMBOL(lprocfs_register);
518
519 /* Generic callbacks */
520 int lprocfs_rd_uint(char *page, char **start, off_t off,
521                     int count, int *eof, void *data)
522 {
523         unsigned int *temp = data;
524         return snprintf(page, count, "%u\n", *temp);
525 }
526 EXPORT_SYMBOL(lprocfs_rd_uint);
527
528 int lprocfs_wr_uint(struct file *file, const char *buffer,
529                     unsigned long count, void *data)
530 {
531         unsigned *p = data;
532         char dummy[MAX_STRING_SIZE + 1], *end;
533         unsigned long tmp;
534
535         dummy[MAX_STRING_SIZE] = '\0';
536         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
537                 return -EFAULT;
538
539         tmp = simple_strtoul(dummy, &end, 0);
540         if (dummy == end)
541                 return -EINVAL;
542
543         *p = (unsigned int)tmp;
544         return count;
545 }
546 EXPORT_SYMBOL(lprocfs_wr_uint);
547
548 int lprocfs_rd_u64(char *page, char **start, off_t off,
549                    int count, int *eof, void *data)
550 {
551         LASSERT(data != NULL);
552         *eof = 1;
553         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
554 }
555 EXPORT_SYMBOL(lprocfs_rd_u64);
556
557 int lprocfs_rd_atomic(char *page, char **start, off_t off,
558                    int count, int *eof, void *data)
559 {
560         cfs_atomic_t *atom = data;
561         LASSERT(atom != NULL);
562         *eof = 1;
563         return snprintf(page, count, "%d\n", cfs_atomic_read(atom));
564 }
565 EXPORT_SYMBOL(lprocfs_rd_atomic);
566
567 int lprocfs_wr_atomic(struct file *file, const char *buffer,
568                       unsigned long count, void *data)
569 {
570         cfs_atomic_t *atm = data;
571         int val = 0;
572         int rc;
573
574         rc = lprocfs_write_helper(buffer, count, &val);
575         if (rc < 0)
576                 return rc;
577
578         if (val <= 0)
579                 return -ERANGE;
580
581         cfs_atomic_set(atm, val);
582         return count;
583 }
584 EXPORT_SYMBOL(lprocfs_wr_atomic);
585
586 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
587                     int *eof, void *data)
588 {
589         struct obd_device *obd = data;
590
591         LASSERT(obd != NULL);
592         *eof = 1;
593         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
594 }
595 EXPORT_SYMBOL(lprocfs_rd_uuid);
596
597 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
598                     int *eof, void *data)
599 {
600         struct obd_device *dev = data;
601
602         LASSERT(dev != NULL);
603         *eof = 1;
604         return snprintf(page, count, "%s\n", dev->obd_name);
605 }
606 EXPORT_SYMBOL(lprocfs_rd_name);
607
608 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
609                        int *eof, void *data)
610 {
611         struct obd_device *obd = data;
612         struct obd_statfs  osfs;
613         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
614                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
615                             OBD_STATFS_NODELAY);
616         if (!rc) {
617                 *eof = 1;
618                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
619         }
620         return rc;
621 }
622 EXPORT_SYMBOL(lprocfs_rd_blksize);
623
624 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
625                            int *eof, void *data)
626 {
627         struct obd_device *obd = data;
628         struct obd_statfs  osfs;
629         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
630                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
631                             OBD_STATFS_NODELAY);
632         if (!rc) {
633                 __u32 blk_size = osfs.os_bsize >> 10;
634                 __u64 result = osfs.os_blocks;
635
636                 while (blk_size >>= 1)
637                         result <<= 1;
638
639                 *eof = 1;
640                 rc = snprintf(page, count, LPU64"\n", result);
641         }
642         return rc;
643 }
644 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
645
646 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
647                           int *eof, void *data)
648 {
649         struct obd_device *obd = data;
650         struct obd_statfs  osfs;
651         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
652                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
653                             OBD_STATFS_NODELAY);
654         if (!rc) {
655                 __u32 blk_size = osfs.os_bsize >> 10;
656                 __u64 result = osfs.os_bfree;
657
658                 while (blk_size >>= 1)
659                         result <<= 1;
660
661                 *eof = 1;
662                 rc = snprintf(page, count, LPU64"\n", result);
663         }
664         return rc;
665 }
666 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
667
668 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
669                            int *eof, void *data)
670 {
671         struct obd_device *obd = data;
672         struct obd_statfs  osfs;
673         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
674                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
675                             OBD_STATFS_NODELAY);
676         if (!rc) {
677                 __u32 blk_size = osfs.os_bsize >> 10;
678                 __u64 result = osfs.os_bavail;
679
680                 while (blk_size >>= 1)
681                         result <<= 1;
682
683                 *eof = 1;
684                 rc = snprintf(page, count, LPU64"\n", result);
685         }
686         return rc;
687 }
688 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
689
690 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
691                           int *eof, void *data)
692 {
693         struct obd_device *obd = data;
694         struct obd_statfs  osfs;
695         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
696                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
697                             OBD_STATFS_NODELAY);
698         if (!rc) {
699                 *eof = 1;
700                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
701         }
702
703         return rc;
704 }
705 EXPORT_SYMBOL(lprocfs_rd_filestotal);
706
707 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
708                          int *eof, void *data)
709 {
710         struct obd_device *obd = data;
711         struct obd_statfs  osfs;
712         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
713                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
714                             OBD_STATFS_NODELAY);
715         if (!rc) {
716                 *eof = 1;
717                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
718         }
719         return rc;
720 }
721 EXPORT_SYMBOL(lprocfs_rd_filesfree);
722
723 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
724                            int *eof, void *data)
725 {
726         struct obd_device *obd = data;
727         struct obd_import *imp;
728         char *imp_state_name = NULL;
729         int rc = 0;
730
731         LASSERT(obd != NULL);
732         LPROCFS_CLIMP_CHECK(obd);
733         imp = obd->u.cli.cl_import;
734         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
735         *eof = 1;
736         rc = snprintf(page, count, "%s\t%s%s\n",
737                       obd2cli_tgt(obd), imp_state_name,
738                       imp->imp_deactive ? "\tDEACTIVATED" : "");
739
740         LPROCFS_CLIMP_EXIT(obd);
741         return rc;
742 }
743 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
744
745 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
746                          int *eof,  void *data)
747 {
748         struct obd_device *obd = data;
749         struct ptlrpc_connection *conn;
750         int rc = 0;
751
752         LASSERT(obd != NULL);
753
754         LPROCFS_CLIMP_CHECK(obd);
755         conn = obd->u.cli.cl_import->imp_connection;
756         *eof = 1;
757         if (conn && obd->u.cli.cl_import) {
758                 rc = snprintf(page, count, "%s\n",
759                               conn->c_remote_uuid.uuid);
760         } else {
761                 rc = snprintf(page, count, "%s\n", "<none>");
762         }
763
764         LPROCFS_CLIMP_EXIT(obd);
765         return rc;
766 }
767 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
768
769 /** add up per-cpu counters */
770 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
771                            struct lprocfs_counter *cnt)
772 {
773         unsigned int                    num_entry;
774         struct lprocfs_counter          *percpu_cntr;
775         struct lprocfs_counter_header   *cntr_header;
776         int                             i;
777         unsigned long                   flags = 0;
778
779         memset(cnt, 0, sizeof(*cnt));
780
781         if (stats == NULL) {
782                 /* set count to 1 to avoid divide-by-zero errs in callers */
783                 cnt->lc_count = 1;
784                 return;
785         }
786
787         cnt->lc_min = LC_MIN_INIT;
788
789         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
790
791         for (i = 0; i < num_entry; i++) {
792                 if (stats->ls_percpu[i] == NULL)
793                         continue;
794                 cntr_header = &stats->ls_cnt_header[idx];
795                 percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
796
797                 cnt->lc_count += percpu_cntr->lc_count;
798                 cnt->lc_sum += percpu_cntr->lc_sum;
799                 if (percpu_cntr->lc_min < cnt->lc_min)
800                         cnt->lc_min = percpu_cntr->lc_min;
801                 if (percpu_cntr->lc_max > cnt->lc_max)
802                         cnt->lc_max = percpu_cntr->lc_max;
803                 cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
804         }
805
806         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
807 }
808 EXPORT_SYMBOL(lprocfs_stats_collect);
809
810 /**
811  * Append a space separated list of current set flags to str.
812  */
813 #define flag2str(flag) \
814         if (imp->imp_##flag && max - len > 0) \
815              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
816 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
817 {
818         int len = 0;
819
820         if (imp->imp_obd->obd_no_recov)
821                 len += snprintf(str, max - len, "no_recov");
822
823         flag2str(invalid);
824         flag2str(deactive);
825         flag2str(replayable);
826         flag2str(pingable);
827         return len;
828 }
829 #undef flags2str
830
831 static const char *obd_connect_names[] = {
832         "read_only",
833         "lov_index",
834         "unused",
835         "write_grant",
836         "server_lock",
837         "version",
838         "request_portal",
839         "acl",
840         "xattr",
841         "create_on_write",
842         "truncate_lock",
843         "initial_transno",
844         "inode_bit_locks",
845         "join_file(obsolete)",
846         "getattr_by_fid",
847         "no_oh_for_devices",
848         "remote_client",
849         "remote_client_by_force",
850         "max_byte_per_rpc",
851         "64bit_qdata",
852         "mds_capability",
853         "oss_capability",
854         "early_lock_cancel",
855         "som",
856         "adaptive_timeouts",
857         "lru_resize",
858         "mds_mds_connection",
859         "real_conn",
860         "change_qunit_size",
861         "alt_checksum_algorithm",
862         "fid_is_enabled",
863         "version_recovery",
864         "pools",
865         "grant_shrink",
866         "skip_orphan",
867         "large_ea",
868         "full20",
869         "layout_lock",
870         "64bithash",
871         "object_max_bytes",
872         "imp_recov",
873         "jobstats",
874         "umask",
875         "einprogress",
876         "grant_param",
877         "flock_owner",
878         "lvb_type",
879         "nanoseconds_times",
880         "lightweight_conn",
881         "short_io",
882         "pingless",
883         "unknown",
884         NULL
885 };
886
887 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
888 {
889         __u64 mask = 1;
890         int i, ret = 0;
891
892         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
893                 if (flags & mask)
894                         ret += snprintf(page + ret, count - ret, "%s%s",
895                                         ret ? sep : "", obd_connect_names[i]);
896         }
897         if (flags & ~(mask - 1))
898                 ret += snprintf(page + ret, count - ret,
899                                 "%sunknown flags "LPX64,
900                                 ret ? sep : "", flags & ~(mask - 1));
901         return ret;
902 }
903 EXPORT_SYMBOL(obd_connect_flags2str);
904
905 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
906                       int *eof, void *data)
907 {
908         struct lprocfs_counter          ret;
909         struct lprocfs_counter_header   *header;
910         struct obd_device               *obd    = (struct obd_device *)data;
911         struct obd_import               *imp;
912         struct obd_import_conn          *conn;
913         int                             i;
914         int                             j;
915         int                             k;
916         int                             rw      = 0;
917
918         LASSERT(obd != NULL);
919         LPROCFS_CLIMP_CHECK(obd);
920         imp = obd->u.cli.cl_import;
921         *eof = 1;
922
923         i = snprintf(page, count,
924                      "import:\n"
925                      "    name: %s\n"
926                      "    target: %s\n"
927                      "    state: %s\n"
928                      "    instance: %u\n"
929                      "    connect_flags: [",
930                      obd->obd_name,
931                      obd2cli_tgt(obd),
932                      ptlrpc_import_state_name(imp->imp_state),
933                      imp->imp_connect_data.ocd_instance);
934         i += obd_connect_flags2str(page + i, count - i,
935                                    imp->imp_connect_data.ocd_connect_flags,
936                                    ", ");
937         i += snprintf(page + i, count - i,
938                       "]\n"
939                       "    import_flags: [");
940         i += obd_import_flags2str(imp, page + i, count - i);
941
942         i += snprintf(page + i, count - i,
943                       "]\n"
944                       "    connection:\n"
945                       "       failover_nids: [");
946         spin_lock(&imp->imp_lock);
947         j = 0;
948         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
949                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
950                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
951                 j++;
952         }
953         i += snprintf(page + i, count - i,
954                       "]\n"
955                       "       current_connection: %s\n"
956                       "       connection_attempts: %u\n"
957                       "       generation: %u\n"
958                       "       in-progress_invalidations: %u\n",
959                       imp->imp_connection == NULL ? "<none>" :
960                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
961                       imp->imp_conn_cnt,
962                       imp->imp_generation,
963                       cfs_atomic_read(&imp->imp_inval_count));
964         spin_unlock(&imp->imp_lock);
965
966         if (obd->obd_svc_stats == NULL)
967                 goto out_climp;
968
969         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
970         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
971         if (ret.lc_count != 0) {
972                 /* first argument to do_div MUST be __u64 */
973                 __u64 sum = ret.lc_sum;
974                 do_div(sum, ret.lc_count);
975                 ret.lc_sum = sum;
976         } else
977                 ret.lc_sum = 0;
978         i += snprintf(page + i, count - i,
979                       "    rpcs:\n"
980                       "       inflight: %u\n"
981                       "       unregistering: %u\n"
982                       "       timeouts: %u\n"
983                       "       avg_waittime: "LPU64" %s\n",
984                       cfs_atomic_read(&imp->imp_inflight),
985                       cfs_atomic_read(&imp->imp_unregistering),
986                       cfs_atomic_read(&imp->imp_timeouts),
987                       ret.lc_sum, header->lc_units);
988
989         k = 0;
990         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
991                 if (imp->imp_at.iat_portal[j] == 0)
992                         break;
993                 k = max_t(unsigned int, k,
994                           at_get(&imp->imp_at.iat_service_estimate[j]));
995         }
996         i += snprintf(page + i, count - i,
997                       "    service_estimates:\n"
998                       "       services: %u sec\n"
999                       "       network: %u sec\n",
1000                       k,
1001                       at_get(&imp->imp_at.iat_net_latency));
1002
1003         i += snprintf(page + i, count - i,
1004                       "    transactions:\n"
1005                       "       last_replay: "LPU64"\n"
1006                       "       peer_committed: "LPU64"\n"
1007                       "       last_checked: "LPU64"\n",
1008                       imp->imp_last_replay_transno,
1009                       imp->imp_peer_committed_transno,
1010                       imp->imp_last_transno_checked);
1011
1012         /* avg data rates */
1013         for (rw = 0; rw <= 1; rw++) {
1014                 lprocfs_stats_collect(obd->obd_svc_stats,
1015                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1016                                       &ret);
1017                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1018                         /* first argument to do_div MUST be __u64 */
1019                         __u64 sum = ret.lc_sum;
1020                         do_div(sum, ret.lc_count);
1021                         ret.lc_sum = sum;
1022                         i += snprintf(page + i, count - i,
1023                                       "    %s_data_averages:\n"
1024                                       "       bytes_per_rpc: "LPU64"\n",
1025                                       rw ? "write" : "read",
1026                                       ret.lc_sum);
1027                 }
1028                 k = (int)ret.lc_sum;
1029                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1030                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1031                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1032                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1033                         /* first argument to do_div MUST be __u64 */
1034                         __u64 sum = ret.lc_sum;
1035                         do_div(sum, ret.lc_count);
1036                         ret.lc_sum = sum;
1037                         i += snprintf(page + i, count - i,
1038                                       "       %s_per_rpc: "LPU64"\n",
1039                                       header->lc_units, ret.lc_sum);
1040                         j = (int)ret.lc_sum;
1041                         if (j > 0)
1042                                 i += snprintf(page + i, count - i,
1043                                               "       MB_per_sec: %u.%.02u\n",
1044                                               k / j, (100 * k / j) % 100);
1045                 }
1046         }
1047
1048 out_climp:
1049         LPROCFS_CLIMP_EXIT(obd);
1050         return i;
1051 }
1052 EXPORT_SYMBOL(lprocfs_rd_import);
1053
1054 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1055                       int *eof, void *data)
1056 {
1057         struct obd_device *obd = (struct obd_device *)data;
1058         struct obd_import *imp;
1059         int i, j, k;
1060
1061         LASSERT(obd != NULL);
1062         LPROCFS_CLIMP_CHECK(obd);
1063         imp = obd->u.cli.cl_import;
1064         *eof = 1;
1065
1066         i = snprintf(page, count, "current_state: %s\n",
1067                      ptlrpc_import_state_name(imp->imp_state));
1068         i += snprintf(page + i, count - i,
1069                       "state_history:\n");
1070         k = imp->imp_state_hist_idx;
1071         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1072                 struct import_state_hist *ish =
1073                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1074                 if (ish->ish_state == 0)
1075                         continue;
1076                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1077                               ish->ish_time,
1078                               ptlrpc_import_state_name(ish->ish_state));
1079         }
1080
1081         LPROCFS_CLIMP_EXIT(obd);
1082         return i;
1083 }
1084 EXPORT_SYMBOL(lprocfs_rd_state);
1085
1086 int lprocfs_at_hist_helper(char *page, int count, int rc,
1087                            struct adaptive_timeout *at)
1088 {
1089         int i;
1090         for (i = 0; i < AT_BINS; i++)
1091                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1092         rc += snprintf(page + rc, count - rc, "\n");
1093         return rc;
1094 }
1095 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1096
1097 /* See also ptlrpc_lprocfs_rd_timeouts */
1098 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1099                         int *eof, void *data)
1100 {
1101         struct obd_device *obd = (struct obd_device *)data;
1102         struct obd_import *imp;
1103         unsigned int cur, worst;
1104         time_t now, worstt;
1105         struct dhms ts;
1106         int i, rc = 0;
1107
1108         LASSERT(obd != NULL);
1109         LPROCFS_CLIMP_CHECK(obd);
1110         imp = obd->u.cli.cl_import;
1111         *eof = 1;
1112
1113         now = cfs_time_current_sec();
1114
1115         /* Some network health info for kicks */
1116         s2dhms(&ts, now - imp->imp_last_reply_time);
1117         rc += snprintf(page + rc, count - rc,
1118                        "%-10s : %ld, "DHMS_FMT" ago\n",
1119                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1120
1121         cur = at_get(&imp->imp_at.iat_net_latency);
1122         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1123         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1124         s2dhms(&ts, now - worstt);
1125         rc += snprintf(page + rc, count - rc,
1126                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1127                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1128         rc = lprocfs_at_hist_helper(page, count, rc,
1129                                     &imp->imp_at.iat_net_latency);
1130
1131         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1132                 if (imp->imp_at.iat_portal[i] == 0)
1133                         break;
1134                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1135                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1136                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1137                 s2dhms(&ts, now - worstt);
1138                 rc += snprintf(page + rc, count - rc,
1139                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1140                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1141                                cur, worst, worstt, DHMS_VARS(&ts));
1142                 rc = lprocfs_at_hist_helper(page, count, rc,
1143                                           &imp->imp_at.iat_service_estimate[i]);
1144         }
1145
1146         LPROCFS_CLIMP_EXIT(obd);
1147         return rc;
1148 }
1149 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1150
1151 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1152                              int count, int *eof, void *data)
1153 {
1154         struct obd_device *obd = data;
1155         __u64 flags;
1156         int ret = 0;
1157
1158         LPROCFS_CLIMP_CHECK(obd);
1159         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1160         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1161         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1162         ret += snprintf(page + ret, count - ret, "\n");
1163         LPROCFS_CLIMP_EXIT(obd);
1164         return ret;
1165 }
1166 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1167
1168 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1169                            int *eof,  void *data)
1170 {
1171         struct obd_device *obd = data;
1172
1173         LASSERT(obd != NULL);
1174         *eof = 1;
1175         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1176 }
1177 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1178
1179 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1180                        int *eof, void *data)
1181 {
1182         struct obd_type *class = (struct obd_type*) data;
1183
1184         LASSERT(class != NULL);
1185         *eof = 1;
1186         return snprintf(page, count, "%d\n", class->typ_refcnt);
1187 }
1188 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1189
1190 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1191 {
1192         int rc = 0;
1193
1194         LASSERT(obd != NULL);
1195         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1196         LASSERT(obd->obd_type->typ_procroot != NULL);
1197
1198         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1199                                                obd->obd_type->typ_procroot,
1200                                                list, obd);
1201         if (IS_ERR(obd->obd_proc_entry)) {
1202                 rc = PTR_ERR(obd->obd_proc_entry);
1203                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1204                 obd->obd_proc_entry = NULL;
1205         }
1206         return rc;
1207 }
1208 EXPORT_SYMBOL(lprocfs_obd_setup);
1209
1210 int lprocfs_obd_cleanup(struct obd_device *obd)
1211 {
1212         if (!obd)
1213                 return -EINVAL;
1214         if (obd->obd_proc_exports_entry) {
1215                 /* Should be no exports left */
1216                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1217                 lprocfs_remove(&obd->obd_proc_exports_entry);
1218                 obd->obd_proc_exports_entry = NULL;
1219         }
1220         if (obd->obd_proc_entry) {
1221                 lprocfs_remove(&obd->obd_proc_entry);
1222                 obd->obd_proc_entry = NULL;
1223         }
1224         return 0;
1225 }
1226 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1227
1228 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1229 {
1230         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
1231                client_stat->nid_proc, client_stat->nid_stats);
1232
1233         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1234                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1235                  atomic_read(&client_stat->nid_exp_ref_count));
1236
1237         if (client_stat->nid_proc)
1238                 lprocfs_remove(&client_stat->nid_proc);
1239
1240         if (client_stat->nid_stats)
1241                 lprocfs_free_stats(&client_stat->nid_stats);
1242
1243         if (client_stat->nid_ldlm_stats)
1244                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1245
1246         OBD_FREE_PTR(client_stat);
1247         return;
1248
1249 }
1250
1251 void lprocfs_free_per_client_stats(struct obd_device *obd)
1252 {
1253         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1254         struct nid_stat *stat;
1255         ENTRY;
1256
1257         /* we need extra list - because hash_exit called to early */
1258         /* not need locking because all clients is died */
1259         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1260                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1261                                       struct nid_stat, nid_list);
1262                 cfs_list_del_init(&stat->nid_list);
1263                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1264                 lprocfs_free_client_stats(stat);
1265         }
1266         EXIT;
1267 }
1268 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1269
1270 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1271                                           enum lprocfs_stats_flags flags)
1272 {
1273         struct lprocfs_stats    *stats;
1274         unsigned int            num_entry;
1275         unsigned int            percpusize = 0;
1276         int                     i;
1277
1278         if (num == 0)
1279                 return NULL;
1280
1281         if (lprocfs_no_percpu_stats != 0)
1282                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1283
1284         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1285                 num_entry = 1;
1286         else
1287                 num_entry = cfs_num_possible_cpus();
1288
1289         /* alloc percpu pointers for all possible cpu slots */
1290         LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1291         if (stats == NULL)
1292                 return NULL;
1293
1294         stats->ls_num = num;
1295         stats->ls_flags = flags;
1296         spin_lock_init(&stats->ls_lock);
1297
1298         /* alloc num of counter headers */
1299         LIBCFS_ALLOC(stats->ls_cnt_header,
1300                      stats->ls_num * sizeof(struct lprocfs_counter_header));
1301         if (stats->ls_cnt_header == NULL)
1302                 goto fail;
1303
1304         if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
1305                 /* contains only one set counters */
1306                 percpusize = lprocfs_stats_counter_size(stats);
1307                 LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
1308                 if (stats->ls_percpu[0] == NULL)
1309                         goto fail;
1310                 stats->ls_biggest_alloc_num = 1;
1311         } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
1312                 /* alloc all percpu data, currently only obd_memory use this */
1313                 for (i = 0; i < num_entry; ++i)
1314                         if (lprocfs_stats_alloc_one(stats, i) < 0)
1315                                 goto fail;
1316         }
1317
1318         return stats;
1319
1320 fail:
1321         lprocfs_free_stats(&stats);
1322         return NULL;
1323 }
1324 EXPORT_SYMBOL(lprocfs_alloc_stats);
1325
1326 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1327 {
1328         struct lprocfs_stats *stats = *statsh;
1329         unsigned int num_entry;
1330         unsigned int percpusize;
1331         unsigned int i;
1332
1333         if (stats == NULL || stats->ls_num == 0)
1334                 return;
1335         *statsh = NULL;
1336
1337         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1338                 num_entry = 1;
1339         else
1340                 num_entry = cfs_num_possible_cpus();
1341
1342         percpusize = lprocfs_stats_counter_size(stats);
1343         for (i = 0; i < num_entry; i++)
1344                 if (stats->ls_percpu[i] != NULL)
1345                         LIBCFS_FREE(stats->ls_percpu[i], percpusize);
1346         if (stats->ls_cnt_header != NULL)
1347                 LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
1348                                         sizeof(struct lprocfs_counter_header));
1349         LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1350 }
1351 EXPORT_SYMBOL(lprocfs_free_stats);
1352
1353 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1354 {
1355         struct lprocfs_counter          *percpu_cntr;
1356         struct lprocfs_counter_header   *header;
1357         int                             i;
1358         int                             j;
1359         unsigned int                    num_entry;
1360         unsigned long                   flags = 0;
1361
1362         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1363
1364         for (i = 0; i < num_entry; i++) {
1365                 if (stats->ls_percpu[i] == NULL)
1366                         continue;
1367                 for (j = 0; j < stats->ls_num; j++) {
1368                         header = &stats->ls_cnt_header[j];
1369                         percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
1370                         percpu_cntr->lc_count           = 0;
1371                         percpu_cntr->lc_min             = LC_MIN_INIT;
1372                         percpu_cntr->lc_max             = 0;
1373                         percpu_cntr->lc_sumsquare       = 0;
1374                         percpu_cntr->lc_sum             = 0;
1375                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1376                                 percpu_cntr->lc_sum_irq = 0;
1377                 }
1378         }
1379
1380         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1381 }
1382 EXPORT_SYMBOL(lprocfs_clear_stats);
1383
1384 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1385                                        size_t len, loff_t *off)
1386 {
1387         struct seq_file *seq = file->private_data;
1388         struct lprocfs_stats *stats = seq->private;
1389
1390         lprocfs_clear_stats(stats);
1391
1392         return len;
1393 }
1394
1395 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1396 {
1397         struct lprocfs_stats *stats = p->private;
1398
1399         return (*pos < stats->ls_num) ? pos : NULL;
1400 }
1401
1402 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1403 {
1404 }
1405
1406 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1407 {
1408         (*pos)++;
1409
1410         return lprocfs_stats_seq_start(p, pos);
1411 }
1412
1413 /* seq file export of one lprocfs counter */
1414 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1415 {
1416         struct lprocfs_stats            *stats  = p->private;
1417         struct lprocfs_counter_header   *hdr;
1418         struct lprocfs_counter           ctr;
1419         int                              idx    = *(loff_t *)v;
1420         int                              rc     = 0;
1421
1422         if (idx == 0) {
1423                 struct timeval now;
1424
1425                 cfs_gettimeofday(&now);
1426                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1427                                 "snapshot_time", now.tv_sec, now.tv_usec);
1428                 if (rc < 0)
1429                         return rc;
1430         }
1431
1432         hdr = &stats->ls_cnt_header[idx];
1433         lprocfs_stats_collect(stats, idx, &ctr);
1434
1435         if (ctr.lc_count == 0)
1436                 goto out;
1437
1438         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
1439                         ctr.lc_count, hdr->lc_units);
1440         if (rc < 0)
1441                 goto out;
1442
1443         if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
1444                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1445                                 ctr.lc_min, ctr.lc_max, ctr.lc_sum);
1446                 if (rc < 0)
1447                         goto out;
1448                 if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
1449                         rc = seq_printf(p, " "LPD64, ctr.lc_sumsquare);
1450                 if (rc < 0)
1451                         goto out;
1452         }
1453         rc = seq_printf(p, "\n");
1454 out:
1455         return (rc < 0) ? rc : 0;
1456 }
1457
1458 struct seq_operations lprocfs_stats_seq_sops = {
1459         .start  = lprocfs_stats_seq_start,
1460         .stop   = lprocfs_stats_seq_stop,
1461         .next   = lprocfs_stats_seq_next,
1462         .show   = lprocfs_stats_seq_show,
1463 };
1464
1465 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1466 {
1467         struct proc_dir_entry *dp = PDE(inode);
1468         struct seq_file *seq;
1469         int rc;
1470
1471         if (LPROCFS_ENTRY_CHECK(dp))
1472                 return -ENOENT;
1473
1474         rc = seq_open(file, &lprocfs_stats_seq_sops);
1475         if (rc)
1476                 return rc;
1477         seq = file->private_data;
1478         seq->private = dp->data;
1479         return 0;
1480 }
1481
1482 struct file_operations lprocfs_stats_seq_fops = {
1483         .owner   = THIS_MODULE,
1484         .open    = lprocfs_stats_seq_open,
1485         .read    = seq_read,
1486         .write   = lprocfs_stats_seq_write,
1487         .llseek  = seq_lseek,
1488         .release = lprocfs_seq_release,
1489 };
1490
1491 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1492                            struct lprocfs_stats *stats)
1493 {
1494         struct proc_dir_entry *entry;
1495         LASSERT(root != NULL);
1496
1497         LPROCFS_WRITE_ENTRY();
1498         entry = create_proc_entry(name, 0644, root);
1499         if (entry) {
1500                 entry->proc_fops = &lprocfs_stats_seq_fops;
1501                 entry->data = stats;
1502         }
1503
1504         LPROCFS_WRITE_EXIT();
1505
1506         if (entry == NULL)
1507                 return -ENOMEM;
1508
1509         return 0;
1510 }
1511 EXPORT_SYMBOL(lprocfs_register_stats);
1512
1513 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1514                           unsigned conf, const char *name, const char *units)
1515 {
1516         struct lprocfs_counter_header   *header;
1517         struct lprocfs_counter          *percpu_cntr;
1518         unsigned long                   flags = 0;
1519         unsigned int                    i;
1520         unsigned int                    num_cpu;
1521
1522         LASSERT(stats != NULL);
1523
1524         header = &stats->ls_cnt_header[index];
1525         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1526                  index, name, units);
1527
1528         header->lc_config = conf;
1529         header->lc_name   = name;
1530         header->lc_units  = units;
1531
1532         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1533         for (i = 0; i < num_cpu; ++i) {
1534                 if (stats->ls_percpu[i] == NULL)
1535                         continue;
1536                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1537                 percpu_cntr->lc_count           = 0;
1538                 percpu_cntr->lc_min             = LC_MIN_INIT;
1539                 percpu_cntr->lc_max             = 0;
1540                 percpu_cntr->lc_sumsquare       = 0;
1541                 percpu_cntr->lc_sum             = 0;
1542                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1543                         percpu_cntr->lc_sum_irq = 0;
1544         }
1545         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1546 }
1547 EXPORT_SYMBOL(lprocfs_counter_init);
1548
1549 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1550 do {                                                                       \
1551         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1552         LASSERT(coffset < stats->ls_num);                                  \
1553         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1554 } while (0)
1555
1556 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1557 {
1558         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1559         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1560         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1561         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1562         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1563         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1564         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1565         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1566         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1567         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1568         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1569         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1570         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1571         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1572         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1573         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1574         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1575         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1576         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1577         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1578         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1579         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1580         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1581         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1582         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1583         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1584         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1585         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1586         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1587         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1588         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1589         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1590         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1591         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1592         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1593         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1594         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1595         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1596         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1597         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1598         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1599         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1600         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1601         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1602         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1603         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1604         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1605         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1606         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1607         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1608         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1609         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1610         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1611         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1612         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1613         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1614         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1615         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1616         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1617         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1618         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1619         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1620         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1621         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1622         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1623         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1624         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1625 }
1626 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1627
1628 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1629 {
1630         struct lprocfs_stats *stats;
1631         unsigned int num_stats;
1632         int rc, i;
1633
1634         LASSERT(obd->obd_stats == NULL);
1635         LASSERT(obd->obd_proc_entry != NULL);
1636         LASSERT(obd->obd_cntr_base == 0);
1637
1638         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1639                 num_private_stats - 1 /* o_owner */;
1640         stats = lprocfs_alloc_stats(num_stats, 0);
1641         if (stats == NULL)
1642                 return -ENOMEM;
1643
1644         lprocfs_init_ops_stats(num_private_stats, stats);
1645
1646         for (i = num_private_stats; i < num_stats; i++) {
1647                 /* If this LBUGs, it is likely that an obd
1648                  * operation was added to struct obd_ops in
1649                  * <obd.h>, and that the corresponding line item
1650                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1651                  * is missing from the list above. */
1652                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
1653                          "Missing obd_stat initializer obd_op "
1654                          "operation at offset %d.\n", i - num_private_stats);
1655         }
1656         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1657         if (rc < 0) {
1658                 lprocfs_free_stats(&stats);
1659         } else {
1660                 obd->obd_stats  = stats;
1661                 obd->obd_cntr_base = num_private_stats;
1662         }
1663         return rc;
1664 }
1665 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1666
1667 void lprocfs_free_obd_stats(struct obd_device *obd)
1668 {
1669         if (obd->obd_stats)
1670                 lprocfs_free_stats(&obd->obd_stats);
1671 }
1672 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1673
1674 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1675 do {                                                                    \
1676         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1677         LASSERT(coffset < stats->ls_num);                               \
1678         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1679 } while (0)
1680
1681 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1682 {
1683         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1684         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1685         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1686         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1687         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1688         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1689         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1690         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1691         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1692         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1693         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1694         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1695         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1696         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1697         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1698         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1699         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1700         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1701         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1702         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1703         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1704         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1705         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1706         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1707         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1708         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1709         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1710         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1711         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1712         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1713         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1714         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1715 }
1716 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1717
1718 int lprocfs_alloc_md_stats(struct obd_device *obd,
1719                            unsigned num_private_stats)
1720 {
1721         struct lprocfs_stats *stats;
1722         unsigned int num_stats;
1723         int rc, i;
1724
1725         LASSERT(obd->md_stats == NULL);
1726         LASSERT(obd->obd_proc_entry != NULL);
1727         LASSERT(obd->md_cntr_base == 0);
1728
1729         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1730                     num_private_stats;
1731         stats = lprocfs_alloc_stats(num_stats, 0);
1732         if (stats == NULL)
1733                 return -ENOMEM;
1734
1735         lprocfs_init_mps_stats(num_private_stats, stats);
1736
1737         for (i = num_private_stats; i < num_stats; i++) {
1738                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1739                         CERROR("Missing md_stat initializer md_op "
1740                                "operation at offset %d. Aborting.\n",
1741                                i - num_private_stats);
1742                         LBUG();
1743                 }
1744         }
1745         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1746         if (rc < 0) {
1747                 lprocfs_free_stats(&stats);
1748         } else {
1749                 obd->md_stats  = stats;
1750                 obd->md_cntr_base = num_private_stats;
1751         }
1752         return rc;
1753 }
1754 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1755
1756 void lprocfs_free_md_stats(struct obd_device *obd)
1757 {
1758         struct lprocfs_stats *stats = obd->md_stats;
1759
1760         if (stats != NULL) {
1761                 obd->md_stats = NULL;
1762                 obd->md_cntr_base = 0;
1763                 lprocfs_free_stats(&stats);
1764         }
1765 }
1766 EXPORT_SYMBOL(lprocfs_free_md_stats);
1767
1768 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1769 {
1770         lprocfs_counter_init(ldlm_stats,
1771                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1772                              0, "ldlm_enqueue", "reqs");
1773         lprocfs_counter_init(ldlm_stats,
1774                              LDLM_CONVERT - LDLM_FIRST_OPC,
1775                              0, "ldlm_convert", "reqs");
1776         lprocfs_counter_init(ldlm_stats,
1777                              LDLM_CANCEL - LDLM_FIRST_OPC,
1778                              0, "ldlm_cancel", "reqs");
1779         lprocfs_counter_init(ldlm_stats,
1780                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1781                              0, "ldlm_bl_callback", "reqs");
1782         lprocfs_counter_init(ldlm_stats,
1783                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1784                              0, "ldlm_cp_callback", "reqs");
1785         lprocfs_counter_init(ldlm_stats,
1786                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1787                              0, "ldlm_gl_callback", "reqs");
1788 }
1789 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1790
1791 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1792                          int *eof,  void *data)
1793 {
1794         struct obd_export *exp = data;
1795         LASSERT(exp != NULL);
1796         *eof = 1;
1797         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1798 }
1799
1800 struct exp_uuid_cb_data {
1801         char                   *page;
1802         int                     count;
1803         int                    *eof;
1804         int                    *len;
1805 };
1806
1807 static void
1808 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1809                             int count, int *eof, int *len)
1810 {
1811         cb_data->page = page;
1812         cb_data->count = count;
1813         cb_data->eof = eof;
1814         cb_data->len = len;
1815 }
1816
1817 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1818                            cfs_hlist_node_t *hnode, void *cb_data)
1819
1820 {
1821         struct obd_export *exp = cfs_hash_object(hs, hnode);
1822         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1823
1824         if (exp->exp_nid_stats)
1825                 *data->len += snprintf((data->page + *data->len),
1826                                        data->count, "%s\n",
1827                                        obd_uuid2str(&exp->exp_client_uuid));
1828         return 0;
1829 }
1830
1831 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1832                         int *eof,  void *data)
1833 {
1834         struct nid_stat *stats = (struct nid_stat *)data;
1835         struct exp_uuid_cb_data cb_data;
1836         struct obd_device *obd = stats->nid_obd;
1837         int len = 0;
1838
1839         *eof = 1;
1840         page[0] = '\0';
1841         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1842         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1843                               lprocfs_exp_print_uuid, &cb_data);
1844         return (*cb_data.len);
1845 }
1846
1847 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1848                            cfs_hlist_node_t *hnode, void *cb_data)
1849
1850 {
1851         struct exp_uuid_cb_data *data = cb_data;
1852         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1853
1854         if (exp->exp_lock_hash != NULL) {
1855                 if (!*data->len) {
1856                         *data->len += cfs_hash_debug_header(data->page,
1857                                                             data->count);
1858                 }
1859                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1860                                                  data->count);
1861         }
1862
1863         return 0;
1864 }
1865
1866 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1867                         int *eof,  void *data)
1868 {
1869         struct nid_stat *stats = (struct nid_stat *)data;
1870         struct exp_uuid_cb_data cb_data;
1871         struct obd_device *obd = stats->nid_obd;
1872         int len = 0;
1873
1874         *eof = 1;
1875         page[0] = '\0';
1876         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1877
1878         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1879                               lprocfs_exp_print_hash, &cb_data);
1880         return (*cb_data.len);
1881 }
1882
1883 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1884                                         int count, int *eof,  void *data)
1885 {
1886         *eof = 1;
1887         return snprintf(page, count, "%s\n",
1888                         "Write into this file to clear all nid stats and "
1889                         "stale nid entries");
1890 }
1891 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1892
1893 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1894 {
1895         struct nid_stat *stat = obj;
1896         ENTRY;
1897
1898         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1899         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1900                 /* object has only hash references. */
1901                 spin_lock(&stat->nid_obd->obd_nid_lock);
1902                 cfs_list_move(&stat->nid_list, data);
1903                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1904                 RETURN(1);
1905         }
1906         /* we has reference to object - only clear data*/
1907         if (stat->nid_stats)
1908                 lprocfs_clear_stats(stat->nid_stats);
1909
1910         RETURN(0);
1911 }
1912
1913 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1914                                   unsigned long count, void *data)
1915 {
1916         struct obd_device *obd = (struct obd_device *)data;
1917         struct nid_stat *client_stat;
1918         CFS_LIST_HEAD(free_list);
1919
1920         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1921                           lprocfs_nid_stats_clear_write_cb, &free_list);
1922
1923         while (!cfs_list_empty(&free_list)) {
1924                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1925                                              nid_list);
1926                 cfs_list_del_init(&client_stat->nid_list);
1927                 lprocfs_free_client_stats(client_stat);
1928         }
1929
1930         return count;
1931 }
1932 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1933
1934 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1935 {
1936         struct nid_stat *new_stat, *old_stat;
1937         struct obd_device *obd = NULL;
1938         cfs_proc_dir_entry_t *entry;
1939         char *buffer = NULL;
1940         int rc = 0;
1941         ENTRY;
1942
1943         *newnid = 0;
1944
1945         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1946             !exp->exp_obd->obd_nid_stats_hash)
1947                 RETURN(-EINVAL);
1948
1949         /* not test against zero because eric say:
1950          * You may only test nid against another nid, or LNET_NID_ANY.
1951          * Anything else is nonsense.*/
1952         if (!nid || *nid == LNET_NID_ANY)
1953                 RETURN(0);
1954
1955         obd = exp->exp_obd;
1956
1957         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1958
1959         OBD_ALLOC_PTR(new_stat);
1960         if (new_stat == NULL)
1961                 RETURN(-ENOMEM);
1962
1963         new_stat->nid               = *nid;
1964         new_stat->nid_obd           = exp->exp_obd;
1965         /* we need set default refcount to 1 to balance obd_disconnect */
1966         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1967
1968         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1969                                            nid, &new_stat->nid_hash);
1970         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1971                old_stat, libcfs_nid2str(*nid),
1972                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1973
1974         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
1975          * been and will never be called. */
1976         if (exp->exp_nid_stats) {
1977                 nidstat_putref(exp->exp_nid_stats);
1978                 exp->exp_nid_stats = NULL;
1979         }
1980
1981         /* Return -EALREADY here so that we know that the /proc
1982          * entry already has been created */
1983         if (old_stat != new_stat) {
1984                 exp->exp_nid_stats = old_stat;
1985                 GOTO(destroy_new, rc = -EALREADY);
1986         }
1987         /* not found - create */
1988         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1989         if (buffer == NULL)
1990                 GOTO(destroy_new, rc = -ENOMEM);
1991
1992         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1993         new_stat->nid_proc = lprocfs_register(buffer,
1994                                               obd->obd_proc_exports_entry,
1995                                               NULL, NULL);
1996         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1997
1998         if (IS_ERR(new_stat->nid_proc)) {
1999                 rc = PTR_ERR(new_stat->nid_proc);
2000                 new_stat->nid_proc = NULL;
2001                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
2002                        obd->obd_name, libcfs_nid2str(*nid), rc);
2003                 GOTO(destroy_new_ns, rc);
2004         }
2005
2006         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2007                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2008         if (IS_ERR(entry)) {
2009                 CWARN("Error adding the NID stats file\n");
2010                 rc = PTR_ERR(entry);
2011                 GOTO(destroy_new_ns, rc);
2012         }
2013
2014         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2015                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2016         if (IS_ERR(entry)) {
2017                 CWARN("Error adding the hash file\n");
2018                 rc = PTR_ERR(entry);
2019                 GOTO(destroy_new_ns, rc);
2020         }
2021
2022         exp->exp_nid_stats = new_stat;
2023         *newnid = 1;
2024         /* protect competitive add to list, not need locking on destroy */
2025         spin_lock(&obd->obd_nid_lock);
2026         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2027         spin_unlock(&obd->obd_nid_lock);
2028
2029         RETURN(rc);
2030
2031 destroy_new_ns:
2032         if (new_stat->nid_proc != NULL)
2033                 lprocfs_remove(&new_stat->nid_proc);
2034         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2035
2036 destroy_new:
2037         nidstat_putref(new_stat);
2038         OBD_FREE_PTR(new_stat);
2039         RETURN(rc);
2040 }
2041 EXPORT_SYMBOL(lprocfs_exp_setup);
2042
2043 int lprocfs_exp_cleanup(struct obd_export *exp)
2044 {
2045         struct nid_stat *stat = exp->exp_nid_stats;
2046
2047         if(!stat || !exp->exp_obd)
2048                 RETURN(0);
2049
2050         nidstat_putref(exp->exp_nid_stats);
2051         exp->exp_nid_stats = NULL;
2052
2053         return 0;
2054 }
2055 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2056
2057 int lprocfs_write_helper(const char *buffer, unsigned long count,
2058                          int *val)
2059 {
2060         return lprocfs_write_frac_helper(buffer, count, val, 1);
2061 }
2062 EXPORT_SYMBOL(lprocfs_write_helper);
2063
2064 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2065                               int *val, int mult)
2066 {
2067         char kernbuf[20], *end, *pbuf;
2068
2069         if (count > (sizeof(kernbuf) - 1))
2070                 return -EINVAL;
2071
2072         if (copy_from_user(kernbuf, buffer, count))
2073                 return -EFAULT;
2074
2075         kernbuf[count] = '\0';
2076         pbuf = kernbuf;
2077         if (*pbuf == '-') {
2078                 mult = -mult;
2079                 pbuf++;
2080         }
2081
2082         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2083         if (pbuf == end)
2084                 return -EINVAL;
2085
2086         if (end != NULL && *end == '.') {
2087                 int temp_val, pow = 1;
2088                 int i;
2089
2090                 pbuf = end + 1;
2091                 if (strlen(pbuf) > 5)
2092                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2093
2094                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2095
2096                 if (pbuf < end) {
2097                         for (i = 0; i < (end - pbuf); i++)
2098                                 pow *= 10;
2099
2100                         *val += temp_val / pow;
2101                 }
2102         }
2103         return 0;
2104 }
2105 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2106
2107 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2108                              int mult)
2109 {
2110         long decimal_val, frac_val;
2111         int prtn;
2112
2113         if (count < 10)
2114                 return -EINVAL;
2115
2116         decimal_val = val / mult;
2117         prtn = snprintf(buffer, count, "%ld", decimal_val);
2118         frac_val = val % mult;
2119
2120         if (prtn < (count - 4) && frac_val > 0) {
2121                 long temp_frac;
2122                 int i, temp_mult = 1, frac_bits = 0;
2123
2124                 temp_frac = frac_val * 10;
2125                 buffer[prtn++] = '.';
2126                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2127                         /* only reserved 2 bits fraction */
2128                         buffer[prtn++] ='0';
2129                         temp_frac *= 10;
2130                         frac_bits++;
2131                 }
2132                 /*
2133                  * Need to think these cases :
2134                  *      1. #echo x.00 > /proc/xxx       output result : x
2135                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2136                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2137                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2138                  *      Only reserved 2 bits fraction.
2139                  */
2140                 for (i = 0; i < (5 - prtn); i++)
2141                         temp_mult *= 10;
2142
2143                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2144                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2145                                  frac_val * temp_mult / mult);
2146
2147                 prtn--;
2148                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2149                         prtn--;
2150                         if (buffer[prtn] == '.') {
2151                                 prtn--;
2152                                 break;
2153                         }
2154                 }
2155                 prtn++;
2156         }
2157         buffer[prtn++] ='\n';
2158         return prtn;
2159 }
2160 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2161
2162 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2163 {
2164         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2165 }
2166 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2167
2168 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2169                               __u64 *val, int mult)
2170 {
2171         char kernbuf[22], *end, *pbuf;
2172         __u64 whole, frac = 0, units;
2173         unsigned frac_d = 1;
2174
2175         if (count > (sizeof(kernbuf) - 1))
2176                 return -EINVAL;
2177
2178         if (copy_from_user(kernbuf, buffer, count))
2179                 return -EFAULT;
2180
2181         kernbuf[count] = '\0';
2182         pbuf = kernbuf;
2183         if (*pbuf == '-') {
2184                 mult = -mult;
2185                 pbuf++;
2186         }
2187
2188         whole = simple_strtoull(pbuf, &end, 10);
2189         if (pbuf == end)
2190                 return -EINVAL;
2191
2192         if (end != NULL && *end == '.') {
2193                 int i;
2194                 pbuf = end + 1;
2195
2196                 /* need to limit frac_d to a __u32 */
2197                 if (strlen(pbuf) > 10)
2198                         pbuf[10] = '\0';
2199
2200                 frac = simple_strtoull(pbuf, &end, 10);
2201                 /* count decimal places */
2202                 for (i = 0; i < (end - pbuf); i++)
2203                         frac_d *= 10;
2204         }
2205
2206         units = 1;
2207         switch(*end) {
2208         case 'p': case 'P':
2209                 units <<= 10;
2210         case 't': case 'T':
2211                 units <<= 10;
2212         case 'g': case 'G':
2213                 units <<= 10;
2214         case 'm': case 'M':
2215                 units <<= 10;
2216         case 'k': case 'K':
2217                 units <<= 10;
2218         }
2219         /* Specified units override the multiplier */
2220         if (units)
2221                 mult = mult < 0 ? -units : units;
2222
2223         frac *= mult;
2224         do_div(frac, frac_d);
2225         *val = whole * mult + frac;
2226         return 0;
2227 }
2228 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2229
2230 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2231 {
2232         size_t l2;
2233
2234         l2 = strlen(s2);
2235         if (!l2)
2236                 return (char *)s1;
2237         while (len >= l2) {
2238                 len--;
2239                 if (!memcmp(s1, s2, l2))
2240                         return (char *)s1;
2241                 s1++;
2242         }
2243         return NULL;
2244 }
2245
2246 /**
2247  * Find the string \a name in the input \a buffer, and return a pointer to the
2248  * value immediately following \a name, reducing \a count appropriately.
2249  * If \a name is not found the original \a buffer is returned.
2250  */
2251 char *lprocfs_find_named_value(const char *buffer, const char *name,
2252                                 unsigned long *count)
2253 {
2254         char *val;
2255         size_t buflen = *count;
2256
2257         /* there is no strnstr() in rhel5 and ubuntu kernels */
2258         val = lprocfs_strnstr(buffer, name, buflen);
2259         if (val == NULL)
2260                 return (char *)buffer;
2261
2262         val += strlen(name);                             /* skip prefix */
2263         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2264                 val++;
2265
2266         *count = 0;
2267         while (val < buffer + buflen && isalnum(*val)) {
2268                 ++*count;
2269                 ++val;
2270         }
2271
2272         return val - *count;
2273 }
2274 EXPORT_SYMBOL(lprocfs_find_named_value);
2275
2276 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2277                        const char *name,
2278                        mode_t mode,
2279                        const struct file_operations *seq_fops,
2280                        void *data)
2281 {
2282         struct proc_dir_entry *entry;
2283         ENTRY;
2284
2285         /* Disallow secretly (un)writable entries. */
2286         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2287
2288         LPROCFS_WRITE_ENTRY();
2289         entry = create_proc_entry(name, mode, parent);
2290         if (entry) {
2291                 entry->proc_fops = seq_fops;
2292                 entry->data = data;
2293         }
2294         LPROCFS_WRITE_EXIT();
2295
2296         if (entry == NULL)
2297                 RETURN(-ENOMEM);
2298
2299         RETURN(0);
2300 }
2301 EXPORT_SYMBOL(lprocfs_seq_create);
2302
2303 int lprocfs_obd_seq_create(struct obd_device *dev,
2304                            const char *name,
2305                            mode_t mode,
2306                            const struct file_operations *seq_fops,
2307                            void *data)
2308 {
2309         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2310                                    mode, seq_fops, data));
2311 }
2312 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2313
2314 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2315 {
2316         if (value >= OBD_HIST_MAX)
2317                 value = OBD_HIST_MAX - 1;
2318
2319         spin_lock(&oh->oh_lock);
2320         oh->oh_buckets[value]++;
2321         spin_unlock(&oh->oh_lock);
2322 }
2323 EXPORT_SYMBOL(lprocfs_oh_tally);
2324
2325 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2326 {
2327         unsigned int val;
2328
2329         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2330                 ;
2331
2332         lprocfs_oh_tally(oh, val);
2333 }
2334 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2335
2336 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2337 {
2338         unsigned long ret = 0;
2339         int i;
2340
2341         for (i = 0; i < OBD_HIST_MAX; i++)
2342                 ret +=  oh->oh_buckets[i];
2343         return ret;
2344 }
2345 EXPORT_SYMBOL(lprocfs_oh_sum);
2346
2347 void lprocfs_oh_clear(struct obd_histogram *oh)
2348 {
2349         spin_lock(&oh->oh_lock);
2350         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2351         spin_unlock(&oh->oh_lock);
2352 }
2353 EXPORT_SYMBOL(lprocfs_oh_clear);
2354
2355 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2356                         int count, int *eof, void *data)
2357 {
2358         struct obd_device *obd = data;
2359         int c = 0;
2360
2361         if (obd == NULL)
2362                 return 0;
2363
2364         c += cfs_hash_debug_header(page, count);
2365         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2366         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2367         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2368
2369         return c;
2370 }
2371 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2372
2373 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2374                                    int count, int *eof, void *data)
2375 {
2376         struct obd_device *obd = data;
2377         int len = 0, size;
2378
2379         LASSERT(obd != NULL);
2380         LASSERT(count >= 0);
2381
2382         /* Set start of user data returned to
2383            page + off since the user may have
2384            requested to read much smaller than
2385            what we need to read */
2386         *start = page + off;
2387
2388         /*
2389          * We know we are allocated a page here.
2390          * Also we know that this function will
2391          * not need to write more than a page
2392          * so we can truncate at PAGE_CACHE_SIZE.
2393          */
2394         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
2395
2396         /* Initialize the page */
2397         memset(page, 0, size);
2398
2399         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2400                 goto out;
2401         if (obd->obd_max_recoverable_clients == 0) {
2402                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2403                         goto out;
2404
2405                 goto fclose;
2406         }
2407
2408         /* sampled unlocked, but really... */
2409         if (obd->obd_recovering == 0) {
2410                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2411                         goto out;
2412                 if (lprocfs_obd_snprintf(&page, size, &len,
2413                                          "recovery_start: %lu\n",
2414                                          obd->obd_recovery_start) <= 0)
2415                         goto out;
2416                 if (lprocfs_obd_snprintf(&page, size, &len,
2417                                          "recovery_duration: %lu\n",
2418                                          obd->obd_recovery_end -
2419                                          obd->obd_recovery_start) <= 0)
2420                         goto out;
2421                 /* Number of clients that have completed recovery */
2422                 if (lprocfs_obd_snprintf(&page, size, &len,
2423                                          "completed_clients: %d/%d\n",
2424                                          obd->obd_max_recoverable_clients -
2425                                          obd->obd_stale_clients,
2426                                          obd->obd_max_recoverable_clients) <= 0)
2427                         goto out;
2428                 if (lprocfs_obd_snprintf(&page, size, &len,
2429                                          "replayed_requests: %d\n",
2430                                          obd->obd_replayed_requests) <= 0)
2431                         goto out;
2432                 if (lprocfs_obd_snprintf(&page, size, &len,
2433                                          "last_transno: "LPD64"\n",
2434                                          obd->obd_next_recovery_transno - 1)<=0)
2435                         goto out;
2436                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2437                                          obd->obd_version_recov ?
2438                                          "ENABLED" : "DISABLED") <=0)
2439                         goto out;
2440                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2441                                          obd->obd_no_ir ?
2442                                          "DISABLED" : "ENABLED") <= 0)
2443                         goto out;
2444                 goto fclose;
2445         }
2446
2447         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2448                 goto out;
2449         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2450                                  obd->obd_recovery_start) <= 0)
2451                 goto out;
2452         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2453                                  cfs_time_current_sec() >=
2454                                  obd->obd_recovery_start +
2455                                  obd->obd_recovery_timeout ? 0 :
2456                                  obd->obd_recovery_start +
2457                                  obd->obd_recovery_timeout -
2458                                  cfs_time_current_sec()) <= 0)
2459                 goto out;
2460         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2461                                  cfs_atomic_read(&obd->obd_connected_clients),
2462                                  obd->obd_max_recoverable_clients) <= 0)
2463                 goto out;
2464         /* Number of clients that have completed recovery */
2465         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2466                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2467                 <= 0)
2468                 goto out;
2469         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2470                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2471                 <=0)
2472                 goto out;
2473         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2474                                  cfs_atomic_read(&obd->obd_connected_clients) -
2475                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2476                 <=0)
2477                 goto out;
2478         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2479                                  obd->obd_stale_clients) <= 0)
2480                 goto out;
2481         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2482                                  obd->obd_replayed_requests) <= 0)
2483                 goto out;
2484         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2485                                  obd->obd_requests_queued_for_recovery) <= 0)
2486                 goto out;
2487
2488         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2489                                  obd->obd_next_recovery_transno) <= 0)
2490                 goto out;
2491
2492 fclose:
2493         *eof = 1;
2494 out:
2495         return min(count, len - (int)off);
2496 }
2497 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2498
2499 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2500                              int count, int *eof, void *data)
2501 {
2502         struct obd_device *obd = (struct obd_device *)data;
2503         LASSERT(obd != NULL);
2504
2505         return snprintf(page, count, "%d\n",
2506                         obd->obd_recovery_ir_factor);
2507 }
2508 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2509
2510 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2511                              unsigned long count, void *data)
2512 {
2513         struct obd_device *obd = (struct obd_device *)data;
2514         int val, rc;
2515         LASSERT(obd != NULL);
2516
2517         rc = lprocfs_write_helper(buffer, count, &val);
2518         if (rc)
2519                 return rc;
2520
2521         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2522                 return -EINVAL;
2523
2524         obd->obd_recovery_ir_factor = val;
2525         return count;
2526 }
2527 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2528
2529 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2530                                       int count, int *eof, void *data)
2531 {
2532         struct obd_device *obd = (struct obd_device *)data;
2533         LASSERT(obd != NULL);
2534
2535         return snprintf(page, count, "%d\n",
2536                         obd->obd_recovery_timeout);
2537 }
2538 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2539
2540 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2541                                       unsigned long count, void *data)
2542 {
2543         struct obd_device *obd = (struct obd_device *)data;
2544         int val, rc;
2545         LASSERT(obd != NULL);
2546
2547         rc = lprocfs_write_helper(buffer, count, &val);
2548         if (rc)
2549                 return rc;
2550
2551         obd->obd_recovery_timeout = val;
2552         return count;
2553 }
2554 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2555
2556 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2557                                       int count, int *eof, void *data)
2558 {
2559         struct obd_device *obd = data;
2560         LASSERT(obd != NULL);
2561
2562         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2563 }
2564 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2565
2566 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2567                                       unsigned long count, void *data)
2568 {
2569         struct obd_device *obd = data;
2570         int val, rc;
2571         LASSERT(obd != NULL);
2572
2573         rc = lprocfs_write_helper(buffer, count, &val);
2574         if (rc)
2575                 return rc;
2576
2577         obd->obd_recovery_time_hard = val;
2578         return count;
2579 }
2580 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2581
2582 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2583                                      int count, int *eof, void *data)
2584 {
2585         struct obd_device *dev = data;
2586         struct client_obd *cli = &dev->u.cli;
2587         int rc;
2588
2589         client_obd_list_lock(&cli->cl_loi_list_lock);
2590         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2591         client_obd_list_unlock(&cli->cl_loi_list_lock);
2592         return rc;
2593 }
2594 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2595
2596 #ifdef HAVE_SERVER_SUPPORT
2597 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2598                                int count, int *eof, void *data)
2599 {
2600         struct obd_device *obd = (struct obd_device *)data;
2601         struct obd_device_target *target = &obd->u.obt;
2602
2603         LASSERT(obd != NULL);
2604         LASSERT(target->obt_magic == OBT_MAGIC);
2605         *eof = 1;
2606         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2607 }
2608 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2609 #endif
2610 #endif /* LPROCFS*/