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