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