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