Whamcloud - gitweb
885287c4b77fc33bf1777fac7c8fcfe139dde801
[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         wake_up(&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                 do_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         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
1624 }
1625 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1626
1627 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1628 {
1629         struct lprocfs_stats *stats;
1630         unsigned int num_stats;
1631         int rc, i;
1632
1633         LASSERT(obd->obd_stats == NULL);
1634         LASSERT(obd->obd_proc_entry != NULL);
1635         LASSERT(obd->obd_cntr_base == 0);
1636
1637         num_stats = NUM_OBD_STATS + num_private_stats;
1638         stats = lprocfs_alloc_stats(num_stats, 0);
1639         if (stats == NULL)
1640                 return -ENOMEM;
1641
1642         lprocfs_init_ops_stats(num_private_stats, stats);
1643
1644         for (i = num_private_stats; i < num_stats; i++) {
1645                 /* If this LBUGs, it is likely that an obd
1646                  * operation was added to struct obd_ops in
1647                  * <obd.h>, and that the corresponding line item
1648                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1649                  * is missing from the list above. */
1650                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
1651                          "Missing obd_stat initializer obd_op "
1652                          "operation at offset %d.\n", i - num_private_stats);
1653         }
1654         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1655         if (rc < 0) {
1656                 lprocfs_free_stats(&stats);
1657         } else {
1658                 obd->obd_stats  = stats;
1659                 obd->obd_cntr_base = num_private_stats;
1660         }
1661         return rc;
1662 }
1663 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1664
1665 void lprocfs_free_obd_stats(struct obd_device *obd)
1666 {
1667         if (obd->obd_stats)
1668                 lprocfs_free_stats(&obd->obd_stats);
1669 }
1670 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1671
1672 /* Note that we only init md counters for ops whose offset is less
1673  * than NUM_MD_STATS. This is explained in a comment in the definition
1674  * of struct md_ops. */
1675 #define LPROCFS_MD_OP_INIT(base, stats, op)                                    \
1676         do {                                                                   \
1677                 unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
1678                                                                                \
1679                 if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
1680                         LASSERT(_idx < stats->ls_num);                         \
1681                         lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
1682                 }                                                              \
1683         } while (0)
1684
1685 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1686 {
1687         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1688         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1689         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1690         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1691         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1692         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1693         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1694         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1695         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1696         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1697         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1698         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1699         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1700         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1701         LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
1702         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1703         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1704         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1705         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1706         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1707         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1708         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1709         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1710         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1711         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1712         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1713         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1714         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1715         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1716         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1717         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1718         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1719 }
1720 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1721
1722 int lprocfs_alloc_md_stats(struct obd_device *obd,
1723                            unsigned int num_private_stats)
1724 {
1725         struct lprocfs_stats *stats;
1726         unsigned int num_stats;
1727         int rc, i;
1728
1729         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
1730         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
1731         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
1732
1733         /* TODO Ensure that this function is only used where
1734          * appropriate by adding an assertion to the effect that
1735          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
1736          * because mdt_procfs_init() uses this function to allocate
1737          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
1738          * mdt layer does not use the md_ops interface. This is
1739          * confusing and a waste of memory. See LU-2484.
1740          */
1741         LASSERT(obd->obd_proc_entry != NULL);
1742         LASSERT(obd->obd_md_stats == NULL);
1743         LASSERT(obd->obd_md_cntr_base == 0);
1744
1745         num_stats = NUM_MD_STATS + num_private_stats;
1746         stats = lprocfs_alloc_stats(num_stats, 0);
1747         if (stats == NULL)
1748                 return -ENOMEM;
1749
1750         lprocfs_init_mps_stats(num_private_stats, stats);
1751
1752         for (i = num_private_stats; i < num_stats; i++) {
1753                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1754                         CERROR("Missing md_stat initializer md_op "
1755                                "operation at offset %d. Aborting.\n",
1756                                i - num_private_stats);
1757                         LBUG();
1758                 }
1759         }
1760
1761         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1762         if (rc < 0) {
1763                 lprocfs_free_stats(&stats);
1764         } else {
1765                 obd->obd_md_stats = stats;
1766                 obd->obd_md_cntr_base = num_private_stats;
1767         }
1768
1769         return rc;
1770 }
1771 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1772
1773 void lprocfs_free_md_stats(struct obd_device *obd)
1774 {
1775         struct lprocfs_stats *stats = obd->obd_md_stats;
1776
1777         if (stats != NULL) {
1778                 obd->obd_md_stats = NULL;
1779                 obd->obd_md_cntr_base = 0;
1780                 lprocfs_free_stats(&stats);
1781         }
1782 }
1783 EXPORT_SYMBOL(lprocfs_free_md_stats);
1784
1785 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1786 {
1787         lprocfs_counter_init(ldlm_stats,
1788                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1789                              0, "ldlm_enqueue", "reqs");
1790         lprocfs_counter_init(ldlm_stats,
1791                              LDLM_CONVERT - LDLM_FIRST_OPC,
1792                              0, "ldlm_convert", "reqs");
1793         lprocfs_counter_init(ldlm_stats,
1794                              LDLM_CANCEL - LDLM_FIRST_OPC,
1795                              0, "ldlm_cancel", "reqs");
1796         lprocfs_counter_init(ldlm_stats,
1797                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1798                              0, "ldlm_bl_callback", "reqs");
1799         lprocfs_counter_init(ldlm_stats,
1800                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1801                              0, "ldlm_cp_callback", "reqs");
1802         lprocfs_counter_init(ldlm_stats,
1803                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1804                              0, "ldlm_gl_callback", "reqs");
1805 }
1806 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1807
1808 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1809                          int *eof,  void *data)
1810 {
1811         struct obd_export *exp = data;
1812         LASSERT(exp != NULL);
1813         *eof = 1;
1814         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1815 }
1816
1817 struct exp_uuid_cb_data {
1818         char                   *page;
1819         int                     count;
1820         int                    *eof;
1821         int                    *len;
1822 };
1823
1824 static void
1825 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1826                             int count, int *eof, int *len)
1827 {
1828         cb_data->page = page;
1829         cb_data->count = count;
1830         cb_data->eof = eof;
1831         cb_data->len = len;
1832 }
1833
1834 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1835                            cfs_hlist_node_t *hnode, void *cb_data)
1836
1837 {
1838         struct obd_export *exp = cfs_hash_object(hs, hnode);
1839         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1840
1841         if (exp->exp_nid_stats)
1842                 *data->len += snprintf((data->page + *data->len),
1843                                        data->count, "%s\n",
1844                                        obd_uuid2str(&exp->exp_client_uuid));
1845         return 0;
1846 }
1847
1848 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1849                         int *eof,  void *data)
1850 {
1851         struct nid_stat *stats = (struct nid_stat *)data;
1852         struct exp_uuid_cb_data cb_data;
1853         struct obd_device *obd = stats->nid_obd;
1854         int len = 0;
1855
1856         *eof = 1;
1857         page[0] = '\0';
1858         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1859         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1860                               lprocfs_exp_print_uuid, &cb_data);
1861         return (*cb_data.len);
1862 }
1863
1864 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1865                            cfs_hlist_node_t *hnode, void *cb_data)
1866
1867 {
1868         struct exp_uuid_cb_data *data = cb_data;
1869         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1870
1871         if (exp->exp_lock_hash != NULL) {
1872                 if (!*data->len) {
1873                         *data->len += cfs_hash_debug_header(data->page,
1874                                                             data->count);
1875                 }
1876                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1877                                                  data->count);
1878         }
1879
1880         return 0;
1881 }
1882
1883 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1884                         int *eof,  void *data)
1885 {
1886         struct nid_stat *stats = (struct nid_stat *)data;
1887         struct exp_uuid_cb_data cb_data;
1888         struct obd_device *obd = stats->nid_obd;
1889         int len = 0;
1890
1891         *eof = 1;
1892         page[0] = '\0';
1893         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1894
1895         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1896                               lprocfs_exp_print_hash, &cb_data);
1897         return (*cb_data.len);
1898 }
1899
1900 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1901                                         int count, int *eof,  void *data)
1902 {
1903         *eof = 1;
1904         return snprintf(page, count, "%s\n",
1905                         "Write into this file to clear all nid stats and "
1906                         "stale nid entries");
1907 }
1908 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1909
1910 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1911 {
1912         struct nid_stat *stat = obj;
1913         ENTRY;
1914
1915         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1916         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1917                 /* object has only hash references. */
1918                 spin_lock(&stat->nid_obd->obd_nid_lock);
1919                 cfs_list_move(&stat->nid_list, data);
1920                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1921                 RETURN(1);
1922         }
1923         /* we has reference to object - only clear data*/
1924         if (stat->nid_stats)
1925                 lprocfs_clear_stats(stat->nid_stats);
1926
1927         RETURN(0);
1928 }
1929
1930 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1931                                   unsigned long count, void *data)
1932 {
1933         struct obd_device *obd = (struct obd_device *)data;
1934         struct nid_stat *client_stat;
1935         CFS_LIST_HEAD(free_list);
1936
1937         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1938                           lprocfs_nid_stats_clear_write_cb, &free_list);
1939
1940         while (!cfs_list_empty(&free_list)) {
1941                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1942                                              nid_list);
1943                 cfs_list_del_init(&client_stat->nid_list);
1944                 lprocfs_free_client_stats(client_stat);
1945         }
1946
1947         return count;
1948 }
1949 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1950
1951 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1952 {
1953         struct nid_stat *new_stat, *old_stat;
1954         struct obd_device *obd = NULL;
1955         cfs_proc_dir_entry_t *entry;
1956         char *buffer = NULL;
1957         int rc = 0;
1958         ENTRY;
1959
1960         *newnid = 0;
1961
1962         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1963             !exp->exp_obd->obd_nid_stats_hash)
1964                 RETURN(-EINVAL);
1965
1966         /* not test against zero because eric say:
1967          * You may only test nid against another nid, or LNET_NID_ANY.
1968          * Anything else is nonsense.*/
1969         if (!nid || *nid == LNET_NID_ANY)
1970                 RETURN(0);
1971
1972         spin_lock(&exp->exp_lock);
1973         if (exp->exp_nid_stats != NULL) {
1974                 spin_unlock(&exp->exp_lock);
1975                 RETURN(-EALREADY);
1976         }
1977         spin_unlock(&exp->exp_lock);
1978
1979         obd = exp->exp_obd;
1980
1981         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1982
1983         OBD_ALLOC_PTR(new_stat);
1984         if (new_stat == NULL)
1985                 RETURN(-ENOMEM);
1986
1987         new_stat->nid               = *nid;
1988         new_stat->nid_obd           = exp->exp_obd;
1989         /* we need set default refcount to 1 to balance obd_disconnect */
1990         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1991
1992         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1993                                            nid, &new_stat->nid_hash);
1994         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1995                old_stat, libcfs_nid2str(*nid),
1996                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1997
1998         /* Return -EALREADY here so that we know that the /proc
1999          * entry already has been created */
2000         if (old_stat != new_stat) {
2001                 nidstat_putref(old_stat);
2002                 GOTO(destroy_new, rc = -EALREADY);
2003         }
2004         /* not found - create */
2005         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2006         if (buffer == NULL)
2007                 GOTO(destroy_new, rc = -ENOMEM);
2008
2009         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2010         new_stat->nid_proc = lprocfs_register(buffer,
2011                                               obd->obd_proc_exports_entry,
2012                                               NULL, NULL);
2013         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2014
2015         if (IS_ERR(new_stat->nid_proc)) {
2016                 rc = PTR_ERR(new_stat->nid_proc);
2017                 new_stat->nid_proc = NULL;
2018                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
2019                        obd->obd_name, libcfs_nid2str(*nid), rc);
2020                 GOTO(destroy_new_ns, rc);
2021         }
2022
2023         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2024                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2025         if (IS_ERR(entry)) {
2026                 CWARN("Error adding the NID stats file\n");
2027                 rc = PTR_ERR(entry);
2028                 GOTO(destroy_new_ns, rc);
2029         }
2030
2031         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2032                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2033         if (IS_ERR(entry)) {
2034                 CWARN("Error adding the hash file\n");
2035                 rc = PTR_ERR(entry);
2036                 GOTO(destroy_new_ns, rc);
2037         }
2038
2039         spin_lock(&exp->exp_lock);
2040         exp->exp_nid_stats = new_stat;
2041         spin_unlock(&exp->exp_lock);
2042         *newnid = 1;
2043         /* protect competitive add to list, not need locking on destroy */
2044         spin_lock(&obd->obd_nid_lock);
2045         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2046         spin_unlock(&obd->obd_nid_lock);
2047
2048         RETURN(rc);
2049
2050 destroy_new_ns:
2051         if (new_stat->nid_proc != NULL)
2052                 lprocfs_remove(&new_stat->nid_proc);
2053         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2054
2055 destroy_new:
2056         nidstat_putref(new_stat);
2057         OBD_FREE_PTR(new_stat);
2058         RETURN(rc);
2059 }
2060 EXPORT_SYMBOL(lprocfs_exp_setup);
2061
2062 int lprocfs_exp_cleanup(struct obd_export *exp)
2063 {
2064         struct nid_stat *stat = exp->exp_nid_stats;
2065
2066         if(!stat || !exp->exp_obd)
2067                 RETURN(0);
2068
2069         nidstat_putref(exp->exp_nid_stats);
2070         exp->exp_nid_stats = NULL;
2071
2072         return 0;
2073 }
2074 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2075
2076 int lprocfs_write_helper(const char *buffer, unsigned long count,
2077                          int *val)
2078 {
2079         return lprocfs_write_frac_helper(buffer, count, val, 1);
2080 }
2081 EXPORT_SYMBOL(lprocfs_write_helper);
2082
2083 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2084                               int *val, int mult)
2085 {
2086         char kernbuf[20], *end, *pbuf;
2087
2088         if (count > (sizeof(kernbuf) - 1))
2089                 return -EINVAL;
2090
2091         if (copy_from_user(kernbuf, buffer, count))
2092                 return -EFAULT;
2093
2094         kernbuf[count] = '\0';
2095         pbuf = kernbuf;
2096         if (*pbuf == '-') {
2097                 mult = -mult;
2098                 pbuf++;
2099         }
2100
2101         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2102         if (pbuf == end)
2103                 return -EINVAL;
2104
2105         if (end != NULL && *end == '.') {
2106                 int temp_val, pow = 1;
2107                 int i;
2108
2109                 pbuf = end + 1;
2110                 if (strlen(pbuf) > 5)
2111                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2112
2113                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2114
2115                 if (pbuf < end) {
2116                         for (i = 0; i < (end - pbuf); i++)
2117                                 pow *= 10;
2118
2119                         *val += temp_val / pow;
2120                 }
2121         }
2122         return 0;
2123 }
2124 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2125
2126 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2127                              int mult)
2128 {
2129         long decimal_val, frac_val;
2130         int prtn;
2131
2132         if (count < 10)
2133                 return -EINVAL;
2134
2135         decimal_val = val / mult;
2136         prtn = snprintf(buffer, count, "%ld", decimal_val);
2137         frac_val = val % mult;
2138
2139         if (prtn < (count - 4) && frac_val > 0) {
2140                 long temp_frac;
2141                 int i, temp_mult = 1, frac_bits = 0;
2142
2143                 temp_frac = frac_val * 10;
2144                 buffer[prtn++] = '.';
2145                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2146                         /* only reserved 2 bits fraction */
2147                         buffer[prtn++] ='0';
2148                         temp_frac *= 10;
2149                         frac_bits++;
2150                 }
2151                 /*
2152                  * Need to think these cases :
2153                  *      1. #echo x.00 > /proc/xxx       output result : x
2154                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2155                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2156                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2157                  *      Only reserved 2 bits fraction.
2158                  */
2159                 for (i = 0; i < (5 - prtn); i++)
2160                         temp_mult *= 10;
2161
2162                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2163                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2164                                  frac_val * temp_mult / mult);
2165
2166                 prtn--;
2167                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2168                         prtn--;
2169                         if (buffer[prtn] == '.') {
2170                                 prtn--;
2171                                 break;
2172                         }
2173                 }
2174                 prtn++;
2175         }
2176         buffer[prtn++] ='\n';
2177         return prtn;
2178 }
2179 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2180
2181 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2182 {
2183         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2184 }
2185 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2186
2187 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2188                               __u64 *val, int mult)
2189 {
2190         char kernbuf[22], *end, *pbuf;
2191         __u64 whole, frac = 0, units;
2192         unsigned frac_d = 1;
2193
2194         if (count > (sizeof(kernbuf) - 1))
2195                 return -EINVAL;
2196
2197         if (copy_from_user(kernbuf, buffer, count))
2198                 return -EFAULT;
2199
2200         kernbuf[count] = '\0';
2201         pbuf = kernbuf;
2202         if (*pbuf == '-') {
2203                 mult = -mult;
2204                 pbuf++;
2205         }
2206
2207         whole = simple_strtoull(pbuf, &end, 10);
2208         if (pbuf == end)
2209                 return -EINVAL;
2210
2211         if (end != NULL && *end == '.') {
2212                 int i;
2213                 pbuf = end + 1;
2214
2215                 /* need to limit frac_d to a __u32 */
2216                 if (strlen(pbuf) > 10)
2217                         pbuf[10] = '\0';
2218
2219                 frac = simple_strtoull(pbuf, &end, 10);
2220                 /* count decimal places */
2221                 for (i = 0; i < (end - pbuf); i++)
2222                         frac_d *= 10;
2223         }
2224
2225         units = 1;
2226         if (end != NULL) {
2227                 switch (*end) {
2228                 case 'p': case 'P':
2229                         units <<= 10;
2230                 case 't': case 'T':
2231                         units <<= 10;
2232                 case 'g': case 'G':
2233                         units <<= 10;
2234                 case 'm': case 'M':
2235                         units <<= 10;
2236                 case 'k': case 'K':
2237                         units <<= 10;
2238                 }
2239         }
2240         /* Specified units override the multiplier */
2241         if (units)
2242                 mult = mult < 0 ? -units : units;
2243
2244         frac *= mult;
2245         do_div(frac, frac_d);
2246         *val = whole * mult + frac;
2247         return 0;
2248 }
2249 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2250
2251 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2252 {
2253         size_t l2;
2254
2255         l2 = strlen(s2);
2256         if (!l2)
2257                 return (char *)s1;
2258         while (len >= l2) {
2259                 len--;
2260                 if (!memcmp(s1, s2, l2))
2261                         return (char *)s1;
2262                 s1++;
2263         }
2264         return NULL;
2265 }
2266
2267 /**
2268  * Find the string \a name in the input \a buffer, and return a pointer to the
2269  * value immediately following \a name, reducing \a count appropriately.
2270  * If \a name is not found the original \a buffer is returned.
2271  */
2272 char *lprocfs_find_named_value(const char *buffer, const char *name,
2273                                 unsigned long *count)
2274 {
2275         char *val;
2276         size_t buflen = *count;
2277
2278         /* there is no strnstr() in rhel5 and ubuntu kernels */
2279         val = lprocfs_strnstr(buffer, name, buflen);
2280         if (val == NULL)
2281                 return (char *)buffer;
2282
2283         val += strlen(name);                             /* skip prefix */
2284         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2285                 val++;
2286
2287         *count = 0;
2288         while (val < buffer + buflen && isalnum(*val)) {
2289                 ++*count;
2290                 ++val;
2291         }
2292
2293         return val - *count;
2294 }
2295 EXPORT_SYMBOL(lprocfs_find_named_value);
2296
2297 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2298                        const char *name,
2299                        mode_t mode,
2300                        const struct file_operations *seq_fops,
2301                        void *data)
2302 {
2303         struct proc_dir_entry *entry;
2304         ENTRY;
2305
2306         /* Disallow secretly (un)writable entries. */
2307         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2308
2309         LPROCFS_WRITE_ENTRY();
2310         entry = create_proc_entry(name, mode, parent);
2311         if (entry) {
2312                 entry->proc_fops = seq_fops;
2313                 entry->data = data;
2314         }
2315         LPROCFS_WRITE_EXIT();
2316
2317         if (entry == NULL)
2318                 RETURN(-ENOMEM);
2319
2320         RETURN(0);
2321 }
2322 EXPORT_SYMBOL(lprocfs_seq_create);
2323
2324 int lprocfs_obd_seq_create(struct obd_device *dev,
2325                            const char *name,
2326                            mode_t mode,
2327                            const struct file_operations *seq_fops,
2328                            void *data)
2329 {
2330         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2331                                    mode, seq_fops, data));
2332 }
2333 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2334
2335 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2336 {
2337         if (value >= OBD_HIST_MAX)
2338                 value = OBD_HIST_MAX - 1;
2339
2340         spin_lock(&oh->oh_lock);
2341         oh->oh_buckets[value]++;
2342         spin_unlock(&oh->oh_lock);
2343 }
2344 EXPORT_SYMBOL(lprocfs_oh_tally);
2345
2346 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2347 {
2348         unsigned int val = 0;
2349
2350         if (likely(value != 0))
2351                 val = min(fls(value - 1), OBD_HIST_MAX);
2352
2353         lprocfs_oh_tally(oh, val);
2354 }
2355 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2356
2357 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2358 {
2359         unsigned long ret = 0;
2360         int i;
2361
2362         for (i = 0; i < OBD_HIST_MAX; i++)
2363                 ret +=  oh->oh_buckets[i];
2364         return ret;
2365 }
2366 EXPORT_SYMBOL(lprocfs_oh_sum);
2367
2368 void lprocfs_oh_clear(struct obd_histogram *oh)
2369 {
2370         spin_lock(&oh->oh_lock);
2371         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2372         spin_unlock(&oh->oh_lock);
2373 }
2374 EXPORT_SYMBOL(lprocfs_oh_clear);
2375
2376 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2377                         int count, int *eof, void *data)
2378 {
2379         struct obd_device *obd = data;
2380         int c = 0;
2381
2382         if (obd == NULL)
2383                 return 0;
2384
2385         c += cfs_hash_debug_header(page, count);
2386         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2387         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2388         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2389
2390         return c;
2391 }
2392 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2393
2394 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2395                                    int count, int *eof, void *data)
2396 {
2397         struct obd_device *obd = data;
2398         int len = 0, size;
2399
2400         LASSERT(obd != NULL);
2401         LASSERT(count >= 0);
2402
2403         /* Set start of user data returned to
2404            page + off since the user may have
2405            requested to read much smaller than
2406            what we need to read */
2407         *start = page + off;
2408
2409         /*
2410          * We know we are allocated a page here.
2411          * Also we know that this function will
2412          * not need to write more than a page
2413          * so we can truncate at PAGE_CACHE_SIZE.
2414          */
2415         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
2416
2417         /* Initialize the page */
2418         memset(page, 0, size);
2419
2420         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2421                 goto out;
2422         if (obd->obd_max_recoverable_clients == 0) {
2423                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2424                         goto out;
2425
2426                 goto fclose;
2427         }
2428
2429         /* sampled unlocked, but really... */
2430         if (obd->obd_recovering == 0) {
2431                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2432                         goto out;
2433                 if (lprocfs_obd_snprintf(&page, size, &len,
2434                                          "recovery_start: %lu\n",
2435                                          obd->obd_recovery_start) <= 0)
2436                         goto out;
2437                 if (lprocfs_obd_snprintf(&page, size, &len,
2438                                          "recovery_duration: %lu\n",
2439                                          obd->obd_recovery_end -
2440                                          obd->obd_recovery_start) <= 0)
2441                         goto out;
2442                 /* Number of clients that have completed recovery */
2443                 if (lprocfs_obd_snprintf(&page, size, &len,
2444                                          "completed_clients: %d/%d\n",
2445                                          obd->obd_max_recoverable_clients -
2446                                          obd->obd_stale_clients,
2447                                          obd->obd_max_recoverable_clients) <= 0)
2448                         goto out;
2449                 if (lprocfs_obd_snprintf(&page, size, &len,
2450                                          "replayed_requests: %d\n",
2451                                          obd->obd_replayed_requests) <= 0)
2452                         goto out;
2453                 if (lprocfs_obd_snprintf(&page, size, &len,
2454                                          "last_transno: "LPD64"\n",
2455                                          obd->obd_next_recovery_transno - 1)<=0)
2456                         goto out;
2457                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2458                                          obd->obd_version_recov ?
2459                                          "ENABLED" : "DISABLED") <=0)
2460                         goto out;
2461                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2462                                          obd->obd_no_ir ?
2463                                          "DISABLED" : "ENABLED") <= 0)
2464                         goto out;
2465                 goto fclose;
2466         }
2467
2468         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2469                 goto out;
2470         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2471                                  obd->obd_recovery_start) <= 0)
2472                 goto out;
2473         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2474                                  cfs_time_current_sec() >=
2475                                  obd->obd_recovery_start +
2476                                  obd->obd_recovery_timeout ? 0 :
2477                                  obd->obd_recovery_start +
2478                                  obd->obd_recovery_timeout -
2479                                  cfs_time_current_sec()) <= 0)
2480                 goto out;
2481         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2482                                  cfs_atomic_read(&obd->obd_connected_clients),
2483                                  obd->obd_max_recoverable_clients) <= 0)
2484                 goto out;
2485         /* Number of clients that have completed recovery */
2486         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2487                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2488                 <= 0)
2489                 goto out;
2490         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2491                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2492                 <=0)
2493                 goto out;
2494         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2495                                  cfs_atomic_read(&obd->obd_connected_clients) -
2496                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2497                 <=0)
2498                 goto out;
2499         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2500                                  obd->obd_stale_clients) <= 0)
2501                 goto out;
2502         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2503                                  obd->obd_replayed_requests) <= 0)
2504                 goto out;
2505         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2506                                  obd->obd_requests_queued_for_recovery) <= 0)
2507                 goto out;
2508
2509         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2510                                  obd->obd_next_recovery_transno) <= 0)
2511                 goto out;
2512
2513 fclose:
2514         *eof = 1;
2515 out:
2516         return min(count, len - (int)off);
2517 }
2518 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2519
2520 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2521                              int count, int *eof, void *data)
2522 {
2523         struct obd_device *obd = (struct obd_device *)data;
2524         LASSERT(obd != NULL);
2525
2526         return snprintf(page, count, "%d\n",
2527                         obd->obd_recovery_ir_factor);
2528 }
2529 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2530
2531 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2532                              unsigned long count, void *data)
2533 {
2534         struct obd_device *obd = (struct obd_device *)data;
2535         int val, rc;
2536         LASSERT(obd != NULL);
2537
2538         rc = lprocfs_write_helper(buffer, count, &val);
2539         if (rc)
2540                 return rc;
2541
2542         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2543                 return -EINVAL;
2544
2545         obd->obd_recovery_ir_factor = val;
2546         return count;
2547 }
2548 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2549
2550 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2551                                       int count, int *eof, void *data)
2552 {
2553         struct obd_device *obd = (struct obd_device *)data;
2554         LASSERT(obd != NULL);
2555
2556         return snprintf(page, count, "%d\n",
2557                         obd->obd_recovery_timeout);
2558 }
2559 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2560
2561 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2562                                       unsigned long count, void *data)
2563 {
2564         struct obd_device *obd = (struct obd_device *)data;
2565         int val, rc;
2566         LASSERT(obd != NULL);
2567
2568         rc = lprocfs_write_helper(buffer, count, &val);
2569         if (rc)
2570                 return rc;
2571
2572         obd->obd_recovery_timeout = val;
2573         return count;
2574 }
2575 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2576
2577 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2578                                       int count, int *eof, void *data)
2579 {
2580         struct obd_device *obd = data;
2581         LASSERT(obd != NULL);
2582
2583         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2584 }
2585 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2586
2587 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2588                                       unsigned long count, void *data)
2589 {
2590         struct obd_device *obd = data;
2591         int val, rc;
2592         LASSERT(obd != NULL);
2593
2594         rc = lprocfs_write_helper(buffer, count, &val);
2595         if (rc)
2596                 return rc;
2597
2598         obd->obd_recovery_time_hard = val;
2599         return count;
2600 }
2601 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2602
2603 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2604                                      int count, int *eof, void *data)
2605 {
2606         struct obd_device *dev = data;
2607         struct client_obd *cli = &dev->u.cli;
2608         int rc;
2609
2610         client_obd_list_lock(&cli->cl_loi_list_lock);
2611         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2612         client_obd_list_unlock(&cli->cl_loi_list_lock);
2613         return rc;
2614 }
2615 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2616
2617 #ifdef HAVE_SERVER_SUPPORT
2618 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2619                                int count, int *eof, void *data)
2620 {
2621         struct obd_device *obd = (struct obd_device *)data;
2622         struct obd_device_target *target = &obd->u.obt;
2623
2624         LASSERT(obd != NULL);
2625         LASSERT(target->obt_magic == OBT_MAGIC);
2626         *eof = 1;
2627         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2628 }
2629 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2630 #endif
2631 #endif /* LPROCFS*/