Whamcloud - gitweb
5ce7661e36836733fdc0616f46ed84bf094c378a
[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 >= CFS_PAGE_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, CFS_PAGE_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 (cfs_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 (cfs_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         /* return 1st cpu location */
1385         return (*pos >= stats->ls_num) ? NULL :
1386                 lprocfs_stats_counter_get(stats, 0, *pos);
1387 }
1388
1389 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1390 {
1391 }
1392
1393 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1394 {
1395         struct lprocfs_stats *stats = p->private;
1396         ++*pos;
1397         return (*pos >= stats->ls_num) ? NULL :
1398                 lprocfs_stats_counter_get(stats, 0, *pos);
1399 }
1400
1401 /* seq file export of one lprocfs counter */
1402 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1403 {
1404         struct lprocfs_stats            *stats  = p->private;
1405         struct lprocfs_counter          *cntr   = v;
1406         struct lprocfs_counter          ret;
1407         struct lprocfs_counter_header   *header;
1408         int                             entry_size;
1409         int                             idx;
1410         int                             rc      = 0;
1411
1412         if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1413                 struct timeval now;
1414                 cfs_gettimeofday(&now);
1415                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1416                                 "snapshot_time", now.tv_sec, now.tv_usec);
1417                 if (rc < 0)
1418                         return rc;
1419         }
1420         entry_size = sizeof(*cntr);
1421         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1422                 entry_size += sizeof(__s64);
1423         idx = ((void *)cntr - (void *)&(stats->ls_percpu[0])->lp_cntr[0]) /
1424                 entry_size;
1425
1426         header = &stats->ls_cnt_header[idx];
1427         lprocfs_stats_collect(stats, idx, &ret);
1428
1429         if (ret.lc_count == 0)
1430                 goto out;
1431
1432         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", header->lc_name,
1433                         ret.lc_count, header->lc_units);
1434
1435         if (rc < 0)
1436                 goto out;
1437
1438         if ((header->lc_config & LPROCFS_CNTR_AVGMINMAX) &&
1439             (ret.lc_count > 0)) {
1440                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1441                                 ret.lc_min, ret.lc_max, ret.lc_sum);
1442                 if (rc < 0)
1443                         goto out;
1444                 if (header->lc_config & LPROCFS_CNTR_STDDEV)
1445                         rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1446                 if (rc < 0)
1447                         goto out;
1448         }
1449         rc = seq_printf(p, "\n");
1450  out:
1451         return (rc < 0) ? rc : 0;
1452 }
1453
1454 struct seq_operations lprocfs_stats_seq_sops = {
1455         start: lprocfs_stats_seq_start,
1456         stop:  lprocfs_stats_seq_stop,
1457         next:  lprocfs_stats_seq_next,
1458         show:  lprocfs_stats_seq_show,
1459 };
1460
1461 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1462 {
1463         struct proc_dir_entry *dp = PDE(inode);
1464         struct seq_file *seq;
1465         int rc;
1466
1467         if (LPROCFS_ENTRY_AND_CHECK(dp))
1468                 return -ENOENT;
1469
1470         rc = seq_open(file, &lprocfs_stats_seq_sops);
1471         if (rc) {
1472                 LPROCFS_EXIT();
1473                 return rc;
1474         }
1475         seq = file->private_data;
1476         seq->private = dp->data;
1477         return 0;
1478 }
1479
1480 struct file_operations lprocfs_stats_seq_fops = {
1481         .owner   = THIS_MODULE,
1482         .open    = lprocfs_stats_seq_open,
1483         .read    = seq_read,
1484         .write   = lprocfs_stats_seq_write,
1485         .llseek  = seq_lseek,
1486         .release = lprocfs_seq_release,
1487 };
1488
1489 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1490                            struct lprocfs_stats *stats)
1491 {
1492         struct proc_dir_entry *entry;
1493         LASSERT(root != NULL);
1494
1495         LPROCFS_WRITE_ENTRY();
1496         entry = create_proc_entry(name, 0644, root);
1497         if (entry) {
1498                 entry->proc_fops = &lprocfs_stats_seq_fops;
1499                 entry->data = stats;
1500         }
1501
1502         LPROCFS_WRITE_EXIT();
1503
1504         if (entry == NULL)
1505                 return -ENOMEM;
1506
1507         return 0;
1508 }
1509 EXPORT_SYMBOL(lprocfs_register_stats);
1510
1511 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1512                           unsigned conf, const char *name, const char *units)
1513 {
1514         struct lprocfs_counter_header   *header;
1515         struct lprocfs_counter          *percpu_cntr;
1516         unsigned long                   flags = 0;
1517         unsigned int                    i;
1518         unsigned int                    num_cpu;
1519
1520         LASSERT(stats != NULL);
1521
1522         header = &stats->ls_cnt_header[index];
1523         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1524                  index, name, units);
1525
1526         header->lc_config = conf;
1527         header->lc_name   = name;
1528         header->lc_units  = units;
1529
1530         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1531         for (i = 0; i < num_cpu; ++i) {
1532                 if (stats->ls_percpu[i] == NULL)
1533                         continue;
1534                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1535                 percpu_cntr->lc_count           = 0;
1536                 percpu_cntr->lc_min             = LC_MIN_INIT;
1537                 percpu_cntr->lc_max             = 0;
1538                 percpu_cntr->lc_sumsquare       = 0;
1539                 percpu_cntr->lc_sum             = 0;
1540                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1541                         percpu_cntr->lc_sum_irq = 0;
1542         }
1543         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1544 }
1545 EXPORT_SYMBOL(lprocfs_counter_init);
1546
1547 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1548 do {                                                                       \
1549         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1550         LASSERT(coffset < stats->ls_num);                                  \
1551         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1552 } while (0)
1553
1554 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1555 {
1556         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1557         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1558         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1559         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1560         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1561         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1562         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1563         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1564         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1565         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1566         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1567         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1568         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1569         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1570         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1571         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1572         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1573         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1574         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1575         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1576         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1577         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1578         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1579         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1580         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1581         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1582         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1583         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1584         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1585         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1586         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1587         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1588         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1589         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1590         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1591         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1592         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1593         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1594         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1595         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1596         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1597         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1598         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1599         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1600         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1601         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1602         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1603         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1604         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1605         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1606         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1607         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1608         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1609         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1610         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1611         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1612         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1613         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1614         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1615         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1616         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1617         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1618         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1619         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1620         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1621         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1622         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1623 }
1624 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1625
1626 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1627 {
1628         struct lprocfs_stats *stats;
1629         unsigned int num_stats;
1630         int rc, i;
1631
1632         LASSERT(obd->obd_stats == NULL);
1633         LASSERT(obd->obd_proc_entry != NULL);
1634         LASSERT(obd->obd_cntr_base == 0);
1635
1636         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1637                 num_private_stats - 1 /* o_owner */;
1638         stats = lprocfs_alloc_stats(num_stats, 0);
1639         if (stats == NULL)
1640                 return -ENOMEM;
1641
1642         lprocfs_init_ops_stats(num_private_stats, stats);
1643
1644         for (i = num_private_stats; i < num_stats; i++) {
1645                 /* If this LBUGs, it is likely that an obd
1646                  * operation was added to struct obd_ops in
1647                  * <obd.h>, and that the corresponding line item
1648                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1649                  * is missing from the list above. */
1650                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
1651                          "Missing obd_stat initializer obd_op "
1652                          "operation at offset %d.\n", i - num_private_stats);
1653         }
1654         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1655         if (rc < 0) {
1656                 lprocfs_free_stats(&stats);
1657         } else {
1658                 obd->obd_stats  = stats;
1659                 obd->obd_cntr_base = num_private_stats;
1660         }
1661         return rc;
1662 }
1663 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1664
1665 void lprocfs_free_obd_stats(struct obd_device *obd)
1666 {
1667         if (obd->obd_stats)
1668                 lprocfs_free_stats(&obd->obd_stats);
1669 }
1670 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1671
1672 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1673 do {                                                                    \
1674         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1675         LASSERT(coffset < stats->ls_num);                               \
1676         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1677 } while (0)
1678
1679 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1680 {
1681         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1682         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1683         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1684         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1685         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1686         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1687         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1688         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1689         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1690         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1691         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1692         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1693         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1694         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1695         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1696         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1697         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1698         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1699         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1700         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1701         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1702         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1703         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1704         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1705         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1706         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1707         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1708         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1709         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1710         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1711         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1712         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1713 }
1714 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1715
1716 int lprocfs_alloc_md_stats(struct obd_device *obd,
1717                            unsigned num_private_stats)
1718 {
1719         struct lprocfs_stats *stats;
1720         unsigned int num_stats;
1721         int rc, i;
1722
1723         LASSERT(obd->md_stats == NULL);
1724         LASSERT(obd->obd_proc_entry != NULL);
1725         LASSERT(obd->md_cntr_base == 0);
1726
1727         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1728                     num_private_stats;
1729         stats = lprocfs_alloc_stats(num_stats, 0);
1730         if (stats == NULL)
1731                 return -ENOMEM;
1732
1733         lprocfs_init_mps_stats(num_private_stats, stats);
1734
1735         for (i = num_private_stats; i < num_stats; i++) {
1736                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1737                         CERROR("Missing md_stat initializer md_op "
1738                                "operation at offset %d. Aborting.\n",
1739                                i - num_private_stats);
1740                         LBUG();
1741                 }
1742         }
1743         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1744         if (rc < 0) {
1745                 lprocfs_free_stats(&stats);
1746         } else {
1747                 obd->md_stats  = stats;
1748                 obd->md_cntr_base = num_private_stats;
1749         }
1750         return rc;
1751 }
1752 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1753
1754 void lprocfs_free_md_stats(struct obd_device *obd)
1755 {
1756         struct lprocfs_stats *stats = obd->md_stats;
1757
1758         if (stats != NULL) {
1759                 obd->md_stats = NULL;
1760                 obd->md_cntr_base = 0;
1761                 lprocfs_free_stats(&stats);
1762         }
1763 }
1764 EXPORT_SYMBOL(lprocfs_free_md_stats);
1765
1766 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1767 {
1768         lprocfs_counter_init(ldlm_stats,
1769                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1770                              0, "ldlm_enqueue", "reqs");
1771         lprocfs_counter_init(ldlm_stats,
1772                              LDLM_CONVERT - LDLM_FIRST_OPC,
1773                              0, "ldlm_convert", "reqs");
1774         lprocfs_counter_init(ldlm_stats,
1775                              LDLM_CANCEL - LDLM_FIRST_OPC,
1776                              0, "ldlm_cancel", "reqs");
1777         lprocfs_counter_init(ldlm_stats,
1778                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1779                              0, "ldlm_bl_callback", "reqs");
1780         lprocfs_counter_init(ldlm_stats,
1781                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1782                              0, "ldlm_cp_callback", "reqs");
1783         lprocfs_counter_init(ldlm_stats,
1784                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1785                              0, "ldlm_gl_callback", "reqs");
1786 }
1787 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1788
1789 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1790                          int *eof,  void *data)
1791 {
1792         struct obd_export *exp = data;
1793         LASSERT(exp != NULL);
1794         *eof = 1;
1795         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1796 }
1797
1798 struct exp_uuid_cb_data {
1799         char                   *page;
1800         int                     count;
1801         int                    *eof;
1802         int                    *len;
1803 };
1804
1805 static void
1806 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1807                             int count, int *eof, int *len)
1808 {
1809         cb_data->page = page;
1810         cb_data->count = count;
1811         cb_data->eof = eof;
1812         cb_data->len = len;
1813 }
1814
1815 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1816                            cfs_hlist_node_t *hnode, void *cb_data)
1817
1818 {
1819         struct obd_export *exp = cfs_hash_object(hs, hnode);
1820         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1821
1822         if (exp->exp_nid_stats)
1823                 *data->len += snprintf((data->page + *data->len),
1824                                        data->count, "%s\n",
1825                                        obd_uuid2str(&exp->exp_client_uuid));
1826         return 0;
1827 }
1828
1829 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1830                         int *eof,  void *data)
1831 {
1832         struct nid_stat *stats = (struct nid_stat *)data;
1833         struct exp_uuid_cb_data cb_data;
1834         struct obd_device *obd = stats->nid_obd;
1835         int len = 0;
1836
1837         *eof = 1;
1838         page[0] = '\0';
1839         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1840         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1841                               lprocfs_exp_print_uuid, &cb_data);
1842         return (*cb_data.len);
1843 }
1844
1845 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1846                            cfs_hlist_node_t *hnode, void *cb_data)
1847
1848 {
1849         struct exp_uuid_cb_data *data = cb_data;
1850         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1851
1852         if (exp->exp_lock_hash != NULL) {
1853                 if (!*data->len) {
1854                         *data->len += cfs_hash_debug_header(data->page,
1855                                                             data->count);
1856                 }
1857                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1858                                                  data->count);
1859         }
1860
1861         return 0;
1862 }
1863
1864 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1865                         int *eof,  void *data)
1866 {
1867         struct nid_stat *stats = (struct nid_stat *)data;
1868         struct exp_uuid_cb_data cb_data;
1869         struct obd_device *obd = stats->nid_obd;
1870         int len = 0;
1871
1872         *eof = 1;
1873         page[0] = '\0';
1874         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1875
1876         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1877                               lprocfs_exp_print_hash, &cb_data);
1878         return (*cb_data.len);
1879 }
1880
1881 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1882                                         int count, int *eof,  void *data)
1883 {
1884         *eof = 1;
1885         return snprintf(page, count, "%s\n",
1886                         "Write into this file to clear all nid stats and "
1887                         "stale nid entries");
1888 }
1889 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1890
1891 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1892 {
1893         struct nid_stat *stat = obj;
1894         ENTRY;
1895
1896         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1897         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1898                 /* object has only hash references. */
1899                 spin_lock(&stat->nid_obd->obd_nid_lock);
1900                 cfs_list_move(&stat->nid_list, data);
1901                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1902                 RETURN(1);
1903         }
1904         /* we has reference to object - only clear data*/
1905         if (stat->nid_stats)
1906                 lprocfs_clear_stats(stat->nid_stats);
1907
1908         RETURN(0);
1909 }
1910
1911 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1912                                   unsigned long count, void *data)
1913 {
1914         struct obd_device *obd = (struct obd_device *)data;
1915         struct nid_stat *client_stat;
1916         CFS_LIST_HEAD(free_list);
1917
1918         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1919                           lprocfs_nid_stats_clear_write_cb, &free_list);
1920
1921         while (!cfs_list_empty(&free_list)) {
1922                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1923                                              nid_list);
1924                 cfs_list_del_init(&client_stat->nid_list);
1925                 lprocfs_free_client_stats(client_stat);
1926         }
1927
1928         return count;
1929 }
1930 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1931
1932 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1933 {
1934         struct nid_stat *new_stat, *old_stat;
1935         struct obd_device *obd = NULL;
1936         cfs_proc_dir_entry_t *entry;
1937         char *buffer = NULL;
1938         int rc = 0;
1939         ENTRY;
1940
1941         *newnid = 0;
1942
1943         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1944             !exp->exp_obd->obd_nid_stats_hash)
1945                 RETURN(-EINVAL);
1946
1947         /* not test against zero because eric say:
1948          * You may only test nid against another nid, or LNET_NID_ANY.
1949          * Anything else is nonsense.*/
1950         if (!nid || *nid == LNET_NID_ANY)
1951                 RETURN(0);
1952
1953         obd = exp->exp_obd;
1954
1955         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1956
1957         OBD_ALLOC_PTR(new_stat);
1958         if (new_stat == NULL)
1959                 RETURN(-ENOMEM);
1960
1961         new_stat->nid               = *nid;
1962         new_stat->nid_obd           = exp->exp_obd;
1963         /* we need set default refcount to 1 to balance obd_disconnect */
1964         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1965
1966         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1967                                            nid, &new_stat->nid_hash);
1968         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1969                old_stat, libcfs_nid2str(*nid),
1970                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1971
1972         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
1973          * been and will never be called. */
1974         if (exp->exp_nid_stats) {
1975                 nidstat_putref(exp->exp_nid_stats);
1976                 exp->exp_nid_stats = NULL;
1977         }
1978
1979         /* Return -EALREADY here so that we know that the /proc
1980          * entry already has been created */
1981         if (old_stat != new_stat) {
1982                 exp->exp_nid_stats = old_stat;
1983                 GOTO(destroy_new, rc = -EALREADY);
1984         }
1985         /* not found - create */
1986         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1987         if (buffer == NULL)
1988                 GOTO(destroy_new, rc = -ENOMEM);
1989
1990         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1991         new_stat->nid_proc = lprocfs_register(buffer,
1992                                               obd->obd_proc_exports_entry,
1993                                               NULL, NULL);
1994         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1995
1996         if (new_stat->nid_proc == NULL) {
1997                 CERROR("Error making export directory for nid %s\n",
1998                        libcfs_nid2str(*nid));
1999                 GOTO(destroy_new_ns, rc = -ENOMEM);
2000         }
2001
2002         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2003                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2004         if (IS_ERR(entry)) {
2005                 CWARN("Error adding the NID stats file\n");
2006                 rc = PTR_ERR(entry);
2007                 GOTO(destroy_new_ns, rc);
2008         }
2009
2010         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2011                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2012         if (IS_ERR(entry)) {
2013                 CWARN("Error adding the hash file\n");
2014                 rc = PTR_ERR(entry);
2015                 GOTO(destroy_new_ns, rc);
2016         }
2017
2018         exp->exp_nid_stats = new_stat;
2019         *newnid = 1;
2020         /* protect competitive add to list, not need locking on destroy */
2021         spin_lock(&obd->obd_nid_lock);
2022         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2023         spin_unlock(&obd->obd_nid_lock);
2024
2025         RETURN(rc);
2026
2027 destroy_new_ns:
2028         if (new_stat->nid_proc != NULL)
2029                 lprocfs_remove(&new_stat->nid_proc);
2030         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2031
2032 destroy_new:
2033         nidstat_putref(new_stat);
2034         OBD_FREE_PTR(new_stat);
2035         RETURN(rc);
2036 }
2037 EXPORT_SYMBOL(lprocfs_exp_setup);
2038
2039 int lprocfs_exp_cleanup(struct obd_export *exp)
2040 {
2041         struct nid_stat *stat = exp->exp_nid_stats;
2042
2043         if(!stat || !exp->exp_obd)
2044                 RETURN(0);
2045
2046         nidstat_putref(exp->exp_nid_stats);
2047         exp->exp_nid_stats = NULL;
2048
2049         return 0;
2050 }
2051 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2052
2053 int lprocfs_write_helper(const char *buffer, unsigned long count,
2054                          int *val)
2055 {
2056         return lprocfs_write_frac_helper(buffer, count, val, 1);
2057 }
2058 EXPORT_SYMBOL(lprocfs_write_helper);
2059
2060 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2061                               int *val, int mult)
2062 {
2063         char kernbuf[20], *end, *pbuf;
2064
2065         if (count > (sizeof(kernbuf) - 1))
2066                 return -EINVAL;
2067
2068         if (cfs_copy_from_user(kernbuf, buffer, count))
2069                 return -EFAULT;
2070
2071         kernbuf[count] = '\0';
2072         pbuf = kernbuf;
2073         if (*pbuf == '-') {
2074                 mult = -mult;
2075                 pbuf++;
2076         }
2077
2078         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2079         if (pbuf == end)
2080                 return -EINVAL;
2081
2082         if (end != NULL && *end == '.') {
2083                 int temp_val, pow = 1;
2084                 int i;
2085
2086                 pbuf = end + 1;
2087                 if (strlen(pbuf) > 5)
2088                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2089
2090                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2091
2092                 if (pbuf < end) {
2093                         for (i = 0; i < (end - pbuf); i++)
2094                                 pow *= 10;
2095
2096                         *val += temp_val / pow;
2097                 }
2098         }
2099         return 0;
2100 }
2101 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2102
2103 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2104                              int mult)
2105 {
2106         long decimal_val, frac_val;
2107         int prtn;
2108
2109         if (count < 10)
2110                 return -EINVAL;
2111
2112         decimal_val = val / mult;
2113         prtn = snprintf(buffer, count, "%ld", decimal_val);
2114         frac_val = val % mult;
2115
2116         if (prtn < (count - 4) && frac_val > 0) {
2117                 long temp_frac;
2118                 int i, temp_mult = 1, frac_bits = 0;
2119
2120                 temp_frac = frac_val * 10;
2121                 buffer[prtn++] = '.';
2122                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2123                         /* only reserved 2 bits fraction */
2124                         buffer[prtn++] ='0';
2125                         temp_frac *= 10;
2126                         frac_bits++;
2127                 }
2128                 /*
2129                  * Need to think these cases :
2130                  *      1. #echo x.00 > /proc/xxx       output result : x
2131                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2132                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2133                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2134                  *      Only reserved 2 bits fraction.
2135                  */
2136                 for (i = 0; i < (5 - prtn); i++)
2137                         temp_mult *= 10;
2138
2139                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2140                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2141                                  frac_val * temp_mult / mult);
2142
2143                 prtn--;
2144                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2145                         prtn--;
2146                         if (buffer[prtn] == '.') {
2147                                 prtn--;
2148                                 break;
2149                         }
2150                 }
2151                 prtn++;
2152         }
2153         buffer[prtn++] ='\n';
2154         return prtn;
2155 }
2156 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2157
2158 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2159 {
2160         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2161 }
2162 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2163
2164 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2165                               __u64 *val, int mult)
2166 {
2167         char kernbuf[22], *end, *pbuf;
2168         __u64 whole, frac = 0, units;
2169         unsigned frac_d = 1;
2170
2171         if (count > (sizeof(kernbuf) - 1))
2172                 return -EINVAL;
2173
2174         if (cfs_copy_from_user(kernbuf, buffer, count))
2175                 return -EFAULT;
2176
2177         kernbuf[count] = '\0';
2178         pbuf = kernbuf;
2179         if (*pbuf == '-') {
2180                 mult = -mult;
2181                 pbuf++;
2182         }
2183
2184         whole = simple_strtoull(pbuf, &end, 10);
2185         if (pbuf == end)
2186                 return -EINVAL;
2187
2188         if (end != NULL && *end == '.') {
2189                 int i;
2190                 pbuf = end + 1;
2191
2192                 /* need to limit frac_d to a __u32 */
2193                 if (strlen(pbuf) > 10)
2194                         pbuf[10] = '\0';
2195
2196                 frac = simple_strtoull(pbuf, &end, 10);
2197                 /* count decimal places */
2198                 for (i = 0; i < (end - pbuf); i++)
2199                         frac_d *= 10;
2200         }
2201
2202         units = 1;
2203         switch(*end) {
2204         case 'p': case 'P':
2205                 units <<= 10;
2206         case 't': case 'T':
2207                 units <<= 10;
2208         case 'g': case 'G':
2209                 units <<= 10;
2210         case 'm': case 'M':
2211                 units <<= 10;
2212         case 'k': case 'K':
2213                 units <<= 10;
2214         }
2215         /* Specified units override the multiplier */
2216         if (units)
2217                 mult = mult < 0 ? -units : units;
2218
2219         frac *= mult;
2220         do_div(frac, frac_d);
2221         *val = whole * mult + frac;
2222         return 0;
2223 }
2224 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2225
2226 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2227 {
2228         size_t l2;
2229
2230         l2 = strlen(s2);
2231         if (!l2)
2232                 return (char *)s1;
2233         while (len >= l2) {
2234                 len--;
2235                 if (!memcmp(s1, s2, l2))
2236                         return (char *)s1;
2237                 s1++;
2238         }
2239         return NULL;
2240 }
2241
2242 /**
2243  * Find the string \a name in the input \a buffer, and return a pointer to the
2244  * value immediately following \a name, reducing \a count appropriately.
2245  * If \a name is not found the original \a buffer is returned.
2246  */
2247 char *lprocfs_find_named_value(const char *buffer, const char *name,
2248                                 unsigned long *count)
2249 {
2250         char *val;
2251         size_t buflen = *count;
2252
2253         /* there is no strnstr() in rhel5 and ubuntu kernels */
2254         val = lprocfs_strnstr(buffer, name, buflen);
2255         if (val == NULL)
2256                 return (char *)buffer;
2257
2258         val += strlen(name);                             /* skip prefix */
2259         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2260                 val++;
2261
2262         *count = 0;
2263         while (val < buffer + buflen && isalnum(*val)) {
2264                 ++*count;
2265                 ++val;
2266         }
2267
2268         return val - *count;
2269 }
2270 EXPORT_SYMBOL(lprocfs_find_named_value);
2271
2272 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2273                        const char *name,
2274                        mode_t mode,
2275                        const struct file_operations *seq_fops,
2276                        void *data)
2277 {
2278         struct proc_dir_entry *entry;
2279         ENTRY;
2280
2281         /* Disallow secretly (un)writable entries. */
2282         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2283
2284         LPROCFS_WRITE_ENTRY();
2285         entry = create_proc_entry(name, mode, parent);
2286         if (entry) {
2287                 entry->proc_fops = seq_fops;
2288                 entry->data = data;
2289         }
2290         LPROCFS_WRITE_EXIT();
2291
2292         if (entry == NULL)
2293                 RETURN(-ENOMEM);
2294
2295         RETURN(0);
2296 }
2297 EXPORT_SYMBOL(lprocfs_seq_create);
2298
2299 int lprocfs_obd_seq_create(struct obd_device *dev,
2300                            const char *name,
2301                            mode_t mode,
2302                            const struct file_operations *seq_fops,
2303                            void *data)
2304 {
2305         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2306                                    mode, seq_fops, data));
2307 }
2308 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2309
2310 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2311 {
2312         if (value >= OBD_HIST_MAX)
2313                 value = OBD_HIST_MAX - 1;
2314
2315         spin_lock(&oh->oh_lock);
2316         oh->oh_buckets[value]++;
2317         spin_unlock(&oh->oh_lock);
2318 }
2319 EXPORT_SYMBOL(lprocfs_oh_tally);
2320
2321 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2322 {
2323         unsigned int val;
2324
2325         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2326                 ;
2327
2328         lprocfs_oh_tally(oh, val);
2329 }
2330 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2331
2332 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2333 {
2334         unsigned long ret = 0;
2335         int i;
2336
2337         for (i = 0; i < OBD_HIST_MAX; i++)
2338                 ret +=  oh->oh_buckets[i];
2339         return ret;
2340 }
2341 EXPORT_SYMBOL(lprocfs_oh_sum);
2342
2343 void lprocfs_oh_clear(struct obd_histogram *oh)
2344 {
2345         spin_lock(&oh->oh_lock);
2346         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2347         spin_unlock(&oh->oh_lock);
2348 }
2349 EXPORT_SYMBOL(lprocfs_oh_clear);
2350
2351 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2352                         int count, int *eof, void *data)
2353 {
2354         struct obd_device *obd = data;
2355         int c = 0;
2356
2357         if (obd == NULL)
2358                 return 0;
2359
2360         c += cfs_hash_debug_header(page, count);
2361         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2362         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2363         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2364
2365         return c;
2366 }
2367 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2368
2369 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2370                                    int count, int *eof, void *data)
2371 {
2372         struct obd_device *obd = data;
2373         int len = 0, size;
2374
2375         LASSERT(obd != NULL);
2376         LASSERT(count >= 0);
2377
2378         /* Set start of user data returned to
2379            page + off since the user may have
2380            requested to read much smaller than
2381            what we need to read */
2382         *start = page + off;
2383
2384         /* We know we are allocated a page here.
2385            Also we know that this function will
2386            not need to write more than a page
2387            so we can truncate at CFS_PAGE_SIZE.  */
2388         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2389
2390         /* Initialize the page */
2391         memset(page, 0, size);
2392
2393         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2394                 goto out;
2395         if (obd->obd_max_recoverable_clients == 0) {
2396                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2397                         goto out;
2398
2399                 goto fclose;
2400         }
2401
2402         /* sampled unlocked, but really... */
2403         if (obd->obd_recovering == 0) {
2404                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2405                         goto out;
2406                 if (lprocfs_obd_snprintf(&page, size, &len,
2407                                          "recovery_start: %lu\n",
2408                                          obd->obd_recovery_start) <= 0)
2409                         goto out;
2410                 if (lprocfs_obd_snprintf(&page, size, &len,
2411                                          "recovery_duration: %lu\n",
2412                                          obd->obd_recovery_end -
2413                                          obd->obd_recovery_start) <= 0)
2414                         goto out;
2415                 /* Number of clients that have completed recovery */
2416                 if (lprocfs_obd_snprintf(&page, size, &len,
2417                                          "completed_clients: %d/%d\n",
2418                                          obd->obd_max_recoverable_clients -
2419                                          obd->obd_stale_clients,
2420                                          obd->obd_max_recoverable_clients) <= 0)
2421                         goto out;
2422                 if (lprocfs_obd_snprintf(&page, size, &len,
2423                                          "replayed_requests: %d\n",
2424                                          obd->obd_replayed_requests) <= 0)
2425                         goto out;
2426                 if (lprocfs_obd_snprintf(&page, size, &len,
2427                                          "last_transno: "LPD64"\n",
2428                                          obd->obd_next_recovery_transno - 1)<=0)
2429                         goto out;
2430                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2431                                          obd->obd_version_recov ?
2432                                          "ENABLED" : "DISABLED") <=0)
2433                         goto out;
2434                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2435                                          obd->obd_no_ir ?
2436                                          "DISABLED" : "ENABLED") <= 0)
2437                         goto out;
2438                 goto fclose;
2439         }
2440
2441         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2442                 goto out;
2443         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2444                                  obd->obd_recovery_start) <= 0)
2445                 goto out;
2446         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2447                                  cfs_time_current_sec() >=
2448                                  obd->obd_recovery_start +
2449                                  obd->obd_recovery_timeout ? 0 :
2450                                  obd->obd_recovery_start +
2451                                  obd->obd_recovery_timeout -
2452                                  cfs_time_current_sec()) <= 0)
2453                 goto out;
2454         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2455                                  cfs_atomic_read(&obd->obd_connected_clients),
2456                                  obd->obd_max_recoverable_clients) <= 0)
2457                 goto out;
2458         /* Number of clients that have completed recovery */
2459         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2460                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2461                 <= 0)
2462                 goto out;
2463         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2464                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2465                 <=0)
2466                 goto out;
2467         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2468                                  cfs_atomic_read(&obd->obd_connected_clients) -
2469                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2470                 <=0)
2471                 goto out;
2472         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2473                                  obd->obd_stale_clients) <= 0)
2474                 goto out;
2475         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2476                                  obd->obd_replayed_requests) <= 0)
2477                 goto out;
2478         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2479                                  obd->obd_requests_queued_for_recovery) <= 0)
2480                 goto out;
2481
2482         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2483                                  obd->obd_next_recovery_transno) <= 0)
2484                 goto out;
2485
2486 fclose:
2487         *eof = 1;
2488 out:
2489         return min(count, len - (int)off);
2490 }
2491 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2492
2493 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2494                              int count, int *eof, void *data)
2495 {
2496         struct obd_device *obd = (struct obd_device *)data;
2497         LASSERT(obd != NULL);
2498
2499         return snprintf(page, count, "%d\n",
2500                         obd->obd_recovery_ir_factor);
2501 }
2502 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2503
2504 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2505                              unsigned long count, void *data)
2506 {
2507         struct obd_device *obd = (struct obd_device *)data;
2508         int val, rc;
2509         LASSERT(obd != NULL);
2510
2511         rc = lprocfs_write_helper(buffer, count, &val);
2512         if (rc)
2513                 return rc;
2514
2515         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2516                 return -EINVAL;
2517
2518         obd->obd_recovery_ir_factor = val;
2519         return count;
2520 }
2521 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2522
2523 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2524                                       int count, int *eof, void *data)
2525 {
2526         struct obd_device *obd = (struct obd_device *)data;
2527         LASSERT(obd != NULL);
2528
2529         return snprintf(page, count, "%d\n",
2530                         obd->obd_recovery_timeout);
2531 }
2532 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2533
2534 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2535                                       unsigned long count, void *data)
2536 {
2537         struct obd_device *obd = (struct obd_device *)data;
2538         int val, rc;
2539         LASSERT(obd != NULL);
2540
2541         rc = lprocfs_write_helper(buffer, count, &val);
2542         if (rc)
2543                 return rc;
2544
2545         obd->obd_recovery_timeout = val;
2546         return count;
2547 }
2548 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2549
2550 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2551                                       int count, int *eof, void *data)
2552 {
2553         struct obd_device *obd = data;
2554         LASSERT(obd != NULL);
2555
2556         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2557 }
2558 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2559
2560 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2561                                       unsigned long count, void *data)
2562 {
2563         struct obd_device *obd = data;
2564         int val, rc;
2565         LASSERT(obd != NULL);
2566
2567         rc = lprocfs_write_helper(buffer, count, &val);
2568         if (rc)
2569                 return rc;
2570
2571         obd->obd_recovery_time_hard = val;
2572         return count;
2573 }
2574 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2575
2576 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2577                                      int count, int *eof, void *data)
2578 {
2579         struct obd_device *dev = data;
2580         struct client_obd *cli = &dev->u.cli;
2581         int rc;
2582
2583         client_obd_list_lock(&cli->cl_loi_list_lock);
2584         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2585         client_obd_list_unlock(&cli->cl_loi_list_lock);
2586         return rc;
2587 }
2588 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2589
2590 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2591                                int count, int *eof, void *data)
2592 {
2593         struct obd_device *obd = (struct obd_device *)data;
2594         struct obd_device_target *target = &obd->u.obt;
2595
2596         LASSERT(obd != NULL);
2597         LASSERT(target->obt_magic == OBT_MAGIC);
2598         *eof = 1;
2599         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2600 }
2601 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2602 #endif /* LPROCFS*/