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