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