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