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