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