Whamcloud - gitweb
LU-946 lprocfs: List open files in filesystem
[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         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         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         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         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         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         "connect_from_mds",
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 static void obd_connect_data_seqprint(struct seq_file *m,
996                                       struct obd_connect_data *ocd)
997 {
998         int flags;
999
1000         LASSERT(ocd != NULL);
1001         flags = ocd->ocd_connect_flags;
1002
1003         seq_printf(m, "    connect_data:\n"
1004                       "       flags: "LPX64"\n"
1005                       "       instance: %u\n",
1006                       ocd->ocd_connect_flags,
1007                       ocd->ocd_instance);
1008         if (flags & OBD_CONNECT_VERSION)
1009                 seq_printf(m, "       target_version: %u.%u.%u.%u\n",
1010                               OBD_OCD_VERSION_MAJOR(ocd->ocd_version),
1011                               OBD_OCD_VERSION_MINOR(ocd->ocd_version),
1012                               OBD_OCD_VERSION_PATCH(ocd->ocd_version),
1013                               OBD_OCD_VERSION_FIX(ocd->ocd_version));
1014         if (flags & OBD_CONNECT_MDS)
1015                 seq_printf(m, "       mdt_index: %d\n", ocd->ocd_group);
1016         if (flags & OBD_CONNECT_GRANT)
1017                 seq_printf(m, "       initial_grant: %d\n", ocd->ocd_grant);
1018         if (flags & OBD_CONNECT_INDEX)
1019                 seq_printf(m, "       target_index: %u\n", ocd->ocd_index);
1020         if (flags & OBD_CONNECT_BRW_SIZE)
1021                 seq_printf(m, "       max_brw_size: %d\n", ocd->ocd_brw_size);
1022         if (flags & OBD_CONNECT_IBITS)
1023                 seq_printf(m, "       ibits_known: "LPX64"\n",
1024                                 ocd->ocd_ibits_known);
1025         if (flags & OBD_CONNECT_GRANT_PARAM)
1026                 seq_printf(m, "       grant_block_size: %d\n"
1027                               "       grant_inode_size: %d\n"
1028                               "       grant_extent_overhead: %d\n",
1029                               ocd->ocd_blocksize,
1030                               ocd->ocd_inodespace,
1031                               ocd->ocd_grant_extent);
1032         if (flags & OBD_CONNECT_TRANSNO)
1033                 seq_printf(m, "       first_transno: "LPX64"\n",
1034                                 ocd->ocd_transno);
1035         if (flags & OBD_CONNECT_CKSUM)
1036                 seq_printf(m, "       cksum_types: %#x\n",
1037                               ocd->ocd_cksum_types);
1038         if (flags & OBD_CONNECT_MAX_EASIZE)
1039                 seq_printf(m, "       max_easize: %d\n", ocd->ocd_max_easize);
1040         if (flags & OBD_CONNECT_MAXBYTES)
1041                 seq_printf(m, "       max_object_bytes: "LPU64"\n",
1042                               ocd->ocd_maxbytes);
1043 }
1044
1045 int lprocfs_import_seq_show(struct seq_file *m, void *data)
1046 {
1047         struct lprocfs_counter          ret;
1048         struct lprocfs_counter_header   *header;
1049         struct obd_device               *obd    = (struct obd_device *)data;
1050         struct obd_import               *imp;
1051         struct obd_import_conn          *conn;
1052         struct obd_connect_data         *ocd;
1053         int                             j;
1054         int                             k;
1055         int                             rw      = 0;
1056
1057         LASSERT(obd != NULL);
1058         LPROCFS_CLIMP_CHECK(obd);
1059         imp = obd->u.cli.cl_import;
1060         ocd = &imp->imp_connect_data;
1061
1062         seq_printf(m, "import:\n"
1063                       "    name: %s\n"
1064                       "    target: %s\n"
1065                       "    state: %s\n"
1066                       "    connect_flags: [",
1067                       obd->obd_name,
1068                       obd2cli_tgt(obd),
1069                       ptlrpc_import_state_name(imp->imp_state));
1070         obd_connect_seq_flags2str(m, imp->imp_connect_data.ocd_connect_flags,
1071                                         ", ");
1072         seq_printf(m, "]\n");
1073         obd_connect_data_seqprint(m, ocd);
1074         seq_printf(m, "    import_flags: [");
1075         obd_import_flags2seqstr(imp, m);
1076
1077         seq_printf(m, "]\n"
1078                       "    connection:\n"
1079                       "       failover_nids: [");
1080         spin_lock(&imp->imp_lock);
1081         j = 0;
1082         list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1083                 seq_printf(m, "%s%s", j ? ", " : "",
1084                            libcfs_nid2str(conn->oic_conn->c_peer.nid));
1085                 j++;
1086         }
1087         seq_printf(m, "]\n"
1088                       "       current_connection: %s\n"
1089                       "       connection_attempts: %u\n"
1090                       "       generation: %u\n"
1091                       "       in-progress_invalidations: %u\n",
1092                       imp->imp_connection == NULL ? "<none>" :
1093                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1094                       imp->imp_conn_cnt,
1095                       imp->imp_generation,
1096                       atomic_read(&imp->imp_inval_count));
1097         spin_unlock(&imp->imp_lock);
1098
1099         if (obd->obd_svc_stats == NULL)
1100                 goto out_climp;
1101
1102         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
1103         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1104         if (ret.lc_count != 0) {
1105                 /* first argument to do_div MUST be __u64 */
1106                 __u64 sum = ret.lc_sum;
1107                 do_div(sum, ret.lc_count);
1108                 ret.lc_sum = sum;
1109         } else
1110                 ret.lc_sum = 0;
1111         seq_printf(m, "    rpcs:\n"
1112                       "       inflight: %u\n"
1113                       "       unregistering: %u\n"
1114                       "       timeouts: %u\n"
1115                       "       avg_waittime: "LPU64" %s\n",
1116                       atomic_read(&imp->imp_inflight),
1117                       atomic_read(&imp->imp_unregistering),
1118                       atomic_read(&imp->imp_timeouts),
1119                       ret.lc_sum, header->lc_units);
1120
1121         k = 0;
1122         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1123                 if (imp->imp_at.iat_portal[j] == 0)
1124                         break;
1125                 k = max_t(unsigned int, k,
1126                           at_get(&imp->imp_at.iat_service_estimate[j]));
1127         }
1128         seq_printf(m, "    service_estimates:\n"
1129                       "       services: %u sec\n"
1130                       "       network: %u sec\n",
1131                       k,
1132                       at_get(&imp->imp_at.iat_net_latency));
1133
1134         seq_printf(m, "    transactions:\n"
1135                       "       last_replay: "LPU64"\n"
1136                       "       peer_committed: "LPU64"\n"
1137                       "       last_checked: "LPU64"\n",
1138                       imp->imp_last_replay_transno,
1139                       imp->imp_peer_committed_transno,
1140                       imp->imp_last_transno_checked);
1141
1142         /* avg data rates */
1143         for (rw = 0; rw <= 1; rw++) {
1144                 lprocfs_stats_collect(obd->obd_svc_stats,
1145                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1146                                       &ret);
1147                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1148                         /* first argument to do_div MUST be __u64 */
1149                         __u64 sum = ret.lc_sum;
1150                         do_div(sum, ret.lc_count);
1151                         ret.lc_sum = sum;
1152                         seq_printf(m, "    %s_data_averages:\n"
1153                                       "       bytes_per_rpc: "LPU64"\n",
1154                                       rw ? "write" : "read",
1155                                       ret.lc_sum);
1156                 }
1157                 k = (int)ret.lc_sum;
1158                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1159                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1160                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1161                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1162                         /* first argument to do_div MUST be __u64 */
1163                         __u64 sum = ret.lc_sum;
1164                         do_div(sum, ret.lc_count);
1165                         ret.lc_sum = sum;
1166                         seq_printf(m, "       %s_per_rpc: "LPU64"\n",
1167                                         header->lc_units, ret.lc_sum);
1168                         j = (int)ret.lc_sum;
1169                         if (j > 0)
1170                                 seq_printf(m, "       MB_per_sec: %u.%.02u\n",
1171                                                 k / j, (100 * k / j) % 100);
1172                 }
1173         }
1174
1175 out_climp:
1176         LPROCFS_CLIMP_EXIT(obd);
1177         return 0;
1178 }
1179 EXPORT_SYMBOL(lprocfs_import_seq_show);
1180
1181 int lprocfs_state_seq_show(struct seq_file *m, void *data)
1182 {
1183         struct obd_device *obd = (struct obd_device *)data;
1184         struct obd_import *imp;
1185         int j, k;
1186
1187         LASSERT(obd != NULL);
1188         LPROCFS_CLIMP_CHECK(obd);
1189         imp = obd->u.cli.cl_import;
1190
1191         seq_printf(m, "current_state: %s\n",
1192                    ptlrpc_import_state_name(imp->imp_state));
1193         seq_printf(m, "state_history:\n");
1194         k = imp->imp_state_hist_idx;
1195         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1196                 struct import_state_hist *ish =
1197                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1198                 if (ish->ish_state == 0)
1199                         continue;
1200                 seq_printf(m, " - ["CFS_TIME_T", %s]\n",
1201                            ish->ish_time,
1202                 ptlrpc_import_state_name(ish->ish_state));
1203         }
1204
1205         LPROCFS_CLIMP_EXIT(obd);
1206         return 0;
1207 }
1208 EXPORT_SYMBOL(lprocfs_state_seq_show);
1209
1210 int lprocfs_seq_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at)
1211 {
1212         int i;
1213         for (i = 0; i < AT_BINS; i++)
1214                 seq_printf(m, "%3u ", at->at_hist[i]);
1215         seq_printf(m, "\n");
1216         return 0;
1217 }
1218 EXPORT_SYMBOL(lprocfs_seq_at_hist_helper);
1219
1220 /* See also ptlrpc_lprocfs_timeouts_show_seq */
1221 int lprocfs_timeouts_seq_show(struct seq_file *m, void *data)
1222 {
1223         struct obd_device *obd = (struct obd_device *)data;
1224         struct obd_import *imp;
1225         unsigned int cur, worst;
1226         time_t now, worstt;
1227         struct dhms ts;
1228         int i;
1229
1230         LASSERT(obd != NULL);
1231         LPROCFS_CLIMP_CHECK(obd);
1232         imp = obd->u.cli.cl_import;
1233
1234         now = cfs_time_current_sec();
1235
1236         /* Some network health info for kicks */
1237         s2dhms(&ts, now - imp->imp_last_reply_time);
1238         seq_printf(m, "%-10s : %ld, "DHMS_FMT" ago\n",
1239                    "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1240
1241         cur = at_get(&imp->imp_at.iat_net_latency);
1242         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1243         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1244         s2dhms(&ts, now - worstt);
1245         seq_printf(m, "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1246                    "network", cur, worst, worstt, DHMS_VARS(&ts));
1247         lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_net_latency);
1248
1249         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1250                 if (imp->imp_at.iat_portal[i] == 0)
1251                         break;
1252                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1253                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1254                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1255                 s2dhms(&ts, now - worstt);
1256                 seq_printf(m, "portal %-2d  : cur %3u  worst %3u (at %ld, "
1257                            DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1258                            cur, worst, worstt, DHMS_VARS(&ts));
1259                 lprocfs_seq_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]);
1260         }
1261
1262         LPROCFS_CLIMP_EXIT(obd);
1263         return 0;
1264 }
1265 EXPORT_SYMBOL(lprocfs_timeouts_seq_show);
1266
1267 int lprocfs_connect_flags_seq_show(struct seq_file *m, void *data)
1268 {
1269         struct obd_device *obd = data;
1270         __u64 flags;
1271
1272         LPROCFS_CLIMP_CHECK(obd);
1273         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1274         seq_printf(m, "flags="LPX64"\n", flags);
1275         obd_connect_seq_flags2str(m, flags, "\n");
1276         seq_printf(m, "\n");
1277         LPROCFS_CLIMP_EXIT(obd);
1278         return 0;
1279 }
1280 EXPORT_SYMBOL(lprocfs_connect_flags_seq_show);
1281
1282 #ifndef HAVE_ONLY_PROCFS_SEQ
1283
1284 int lprocfs_rd_uint(char *page, char **start, off_t off,
1285                     int count, int *eof, void *data)
1286 {
1287         unsigned int *temp = data;
1288         return snprintf(page, count, "%u\n", *temp);
1289 }
1290 EXPORT_SYMBOL(lprocfs_rd_uint);
1291
1292 int lprocfs_rd_u64(char *page, char **start, off_t off,
1293                    int count, int *eof, void *data)
1294 {
1295         LASSERT(data != NULL);
1296         *eof = 1;
1297         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
1298 }
1299 EXPORT_SYMBOL(lprocfs_rd_u64);
1300
1301 int lprocfs_rd_atomic(char *page, char **start, off_t off,
1302                    int count, int *eof, void *data)
1303 {
1304         atomic_t *atom = data;
1305         LASSERT(atom != NULL);
1306         *eof = 1;
1307         return snprintf(page, count, "%d\n", atomic_read(atom));
1308 }
1309 EXPORT_SYMBOL(lprocfs_rd_atomic);
1310
1311 int lprocfs_wr_atomic(struct file *file, const char *buffer,
1312                       unsigned long count, void *data)
1313 {
1314         atomic_t *atm = data;
1315         int val = 0;
1316         int rc;
1317
1318         rc = lprocfs_write_helper(buffer, count, &val);
1319         if (rc < 0)
1320                 return rc;
1321
1322         if (val <= 0)
1323                 return -ERANGE;
1324
1325         atomic_set(atm, val);
1326         return count;
1327 }
1328 EXPORT_SYMBOL(lprocfs_wr_atomic);
1329
1330 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
1331                     int *eof, void *data)
1332 {
1333         struct obd_device *obd = data;
1334
1335         LASSERT(obd != NULL);
1336         *eof = 1;
1337         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
1338 }
1339 EXPORT_SYMBOL(lprocfs_rd_uuid);
1340
1341 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
1342                     int *eof, void *data)
1343 {
1344         struct obd_device *dev = data;
1345
1346         LASSERT(dev != NULL);
1347         *eof = 1;
1348         return snprintf(page, count, "%s\n", dev->obd_name);
1349 }
1350 EXPORT_SYMBOL(lprocfs_rd_name);
1351
1352 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
1353                        int *eof, void *data)
1354 {
1355         struct obd_device *obd = data;
1356         struct obd_statfs  osfs;
1357         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1358                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1359                             OBD_STATFS_NODELAY);
1360         if (!rc) {
1361                 *eof = 1;
1362                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
1363         }
1364         return rc;
1365 }
1366 EXPORT_SYMBOL(lprocfs_rd_blksize);
1367
1368 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
1369                            int *eof, void *data)
1370 {
1371         struct obd_device *obd = data;
1372         struct obd_statfs  osfs;
1373         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1374                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1375                             OBD_STATFS_NODELAY);
1376         if (!rc) {
1377                 __u32 blk_size = osfs.os_bsize >> 10;
1378                 __u64 result = osfs.os_blocks;
1379
1380                 while (blk_size >>= 1)
1381                         result <<= 1;
1382
1383                 *eof = 1;
1384                 rc = snprintf(page, count, LPU64"\n", result);
1385         }
1386         return rc;
1387 }
1388 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1389
1390 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
1391                           int *eof, void *data)
1392 {
1393         struct obd_device *obd = data;
1394         struct obd_statfs  osfs;
1395         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1396                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1397                             OBD_STATFS_NODELAY);
1398         if (!rc) {
1399                 __u32 blk_size = osfs.os_bsize >> 10;
1400                 __u64 result = osfs.os_bfree;
1401
1402                 while (blk_size >>= 1)
1403                         result <<= 1;
1404
1405                 *eof = 1;
1406                 rc = snprintf(page, count, LPU64"\n", result);
1407         }
1408         return rc;
1409 }
1410 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1411
1412 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
1413                            int *eof, void *data)
1414 {
1415         struct obd_device *obd = data;
1416         struct obd_statfs  osfs;
1417         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1418                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1419                             OBD_STATFS_NODELAY);
1420         if (!rc) {
1421                 __u32 blk_size = osfs.os_bsize >> 10;
1422                 __u64 result = osfs.os_bavail;
1423
1424                 while (blk_size >>= 1)
1425                         result <<= 1;
1426
1427                 *eof = 1;
1428                 rc = snprintf(page, count, LPU64"\n", result);
1429         }
1430         return rc;
1431 }
1432 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1433
1434 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
1435                           int *eof, void *data)
1436 {
1437         struct obd_device *obd = data;
1438         struct obd_statfs  osfs;
1439         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1440                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1441                             OBD_STATFS_NODELAY);
1442         if (!rc) {
1443                 *eof = 1;
1444                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
1445         }
1446
1447         return rc;
1448 }
1449 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1450
1451 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
1452                          int *eof, void *data)
1453 {
1454         struct obd_device *obd = data;
1455         struct obd_statfs  osfs;
1456         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
1457                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
1458                             OBD_STATFS_NODELAY);
1459         if (!rc) {
1460                 *eof = 1;
1461                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
1462         }
1463         return rc;
1464 }
1465 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1466
1467 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
1468                            int *eof, void *data)
1469 {
1470         struct obd_device *obd = data;
1471         struct obd_import *imp;
1472         char *imp_state_name = NULL;
1473         int rc = 0;
1474
1475         LASSERT(obd != NULL);
1476         LPROCFS_CLIMP_CHECK(obd);
1477         imp = obd->u.cli.cl_import;
1478         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
1479         *eof = 1;
1480         rc = snprintf(page, count, "%s\t%s%s\n",
1481                       obd2cli_tgt(obd), imp_state_name,
1482                       imp->imp_deactive ? "\tDEACTIVATED" : "");
1483
1484         LPROCFS_CLIMP_EXIT(obd);
1485         return rc;
1486 }
1487 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1488
1489 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
1490                          int *eof,  void *data)
1491 {
1492         struct obd_device *obd = data;
1493         struct ptlrpc_connection *conn;
1494         int rc = 0;
1495
1496         LASSERT(obd != NULL);
1497
1498         LPROCFS_CLIMP_CHECK(obd);
1499         conn = obd->u.cli.cl_import->imp_connection;
1500         *eof = 1;
1501         if (conn && obd->u.cli.cl_import) {
1502                 rc = snprintf(page, count, "%s\n",
1503                               conn->c_remote_uuid.uuid);
1504         } else {
1505                 rc = snprintf(page, count, "%s\n", "<none>");
1506         }
1507
1508         LPROCFS_CLIMP_EXIT(obd);
1509         return rc;
1510 }
1511 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1512
1513 /**
1514  * Append a space separated list of current set flags to str.
1515  */
1516 #define flag2str(flag) \
1517         if (imp->imp_##flag && max - len > 0) \
1518              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
1519 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
1520 {
1521         int len = 0;
1522
1523         if (imp->imp_obd->obd_no_recov)
1524                 len += snprintf(str, max - len, "no_recov");
1525
1526         flag2str(invalid);
1527         flag2str(deactive);
1528         flag2str(replayable);
1529         flag2str(pingable);
1530         return len;
1531 }
1532 #undef flags2str
1533
1534 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
1535                       int *eof, void *data)
1536 {
1537         struct lprocfs_counter          ret;
1538         struct lprocfs_counter_header   *header;
1539         struct obd_device               *obd    = (struct obd_device *)data;
1540         struct obd_import               *imp;
1541         struct obd_import_conn          *conn;
1542         int                             i;
1543         int                             j;
1544         int                             k;
1545         int                             rw      = 0;
1546
1547         LASSERT(obd != NULL);
1548         LPROCFS_CLIMP_CHECK(obd);
1549         imp = obd->u.cli.cl_import;
1550         *eof = 1;
1551
1552         i = snprintf(page, count,
1553                      "import:\n"
1554                      "    name: %s\n"
1555                      "    target: %s\n"
1556                      "    state: %s\n"
1557                      "    instance: %u\n"
1558                      "    connect_flags: [",
1559                      obd->obd_name,
1560                      obd2cli_tgt(obd),
1561                      ptlrpc_import_state_name(imp->imp_state),
1562                      imp->imp_connect_data.ocd_instance);
1563         i += obd_connect_flags2str(page + i, count - i,
1564                                    imp->imp_connect_data.ocd_connect_flags,
1565                                    ", ");
1566         i += snprintf(page + i, count - i,
1567                       "]\n"
1568                       "    import_flags: [");
1569         i += obd_import_flags2str(imp, page + i, count - i);
1570
1571         i += snprintf(page + i, count - i,
1572                       "]\n"
1573                       "    connection:\n"
1574                       "       failover_nids: [");
1575         spin_lock(&imp->imp_lock);
1576         j = 0;
1577         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1578                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
1579                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
1580                 j++;
1581         }
1582         i += snprintf(page + i, count - i,
1583                       "]\n"
1584                       "       current_connection: %s\n"
1585                       "       connection_attempts: %u\n"
1586                       "       generation: %u\n"
1587                       "       in-progress_invalidations: %u\n",
1588                       imp->imp_connection == NULL ? "<none>" :
1589                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1590                       imp->imp_conn_cnt,
1591                       imp->imp_generation,
1592                       atomic_read(&imp->imp_inval_count));
1593         spin_unlock(&imp->imp_lock);
1594
1595         if (obd->obd_svc_stats == NULL)
1596                 goto out_climp;
1597
1598         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
1599         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1600         if (ret.lc_count != 0) {
1601                 /* first argument to do_div MUST be __u64 */
1602                 __u64 sum = ret.lc_sum;
1603                 do_div(sum, ret.lc_count);
1604                 ret.lc_sum = sum;
1605         } else
1606                 ret.lc_sum = 0;
1607         i += snprintf(page + i, count - i,
1608                       "    rpcs:\n"
1609                       "       inflight: %u\n"
1610                       "       unregistering: %u\n"
1611                       "       timeouts: %u\n"
1612                       "       avg_waittime: "LPU64" %s\n",
1613                       atomic_read(&imp->imp_inflight),
1614                       atomic_read(&imp->imp_unregistering),
1615                       atomic_read(&imp->imp_timeouts),
1616                       ret.lc_sum, header->lc_units);
1617
1618         k = 0;
1619         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1620                 if (imp->imp_at.iat_portal[j] == 0)
1621                         break;
1622                 k = max_t(unsigned int, k,
1623                           at_get(&imp->imp_at.iat_service_estimate[j]));
1624         }
1625         i += snprintf(page + i, count - i,
1626                       "    service_estimates:\n"
1627                       "       services: %u sec\n"
1628                       "       network: %u sec\n",
1629                       k,
1630                       at_get(&imp->imp_at.iat_net_latency));
1631
1632         i += snprintf(page + i, count - i,
1633                       "    transactions:\n"
1634                       "       last_replay: "LPU64"\n"
1635                       "       peer_committed: "LPU64"\n"
1636                       "       last_checked: "LPU64"\n",
1637                       imp->imp_last_replay_transno,
1638                       imp->imp_peer_committed_transno,
1639                       imp->imp_last_transno_checked);
1640
1641         /* avg data rates */
1642         for (rw = 0; rw <= 1; rw++) {
1643                 lprocfs_stats_collect(obd->obd_svc_stats,
1644                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1645                                       &ret);
1646                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1647                         /* first argument to do_div MUST be __u64 */
1648                         __u64 sum = ret.lc_sum;
1649                         do_div(sum, ret.lc_count);
1650                         ret.lc_sum = sum;
1651                         i += snprintf(page + i, count - i,
1652                                       "    %s_data_averages:\n"
1653                                       "       bytes_per_rpc: "LPU64"\n",
1654                                       rw ? "write" : "read",
1655                                       ret.lc_sum);
1656                 }
1657                 k = (int)ret.lc_sum;
1658                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1659                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1660                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1661                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1662                         /* first argument to do_div MUST be __u64 */
1663                         __u64 sum = ret.lc_sum;
1664                         do_div(sum, ret.lc_count);
1665                         ret.lc_sum = sum;
1666                         i += snprintf(page + i, count - i,
1667                                       "       %s_per_rpc: "LPU64"\n",
1668                                       header->lc_units, ret.lc_sum);
1669                         j = (int)ret.lc_sum;
1670                         if (j > 0)
1671                                 i += snprintf(page + i, count - i,
1672                                               "       MB_per_sec: %u.%.02u\n",
1673                                               k / j, (100 * k / j) % 100);
1674                 }
1675         }
1676
1677 out_climp:
1678         LPROCFS_CLIMP_EXIT(obd);
1679         return i;
1680 }
1681 EXPORT_SYMBOL(lprocfs_rd_import);
1682
1683 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1684                       int *eof, void *data)
1685 {
1686         struct obd_device *obd = (struct obd_device *)data;
1687         struct obd_import *imp;
1688         int i, j, k;
1689
1690         LASSERT(obd != NULL);
1691         LPROCFS_CLIMP_CHECK(obd);
1692         imp = obd->u.cli.cl_import;
1693         *eof = 1;
1694
1695         i = snprintf(page, count, "current_state: %s\n",
1696                      ptlrpc_import_state_name(imp->imp_state));
1697         i += snprintf(page + i, count - i,
1698                       "state_history:\n");
1699         k = imp->imp_state_hist_idx;
1700         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1701                 struct import_state_hist *ish =
1702                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1703                 if (ish->ish_state == 0)
1704                         continue;
1705                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1706                               ish->ish_time,
1707                               ptlrpc_import_state_name(ish->ish_state));
1708         }
1709
1710         LPROCFS_CLIMP_EXIT(obd);
1711         return i;
1712 }
1713 EXPORT_SYMBOL(lprocfs_rd_state);
1714
1715 int lprocfs_at_hist_helper(char *page, int count, int rc,
1716                            struct adaptive_timeout *at)
1717 {
1718         int i;
1719         for (i = 0; i < AT_BINS; i++)
1720                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1721         rc += snprintf(page + rc, count - rc, "\n");
1722         return rc;
1723 }
1724 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1725
1726 /* See also ptlrpc_lprocfs_rd_timeouts */
1727 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1728                         int *eof, void *data)
1729 {
1730         struct obd_device *obd = (struct obd_device *)data;
1731         struct obd_import *imp;
1732         unsigned int cur, worst;
1733         time_t now, worstt;
1734         struct dhms ts;
1735         int i, rc = 0;
1736
1737         LASSERT(obd != NULL);
1738         LPROCFS_CLIMP_CHECK(obd);
1739         imp = obd->u.cli.cl_import;
1740         *eof = 1;
1741
1742         now = cfs_time_current_sec();
1743
1744         /* Some network health info for kicks */
1745         s2dhms(&ts, now - imp->imp_last_reply_time);
1746         rc += snprintf(page + rc, count - rc,
1747                        "%-10s : %ld, "DHMS_FMT" ago\n",
1748                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1749
1750         cur = at_get(&imp->imp_at.iat_net_latency);
1751         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1752         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1753         s2dhms(&ts, now - worstt);
1754         rc += snprintf(page + rc, count - rc,
1755                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1756                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1757         rc = lprocfs_at_hist_helper(page, count, rc,
1758                                     &imp->imp_at.iat_net_latency);
1759
1760         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1761                 if (imp->imp_at.iat_portal[i] == 0)
1762                         break;
1763                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1764                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1765                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1766                 s2dhms(&ts, now - worstt);
1767                 rc += snprintf(page + rc, count - rc,
1768                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1769                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1770                                cur, worst, worstt, DHMS_VARS(&ts));
1771                 rc = lprocfs_at_hist_helper(page, count, rc,
1772                                           &imp->imp_at.iat_service_estimate[i]);
1773         }
1774
1775         LPROCFS_CLIMP_EXIT(obd);
1776         return rc;
1777 }
1778 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1779
1780 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1781                              int count, int *eof, void *data)
1782 {
1783         struct obd_device *obd = data;
1784         __u64 flags;
1785         int ret = 0;
1786
1787         LPROCFS_CLIMP_CHECK(obd);
1788         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1789         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1790         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1791         ret += snprintf(page + ret, count - ret, "\n");
1792         LPROCFS_CLIMP_EXIT(obd);
1793         return ret;
1794 }
1795 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1796
1797 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1798                            int *eof,  void *data)
1799 {
1800         struct obd_device *obd = data;
1801
1802         LASSERT(obd != NULL);
1803         *eof = 1;
1804         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1805 }
1806 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1807
1808 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1809                        int *eof, void *data)
1810 {
1811         struct obd_type *class = (struct obd_type*) data;
1812
1813         LASSERT(class != NULL);
1814         *eof = 1;
1815         return snprintf(page, count, "%d\n", class->typ_refcnt);
1816 }
1817 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1818
1819 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1820 {
1821         int rc = 0;
1822
1823         LASSERT(obd != NULL);
1824         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1825         LASSERT(obd->obd_type->typ_procroot != NULL);
1826
1827         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1828                                                obd->obd_type->typ_procroot,
1829                                                list, obd);
1830         if (IS_ERR(obd->obd_proc_entry)) {
1831                 rc = PTR_ERR(obd->obd_proc_entry);
1832                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1833                 obd->obd_proc_entry = NULL;
1834         }
1835         return rc;
1836 }
1837 EXPORT_SYMBOL(lprocfs_obd_setup);
1838 #endif
1839
1840 int
1841 lprocfs_seq_obd_setup(struct obd_device *obd)
1842 {
1843         int rc = 0;
1844
1845         LASSERT(obd != NULL);
1846         LASSERT(obd->obd_vars != NULL);
1847         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1848         LASSERT(obd->obd_type->typ_procroot != NULL);
1849
1850         obd->obd_proc_entry = lprocfs_seq_register(obd->obd_name,
1851                                                    obd->obd_type->typ_procroot,
1852                                                    obd->obd_vars, obd);
1853         if (IS_ERR(obd->obd_proc_entry)) {
1854                 rc = PTR_ERR(obd->obd_proc_entry);
1855                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1856                 obd->obd_proc_entry = NULL;
1857         }
1858         return rc;
1859 }
1860 EXPORT_SYMBOL(lprocfs_seq_obd_setup);
1861
1862 int lprocfs_obd_cleanup(struct obd_device *obd)
1863 {
1864         if (!obd)
1865                 return -EINVAL;
1866         if (obd->obd_proc_exports_entry) {
1867                 /* Should be no exports left */
1868                 lprocfs_remove(&obd->obd_proc_exports_entry);
1869                 obd->obd_proc_exports_entry = NULL;
1870         }
1871         if (obd->obd_proc_entry) {
1872                 lprocfs_remove(&obd->obd_proc_entry);
1873                 obd->obd_proc_entry = NULL;
1874         }
1875         return 0;
1876 }
1877 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1878
1879 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1880 {
1881         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
1882                client_stat->nid_proc, client_stat->nid_stats);
1883
1884         LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
1885                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1886                  atomic_read(&client_stat->nid_exp_ref_count));
1887
1888         if (client_stat->nid_proc)
1889                 lprocfs_remove(&client_stat->nid_proc);
1890
1891         if (client_stat->nid_stats)
1892                 lprocfs_free_stats(&client_stat->nid_stats);
1893
1894         if (client_stat->nid_ldlm_stats)
1895                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1896
1897         OBD_FREE_PTR(client_stat);
1898         return;
1899
1900 }
1901
1902 void lprocfs_free_per_client_stats(struct obd_device *obd)
1903 {
1904         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1905         struct nid_stat *stat;
1906         ENTRY;
1907
1908         /* we need extra list - because hash_exit called to early */
1909         /* not need locking because all clients is died */
1910         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1911                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1912                                       struct nid_stat, nid_list);
1913                 cfs_list_del_init(&stat->nid_list);
1914                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1915                 lprocfs_free_client_stats(stat);
1916         }
1917         EXIT;
1918 }
1919 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1920
1921 int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid)
1922 {
1923         struct lprocfs_counter  *cntr;
1924         unsigned int            percpusize;
1925         int                     rc = -ENOMEM;
1926         unsigned long           flags = 0;
1927         int                     i;
1928
1929         LASSERT(stats->ls_percpu[cpuid] == NULL);
1930         LASSERT((stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) == 0);
1931
1932         percpusize = lprocfs_stats_counter_size(stats);
1933         LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[cpuid], percpusize);
1934         if (stats->ls_percpu[cpuid] != NULL) {
1935                 rc = 0;
1936                 if (unlikely(stats->ls_biggest_alloc_num <= cpuid)) {
1937                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1938                                 spin_lock_irqsave(&stats->ls_lock, flags);
1939                         else
1940                                 spin_lock(&stats->ls_lock);
1941                         if (stats->ls_biggest_alloc_num <= cpuid)
1942                                 stats->ls_biggest_alloc_num = cpuid + 1;
1943                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) {
1944                                 spin_unlock_irqrestore(&stats->ls_lock, flags);
1945                         } else {
1946                                 spin_unlock(&stats->ls_lock);
1947                         }
1948                 }
1949                 /* initialize the ls_percpu[cpuid] non-zero counter */
1950                 for (i = 0; i < stats->ls_num; ++i) {
1951                         cntr = lprocfs_stats_counter_get(stats, cpuid, i);
1952                         cntr->lc_min = LC_MIN_INIT;
1953                 }
1954         }
1955         return rc;
1956 }
1957 EXPORT_SYMBOL(lprocfs_stats_alloc_one);
1958
1959 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1960                                           enum lprocfs_stats_flags flags)
1961 {
1962         struct lprocfs_stats    *stats;
1963         unsigned int            num_entry;
1964         unsigned int            percpusize = 0;
1965         int                     i;
1966
1967         if (num == 0)
1968                 return NULL;
1969
1970         if (lprocfs_no_percpu_stats != 0)
1971                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1972
1973         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1974                 num_entry = 1;
1975         else
1976                 num_entry = num_possible_cpus();
1977
1978         /* alloc percpu pointers for all possible cpu slots */
1979         LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1980         if (stats == NULL)
1981                 return NULL;
1982
1983         stats->ls_num = num;
1984         stats->ls_flags = flags;
1985         spin_lock_init(&stats->ls_lock);
1986
1987         /* alloc num of counter headers */
1988         LIBCFS_ALLOC(stats->ls_cnt_header,
1989                      stats->ls_num * sizeof(struct lprocfs_counter_header));
1990         if (stats->ls_cnt_header == NULL)
1991                 goto fail;
1992
1993         if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
1994                 /* contains only one set counters */
1995                 percpusize = lprocfs_stats_counter_size(stats);
1996                 LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
1997                 if (stats->ls_percpu[0] == NULL)
1998                         goto fail;
1999                 stats->ls_biggest_alloc_num = 1;
2000         } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
2001                 /* alloc all percpu data, currently only obd_memory use this */
2002                 for (i = 0; i < num_entry; ++i)
2003                         if (lprocfs_stats_alloc_one(stats, i) < 0)
2004                                 goto fail;
2005         }
2006
2007         return stats;
2008
2009 fail:
2010         lprocfs_free_stats(&stats);
2011         return NULL;
2012 }
2013 EXPORT_SYMBOL(lprocfs_alloc_stats);
2014
2015 void lprocfs_free_stats(struct lprocfs_stats **statsh)
2016 {
2017         struct lprocfs_stats *stats = *statsh;
2018         unsigned int num_entry;
2019         unsigned int percpusize;
2020         unsigned int i;
2021
2022         if (stats == NULL || stats->ls_num == 0)
2023                 return;
2024         *statsh = NULL;
2025
2026         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
2027                 num_entry = 1;
2028         else
2029                 num_entry = num_possible_cpus();
2030
2031         percpusize = lprocfs_stats_counter_size(stats);
2032         for (i = 0; i < num_entry; i++)
2033                 if (stats->ls_percpu[i] != NULL)
2034                         LIBCFS_FREE(stats->ls_percpu[i], percpusize);
2035         if (stats->ls_cnt_header != NULL)
2036                 LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
2037                                         sizeof(struct lprocfs_counter_header));
2038         LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
2039 }
2040 EXPORT_SYMBOL(lprocfs_free_stats);
2041
2042 void lprocfs_clear_stats(struct lprocfs_stats *stats)
2043 {
2044         struct lprocfs_counter          *percpu_cntr;
2045         int                             i;
2046         int                             j;
2047         unsigned int                    num_entry;
2048         unsigned long                   flags = 0;
2049
2050         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
2051
2052         for (i = 0; i < num_entry; i++) {
2053                 if (stats->ls_percpu[i] == NULL)
2054                         continue;
2055                 for (j = 0; j < stats->ls_num; j++) {
2056                         percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
2057                         percpu_cntr->lc_count           = 0;
2058                         percpu_cntr->lc_min             = LC_MIN_INIT;
2059                         percpu_cntr->lc_max             = 0;
2060                         percpu_cntr->lc_sumsquare       = 0;
2061                         percpu_cntr->lc_sum             = 0;
2062                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
2063                                 percpu_cntr->lc_sum_irq = 0;
2064                 }
2065         }
2066
2067         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
2068 }
2069 EXPORT_SYMBOL(lprocfs_clear_stats);
2070
2071 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
2072                                        size_t len, loff_t *off)
2073 {
2074         struct seq_file *seq = file->private_data;
2075         struct lprocfs_stats *stats = seq->private;
2076
2077         lprocfs_clear_stats(stats);
2078
2079         return len;
2080 }
2081
2082 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
2083 {
2084         struct lprocfs_stats *stats = p->private;
2085
2086         return (*pos < stats->ls_num) ? pos : NULL;
2087 }
2088
2089 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
2090 {
2091 }
2092
2093 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
2094 {
2095         (*pos)++;
2096
2097         return lprocfs_stats_seq_start(p, pos);
2098 }
2099
2100 /* seq file export of one lprocfs counter */
2101 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
2102 {
2103         struct lprocfs_stats            *stats  = p->private;
2104         struct lprocfs_counter_header   *hdr;
2105         struct lprocfs_counter           ctr;
2106         int                              idx    = *(loff_t *)v;
2107         int                              rc     = 0;
2108
2109         if (idx == 0) {
2110                 struct timeval now;
2111
2112                 do_gettimeofday(&now);
2113                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
2114                                 "snapshot_time", now.tv_sec, now.tv_usec);
2115                 if (rc < 0)
2116                         return rc;
2117         }
2118
2119         hdr = &stats->ls_cnt_header[idx];
2120         lprocfs_stats_collect(stats, idx, &ctr);
2121
2122         if (ctr.lc_count == 0)
2123                 goto out;
2124
2125         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
2126                         ctr.lc_count, hdr->lc_units);
2127         if (rc < 0)
2128                 goto out;
2129
2130         if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
2131                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
2132                                 ctr.lc_min, ctr.lc_max, ctr.lc_sum);
2133                 if (rc < 0)
2134                         goto out;
2135                 if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
2136                         rc = seq_printf(p, " "LPD64, ctr.lc_sumsquare);
2137                 if (rc < 0)
2138                         goto out;
2139         }
2140         rc = seq_printf(p, "\n");
2141 out:
2142         return (rc < 0) ? rc : 0;
2143 }
2144
2145 struct seq_operations lprocfs_stats_seq_sops = {
2146         .start  = lprocfs_stats_seq_start,
2147         .stop   = lprocfs_stats_seq_stop,
2148         .next   = lprocfs_stats_seq_next,
2149         .show   = lprocfs_stats_seq_show,
2150 };
2151
2152 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
2153 {
2154         struct seq_file *seq;
2155         int rc;
2156
2157 #ifndef HAVE_ONLY_PROCFS_SEQ
2158         if (LPROCFS_ENTRY_CHECK(PDE(inode)))
2159                 return -ENOENT;
2160 #endif
2161         rc = seq_open(file, &lprocfs_stats_seq_sops);
2162         if (rc)
2163                 return rc;
2164         seq = file->private_data;
2165         seq->private = PDE_DATA(inode);
2166         return 0;
2167 }
2168
2169 struct file_operations lprocfs_stats_seq_fops = {
2170         .owner   = THIS_MODULE,
2171         .open    = lprocfs_stats_seq_open,
2172         .read    = seq_read,
2173         .write   = lprocfs_stats_seq_write,
2174         .llseek  = seq_lseek,
2175         .release = lprocfs_seq_release,
2176 };
2177
2178 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
2179                            struct lprocfs_stats *stats)
2180 {
2181         struct proc_dir_entry *entry;
2182         LASSERT(root != NULL);
2183
2184         entry = proc_create_data(name, 0644, root,
2185                                  &lprocfs_stats_seq_fops, stats);
2186         if (entry == NULL)
2187                 return -ENOMEM;
2188         return 0;
2189 }
2190 EXPORT_SYMBOL(lprocfs_register_stats);
2191
2192 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
2193                           unsigned conf, const char *name, const char *units)
2194 {
2195         struct lprocfs_counter_header   *header;
2196         struct lprocfs_counter          *percpu_cntr;
2197         unsigned long                   flags = 0;
2198         unsigned int                    i;
2199         unsigned int                    num_cpu;
2200
2201         LASSERT(stats != NULL);
2202
2203         header = &stats->ls_cnt_header[index];
2204         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
2205                  index, name, units);
2206
2207         header->lc_config = conf;
2208         header->lc_name   = name;
2209         header->lc_units  = units;
2210
2211         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
2212         for (i = 0; i < num_cpu; ++i) {
2213                 if (stats->ls_percpu[i] == NULL)
2214                         continue;
2215                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
2216                 percpu_cntr->lc_count           = 0;
2217                 percpu_cntr->lc_min             = LC_MIN_INIT;
2218                 percpu_cntr->lc_max             = 0;
2219                 percpu_cntr->lc_sumsquare       = 0;
2220                 percpu_cntr->lc_sum             = 0;
2221                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
2222                         percpu_cntr->lc_sum_irq = 0;
2223         }
2224         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
2225 }
2226 EXPORT_SYMBOL(lprocfs_counter_init);
2227
2228 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
2229 do {                                                                       \
2230         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
2231         LASSERT(coffset < stats->ls_num);                                  \
2232         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
2233 } while (0)
2234
2235 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
2236 {
2237         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
2238         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
2239         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
2240         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
2241         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
2242         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
2243         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
2244         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
2245         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
2246         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
2247         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
2248         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
2249         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
2250         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
2251         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
2252         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
2253         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
2254         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
2255         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
2256         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
2257         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
2258         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
2259         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
2260         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
2261         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
2262         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
2263         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
2264         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
2265         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
2266         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
2267         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
2268         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
2269         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
2270         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
2271         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
2272         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
2273         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
2274         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
2275         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
2276         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
2277         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
2278         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
2279         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
2280         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
2281         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
2282         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
2283         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
2284         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
2285         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
2286         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
2287         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
2288         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
2289         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
2290         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
2291         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
2292         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
2293         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
2294         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
2295         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
2296         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
2297         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
2298         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
2299         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
2300         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
2301         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
2302         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
2303         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
2304
2305         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
2306 }
2307 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2308
2309 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
2310 {
2311         struct lprocfs_stats *stats;
2312         unsigned int num_stats;
2313         int rc, i;
2314
2315         LASSERT(obd->obd_stats == NULL);
2316         LASSERT(obd->obd_proc_entry != NULL);
2317         LASSERT(obd->obd_cntr_base == 0);
2318
2319         num_stats = NUM_OBD_STATS + num_private_stats;
2320         stats = lprocfs_alloc_stats(num_stats, 0);
2321         if (stats == NULL)
2322                 return -ENOMEM;
2323
2324         lprocfs_init_ops_stats(num_private_stats, stats);
2325
2326         for (i = num_private_stats; i < num_stats; i++) {
2327                 /* If this LBUGs, it is likely that an obd
2328                  * operation was added to struct obd_ops in
2329                  * <obd.h>, and that the corresponding line item
2330                  * LPROCFS_OBD_OP_INIT(.., .., opname)
2331                  * is missing from the list above. */
2332                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
2333                          "Missing obd_stat initializer obd_op "
2334                          "operation at offset %d.\n", i - num_private_stats);
2335         }
2336         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
2337         if (rc < 0) {
2338                 lprocfs_free_stats(&stats);
2339         } else {
2340                 obd->obd_stats  = stats;
2341                 obd->obd_cntr_base = num_private_stats;
2342         }
2343         return rc;
2344 }
2345 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2346
2347 void lprocfs_free_obd_stats(struct obd_device *obd)
2348 {
2349         if (obd->obd_stats)
2350                 lprocfs_free_stats(&obd->obd_stats);
2351 }
2352 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2353
2354 /* Note that we only init md counters for ops whose offset is less
2355  * than NUM_MD_STATS. This is explained in a comment in the definition
2356  * of struct md_ops. */
2357 #define LPROCFS_MD_OP_INIT(base, stats, op)                                    \
2358         do {                                                                   \
2359                 unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
2360                                                                                \
2361                 if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
2362                         LASSERT(_idx < stats->ls_num);                         \
2363                         lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
2364                 }                                                              \
2365         } while (0)
2366
2367 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
2368 {
2369         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
2370         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
2371         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
2372         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
2373         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
2374         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
2375         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
2376         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
2377         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
2378         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
2379         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
2380         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
2381         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
2382         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
2383         LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
2384         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
2385         LPROCFS_MD_OP_INIT(num_private_stats, stats, read_entry);
2386         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
2387         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
2388         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
2389         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
2390         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
2391         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
2392         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
2393         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
2394         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
2395         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
2396         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
2397         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
2398         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
2399         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
2400         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
2401         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
2402 }
2403 EXPORT_SYMBOL(lprocfs_init_mps_stats);
2404
2405 int lprocfs_alloc_md_stats(struct obd_device *obd,
2406                            unsigned int num_private_stats)
2407 {
2408         struct lprocfs_stats *stats;
2409         unsigned int num_stats;
2410         int rc, i;
2411
2412         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
2413         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
2414         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
2415
2416         /* TODO Ensure that this function is only used where
2417          * appropriate by adding an assertion to the effect that
2418          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
2419          * because mdt_procfs_init() uses this function to allocate
2420          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
2421          * mdt layer does not use the md_ops interface. This is
2422          * confusing and a waste of memory. See LU-2484.
2423          */
2424         LASSERT(obd->obd_proc_entry != NULL);
2425         LASSERT(obd->obd_md_stats == NULL);
2426         LASSERT(obd->obd_md_cntr_base == 0);
2427
2428         num_stats = NUM_MD_STATS + num_private_stats;
2429         stats = lprocfs_alloc_stats(num_stats, 0);
2430         if (stats == NULL)
2431                 return -ENOMEM;
2432
2433         lprocfs_init_mps_stats(num_private_stats, stats);
2434
2435         for (i = num_private_stats; i < num_stats; i++) {
2436                 if (stats->ls_cnt_header[i].lc_name == NULL) {
2437                         CERROR("Missing md_stat initializer md_op "
2438                                "operation at offset %d. Aborting.\n",
2439                                i - num_private_stats);
2440                         LBUG();
2441                 }
2442         }
2443
2444         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
2445         if (rc < 0) {
2446                 lprocfs_free_stats(&stats);
2447         } else {
2448                 obd->obd_md_stats = stats;
2449                 obd->obd_md_cntr_base = num_private_stats;
2450         }
2451
2452         return rc;
2453 }
2454 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2455
2456 void lprocfs_free_md_stats(struct obd_device *obd)
2457 {
2458         struct lprocfs_stats *stats = obd->obd_md_stats;
2459
2460         if (stats != NULL) {
2461                 obd->obd_md_stats = NULL;
2462                 obd->obd_md_cntr_base = 0;
2463                 lprocfs_free_stats(&stats);
2464         }
2465 }
2466 EXPORT_SYMBOL(lprocfs_free_md_stats);
2467
2468 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
2469 {
2470         lprocfs_counter_init(ldlm_stats,
2471                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
2472                              0, "ldlm_enqueue", "reqs");
2473         lprocfs_counter_init(ldlm_stats,
2474                              LDLM_CONVERT - LDLM_FIRST_OPC,
2475                              0, "ldlm_convert", "reqs");
2476         lprocfs_counter_init(ldlm_stats,
2477                              LDLM_CANCEL - LDLM_FIRST_OPC,
2478                              0, "ldlm_cancel", "reqs");
2479         lprocfs_counter_init(ldlm_stats,
2480                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
2481                              0, "ldlm_bl_callback", "reqs");
2482         lprocfs_counter_init(ldlm_stats,
2483                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
2484                              0, "ldlm_cp_callback", "reqs");
2485         lprocfs_counter_init(ldlm_stats,
2486                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
2487                              0, "ldlm_gl_callback", "reqs");
2488 }
2489 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2490
2491 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
2492                          int *eof,  void *data)
2493 {
2494         struct obd_export *exp = data;
2495         LASSERT(exp != NULL);
2496         *eof = 1;
2497         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
2498 }
2499
2500 struct exp_uuid_cb_data {
2501         char                   *page;
2502         int                     count;
2503         int                    *eof;
2504         int                    *len;
2505 };
2506
2507 static void
2508 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
2509                             int count, int *eof, int *len)
2510 {
2511         cb_data->page = page;
2512         cb_data->count = count;
2513         cb_data->eof = eof;
2514         cb_data->len = len;
2515 }
2516
2517 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
2518                            cfs_hlist_node_t *hnode, void *cb_data)
2519
2520 {
2521         struct obd_export *exp = cfs_hash_object(hs, hnode);
2522         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
2523
2524         if (exp->exp_nid_stats)
2525                 *data->len += snprintf((data->page + *data->len),
2526                                        data->count, "%s\n",
2527                                        obd_uuid2str(&exp->exp_client_uuid));
2528         return 0;
2529 }
2530
2531 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
2532                         int *eof,  void *data)
2533 {
2534         struct nid_stat *stats = (struct nid_stat *)data;
2535         struct exp_uuid_cb_data cb_data;
2536         struct obd_device *obd = stats->nid_obd;
2537         int len = 0;
2538
2539         *eof = 1;
2540         page[0] = '\0';
2541         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
2542         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
2543                               lprocfs_exp_print_uuid, &cb_data);
2544         return (*cb_data.len);
2545 }
2546
2547 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
2548                            cfs_hlist_node_t *hnode, void *cb_data)
2549
2550 {
2551         struct exp_uuid_cb_data *data = cb_data;
2552         struct obd_export       *exp = cfs_hash_object(hs, hnode);
2553
2554         if (exp->exp_lock_hash != NULL) {
2555                 if (!*data->len) {
2556                         *data->len += cfs_hash_debug_header(data->page,
2557                                                             data->count);
2558                 }
2559                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
2560                                                  data->count);
2561         }
2562
2563         return 0;
2564 }
2565
2566 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
2567                         int *eof,  void *data)
2568 {
2569         struct nid_stat *stats = (struct nid_stat *)data;
2570         struct exp_uuid_cb_data cb_data;
2571         struct obd_device *obd = stats->nid_obd;
2572         int len = 0;
2573
2574         *eof = 1;
2575         page[0] = '\0';
2576         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
2577
2578         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
2579                               lprocfs_exp_print_hash, &cb_data);
2580         return (*cb_data.len);
2581 }
2582
2583 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
2584                                         int count, int *eof,  void *data)
2585 {
2586         *eof = 1;
2587         return snprintf(page, count, "%s\n",
2588                         "Write into this file to clear all nid stats and "
2589                         "stale nid entries");
2590 }
2591 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
2592
2593 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
2594 {
2595         struct nid_stat *stat = obj;
2596         ENTRY;
2597
2598         CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
2599         if (atomic_read(&stat->nid_exp_ref_count) == 1) {
2600                 /* object has only hash references. */
2601                 spin_lock(&stat->nid_obd->obd_nid_lock);
2602                 cfs_list_move(&stat->nid_list, data);
2603                 spin_unlock(&stat->nid_obd->obd_nid_lock);
2604                 RETURN(1);
2605         }
2606         /* we has reference to object - only clear data*/
2607         if (stat->nid_stats)
2608                 lprocfs_clear_stats(stat->nid_stats);
2609
2610         RETURN(0);
2611 }
2612
2613 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
2614                                   unsigned long count, void *data)
2615 {
2616         struct obd_device *obd = (struct obd_device *)data;
2617         struct nid_stat *client_stat;
2618         CFS_LIST_HEAD(free_list);
2619
2620         cfs_hash_cond_del(obd->obd_nid_stats_hash,
2621                           lprocfs_nid_stats_clear_write_cb, &free_list);
2622
2623         while (!cfs_list_empty(&free_list)) {
2624                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
2625                                              nid_list);
2626                 cfs_list_del_init(&client_stat->nid_list);
2627                 lprocfs_free_client_stats(client_stat);
2628         }
2629
2630         return count;
2631 }
2632 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
2633
2634 #ifdef HAVE_SERVER_SUPPORT
2635 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2636 {
2637         struct nid_stat *new_stat, *old_stat;
2638         struct obd_device *obd = NULL;
2639         cfs_proc_dir_entry_t *entry;
2640         char *buffer = NULL;
2641         int rc = 0;
2642         ENTRY;
2643
2644         *newnid = 0;
2645
2646         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2647             !exp->exp_obd->obd_nid_stats_hash)
2648                 RETURN(-EINVAL);
2649
2650         /* not test against zero because eric say:
2651          * You may only test nid against another nid, or LNET_NID_ANY.
2652          * Anything else is nonsense.*/
2653         if (!nid || *nid == LNET_NID_ANY)
2654                 RETURN(0);
2655
2656         spin_lock(&exp->exp_lock);
2657         if (exp->exp_nid_stats != NULL) {
2658                 spin_unlock(&exp->exp_lock);
2659                 RETURN(-EALREADY);
2660         }
2661         spin_unlock(&exp->exp_lock);
2662
2663         obd = exp->exp_obd;
2664
2665         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2666
2667         OBD_ALLOC_PTR(new_stat);
2668         if (new_stat == NULL)
2669                 RETURN(-ENOMEM);
2670
2671         new_stat->nid               = *nid;
2672         new_stat->nid_obd           = exp->exp_obd;
2673         /* we need set default refcount to 1 to balance obd_disconnect */
2674         atomic_set(&new_stat->nid_exp_ref_count, 1);
2675
2676         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2677                                            nid, &new_stat->nid_hash);
2678         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2679                old_stat, libcfs_nid2str(*nid),
2680                atomic_read(&new_stat->nid_exp_ref_count));
2681
2682         /* Return -EALREADY here so that we know that the /proc
2683          * entry already has been created */
2684         if (old_stat != new_stat) {
2685                 nidstat_putref(old_stat);
2686                 GOTO(destroy_new, rc = -EALREADY);
2687         }
2688         /* not found - create */
2689         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2690         if (buffer == NULL)
2691                 GOTO(destroy_new, rc = -ENOMEM);
2692
2693         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2694         new_stat->nid_proc = lprocfs_register(buffer,
2695                                               obd->obd_proc_exports_entry,
2696                                               NULL, NULL);
2697         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2698
2699         if (IS_ERR(new_stat->nid_proc)) {
2700                 rc = PTR_ERR(new_stat->nid_proc);
2701                 new_stat->nid_proc = NULL;
2702                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
2703                        obd->obd_name, libcfs_nid2str(*nid), rc);
2704                 GOTO(destroy_new_ns, rc);
2705         }
2706
2707         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2708                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2709         if (IS_ERR(entry)) {
2710                 CWARN("Error adding the NID stats file\n");
2711                 rc = PTR_ERR(entry);
2712                 GOTO(destroy_new_ns, rc);
2713         }
2714
2715         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2716                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2717         if (IS_ERR(entry)) {
2718                 CWARN("Error adding the hash file\n");
2719                 rc = PTR_ERR(entry);
2720                 GOTO(destroy_new_ns, rc);
2721         }
2722
2723         spin_lock(&exp->exp_lock);
2724         exp->exp_nid_stats = new_stat;
2725         spin_unlock(&exp->exp_lock);
2726         *newnid = 1;
2727         /* protect competitive add to list, not need locking on destroy */
2728         spin_lock(&obd->obd_nid_lock);
2729         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2730         spin_unlock(&obd->obd_nid_lock);
2731
2732         RETURN(rc);
2733
2734 destroy_new_ns:
2735         if (new_stat->nid_proc != NULL)
2736                 lprocfs_remove(&new_stat->nid_proc);
2737         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2738
2739 destroy_new:
2740         nidstat_putref(new_stat);
2741         OBD_FREE_PTR(new_stat);
2742         RETURN(rc);
2743 }
2744 EXPORT_SYMBOL(lprocfs_exp_setup);
2745 #endif
2746
2747 int lprocfs_exp_cleanup(struct obd_export *exp)
2748 {
2749         struct nid_stat *stat = exp->exp_nid_stats;
2750
2751         if(!stat || !exp->exp_obd)
2752                 RETURN(0);
2753
2754         nidstat_putref(exp->exp_nid_stats);
2755         exp->exp_nid_stats = NULL;
2756
2757         return 0;
2758 }
2759 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2760
2761 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
2762                           struct lprocfs_counter_header *header,
2763                           enum lprocfs_stats_flags flags,
2764                           enum lprocfs_fields_flags field)
2765 {
2766         __s64 ret = 0;
2767
2768         if (lc == NULL || header == NULL)
2769                 RETURN(0);
2770
2771         switch (field) {
2772                 case LPROCFS_FIELDS_FLAGS_CONFIG:
2773                         ret = header->lc_config;
2774                         break;
2775                 case LPROCFS_FIELDS_FLAGS_SUM:
2776                         ret = lc->lc_sum;
2777                         if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
2778                                 ret += lc->lc_sum_irq;
2779                         break;
2780                 case LPROCFS_FIELDS_FLAGS_MIN:
2781                         ret = lc->lc_min;
2782                         break;
2783                 case LPROCFS_FIELDS_FLAGS_MAX:
2784                         ret = lc->lc_max;
2785                         break;
2786                 case LPROCFS_FIELDS_FLAGS_AVG:
2787                         ret = (lc->lc_max - lc->lc_min) / 2;
2788                         break;
2789                 case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
2790                         ret = lc->lc_sumsquare;
2791                         break;
2792                 case LPROCFS_FIELDS_FLAGS_COUNT:
2793                         ret = lc->lc_count;
2794                         break;
2795                 default:
2796                         break;
2797         };
2798         RETURN(ret);
2799 }
2800 EXPORT_SYMBOL(lprocfs_read_helper);
2801
2802 int lprocfs_write_helper(const char *buffer, unsigned long count,
2803                          int *val)
2804 {
2805         return lprocfs_write_frac_helper(buffer, count, val, 1);
2806 }
2807 EXPORT_SYMBOL(lprocfs_write_helper);
2808
2809 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2810                               int *val, int mult)
2811 {
2812         char kernbuf[20], *end, *pbuf;
2813
2814         if (count > (sizeof(kernbuf) - 1))
2815                 return -EINVAL;
2816
2817         if (copy_from_user(kernbuf, buffer, count))
2818                 return -EFAULT;
2819
2820         kernbuf[count] = '\0';
2821         pbuf = kernbuf;
2822         if (*pbuf == '-') {
2823                 mult = -mult;
2824                 pbuf++;
2825         }
2826
2827         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2828         if (pbuf == end)
2829                 return -EINVAL;
2830
2831         if (end != NULL && *end == '.') {
2832                 int temp_val, pow = 1;
2833                 int i;
2834
2835                 pbuf = end + 1;
2836                 if (strlen(pbuf) > 5)
2837                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2838
2839                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2840
2841                 if (pbuf < end) {
2842                         for (i = 0; i < (end - pbuf); i++)
2843                                 pow *= 10;
2844
2845                         *val += temp_val / pow;
2846                 }
2847         }
2848         return 0;
2849 }
2850 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2851
2852 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2853                              int mult)
2854 {
2855         long decimal_val, frac_val;
2856         int prtn;
2857
2858         if (count < 10)
2859                 return -EINVAL;
2860
2861         decimal_val = val / mult;
2862         prtn = snprintf(buffer, count, "%ld", decimal_val);
2863         frac_val = val % mult;
2864
2865         if (prtn < (count - 4) && frac_val > 0) {
2866                 long temp_frac;
2867                 int i, temp_mult = 1, frac_bits = 0;
2868
2869                 temp_frac = frac_val * 10;
2870                 buffer[prtn++] = '.';
2871                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2872                         /* only reserved 2 bits fraction */
2873                         buffer[prtn++] ='0';
2874                         temp_frac *= 10;
2875                         frac_bits++;
2876                 }
2877                 /*
2878                  * Need to think these cases :
2879                  *      1. #echo x.00 > /proc/xxx       output result : x
2880                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2881                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2882                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2883                  *      Only reserved 2 bits fraction.
2884                  */
2885                 for (i = 0; i < (5 - prtn); i++)
2886                         temp_mult *= 10;
2887
2888                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2889                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2890                                  frac_val * temp_mult / mult);
2891
2892                 prtn--;
2893                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2894                         prtn--;
2895                         if (buffer[prtn] == '.') {
2896                                 prtn--;
2897                                 break;
2898                         }
2899                 }
2900                 prtn++;
2901         }
2902         buffer[prtn++] ='\n';
2903         return prtn;
2904 }
2905 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2906
2907 int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
2908 {
2909         long decimal_val, frac_val;
2910
2911         decimal_val = val / mult;
2912         seq_printf(m, "%ld", decimal_val);
2913         frac_val = val % mult;
2914
2915         if (frac_val > 0) {
2916                 frac_val *= 100;
2917                 frac_val /= mult;
2918         }
2919         if (frac_val > 0) {
2920                 /* Three cases: x0, xx, 0x */
2921                 if ((frac_val % 10) != 0)
2922                         seq_printf(m, ".%ld", frac_val);
2923                 else
2924                         seq_printf(m, ".%ld", frac_val / 10);
2925         }
2926
2927         seq_printf(m, "\n");
2928         return 0;
2929 }
2930 EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
2931
2932 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2933 {
2934         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2935 }
2936 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2937
2938 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2939                               __u64 *val, int mult)
2940 {
2941         char kernbuf[22], *end, *pbuf;
2942         __u64 whole, frac = 0, units;
2943         unsigned frac_d = 1;
2944
2945         if (count > (sizeof(kernbuf) - 1))
2946                 return -EINVAL;
2947
2948         if (copy_from_user(kernbuf, buffer, count))
2949                 return -EFAULT;
2950
2951         kernbuf[count] = '\0';
2952         pbuf = kernbuf;
2953         if (*pbuf == '-') {
2954                 mult = -mult;
2955                 pbuf++;
2956         }
2957
2958         whole = simple_strtoull(pbuf, &end, 10);
2959         if (pbuf == end)
2960                 return -EINVAL;
2961
2962         if (end != NULL && *end == '.') {
2963                 int i;
2964                 pbuf = end + 1;
2965
2966                 /* need to limit frac_d to a __u32 */
2967                 if (strlen(pbuf) > 10)
2968                         pbuf[10] = '\0';
2969
2970                 frac = simple_strtoull(pbuf, &end, 10);
2971                 /* count decimal places */
2972                 for (i = 0; i < (end - pbuf); i++)
2973                         frac_d *= 10;
2974         }
2975
2976         units = 1;
2977         if (end != NULL) {
2978                 switch (*end) {
2979                 case 'p': case 'P':
2980                         units <<= 10;
2981                 case 't': case 'T':
2982                         units <<= 10;
2983                 case 'g': case 'G':
2984                         units <<= 10;
2985                 case 'm': case 'M':
2986                         units <<= 10;
2987                 case 'k': case 'K':
2988                         units <<= 10;
2989                 }
2990         }
2991         /* Specified units override the multiplier */
2992         if (units)
2993                 mult = mult < 0 ? -units : units;
2994
2995         frac *= mult;
2996         do_div(frac, frac_d);
2997         *val = whole * mult + frac;
2998         return 0;
2999 }
3000 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
3001
3002 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
3003 {
3004         size_t l2;
3005
3006         l2 = strlen(s2);
3007         if (!l2)
3008                 return (char *)s1;
3009         while (len >= l2) {
3010                 len--;
3011                 if (!memcmp(s1, s2, l2))
3012                         return (char *)s1;
3013                 s1++;
3014         }
3015         return NULL;
3016 }
3017
3018 /**
3019  * Find the string \a name in the input \a buffer, and return a pointer to the
3020  * value immediately following \a name, reducing \a count appropriately.
3021  * If \a name is not found the original \a buffer is returned.
3022  */
3023 char *lprocfs_find_named_value(const char *buffer, const char *name,
3024                                 size_t *count)
3025 {
3026         char *val;
3027         size_t buflen = *count;
3028
3029         /* there is no strnstr() in rhel5 and ubuntu kernels */
3030         val = lprocfs_strnstr(buffer, name, buflen);
3031         if (val == NULL)
3032                 return (char *)buffer;
3033
3034         val += strlen(name);                             /* skip prefix */
3035         while (val < buffer + buflen && isspace(*val)) /* skip separator */
3036                 val++;
3037
3038         *count = 0;
3039         while (val < buffer + buflen && isalnum(*val)) {
3040                 ++*count;
3041                 ++val;
3042         }
3043
3044         return val - *count;
3045 }
3046 EXPORT_SYMBOL(lprocfs_find_named_value);
3047
3048 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
3049                        const char *name,
3050                        mode_t mode,
3051                        const struct file_operations *seq_fops,
3052                        void *data)
3053 {
3054         struct proc_dir_entry *entry;
3055         ENTRY;
3056
3057         /* Disallow secretly (un)writable entries. */
3058         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
3059
3060         entry = proc_create_data(name, mode, parent, seq_fops, data);
3061
3062         if (entry == NULL)
3063                 RETURN(-ENOMEM);
3064
3065         RETURN(0);
3066 }
3067 EXPORT_SYMBOL(lprocfs_seq_create);
3068
3069 int lprocfs_obd_seq_create(struct obd_device *dev,
3070                            const char *name,
3071                            mode_t mode,
3072                            const struct file_operations *seq_fops,
3073                            void *data)
3074 {
3075         return (lprocfs_seq_create(dev->obd_proc_entry, name,
3076                                    mode, seq_fops, data));
3077 }
3078 EXPORT_SYMBOL(lprocfs_obd_seq_create);
3079
3080 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
3081 {
3082         if (value >= OBD_HIST_MAX)
3083                 value = OBD_HIST_MAX - 1;
3084
3085         spin_lock(&oh->oh_lock);
3086         oh->oh_buckets[value]++;
3087         spin_unlock(&oh->oh_lock);
3088 }
3089 EXPORT_SYMBOL(lprocfs_oh_tally);
3090
3091 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
3092 {
3093         unsigned int val = 0;
3094
3095         if (likely(value != 0))
3096                 val = min(fls(value - 1), OBD_HIST_MAX);
3097
3098         lprocfs_oh_tally(oh, val);
3099 }
3100 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
3101
3102 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
3103 {
3104         unsigned long ret = 0;
3105         int i;
3106
3107         for (i = 0; i < OBD_HIST_MAX; i++)
3108                 ret +=  oh->oh_buckets[i];
3109         return ret;
3110 }
3111 EXPORT_SYMBOL(lprocfs_oh_sum);
3112
3113 void lprocfs_oh_clear(struct obd_histogram *oh)
3114 {
3115         spin_lock(&oh->oh_lock);
3116         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
3117         spin_unlock(&oh->oh_lock);
3118 }
3119 EXPORT_SYMBOL(lprocfs_oh_clear);
3120
3121 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
3122                         int count, int *eof, void *data)
3123 {
3124         struct obd_device *obd = data;
3125         int c = 0;
3126
3127         if (obd == NULL)
3128                 return 0;
3129
3130         c += cfs_hash_debug_header(page, count);
3131         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
3132         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
3133         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
3134
3135         return c;
3136 }
3137 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
3138
3139 #ifdef HAVE_SERVER_SUPPORT
3140 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
3141                                    int count, int *eof, void *data)
3142 {
3143         struct obd_device *obd = data;
3144         int len = 0, size;
3145
3146         LASSERT(obd != NULL);
3147         LASSERT(count >= 0);
3148
3149         /* Set start of user data returned to
3150            page + off since the user may have
3151            requested to read much smaller than
3152            what we need to read */
3153         *start = page + off;
3154
3155         /*
3156          * We know we are allocated a page here.
3157          * Also we know that this function will
3158          * not need to write more than a page
3159          * so we can truncate at PAGE_CACHE_SIZE.
3160          */
3161         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
3162
3163         /* Initialize the page */
3164         memset(page, 0, size);
3165
3166         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
3167                 goto out;
3168         if (obd->obd_max_recoverable_clients == 0) {
3169                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
3170                         goto out;
3171
3172                 goto fclose;
3173         }
3174
3175         /* sampled unlocked, but really... */
3176         if (obd->obd_recovering == 0) {
3177                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
3178                         goto out;
3179                 if (lprocfs_obd_snprintf(&page, size, &len,
3180                                          "recovery_start: %lu\n",
3181                                          obd->obd_recovery_start) <= 0)
3182                         goto out;
3183                 if (lprocfs_obd_snprintf(&page, size, &len,
3184                                          "recovery_duration: %lu\n",
3185                                          obd->obd_recovery_end -
3186                                          obd->obd_recovery_start) <= 0)
3187                         goto out;
3188                 /* Number of clients that have completed recovery */
3189                 if (lprocfs_obd_snprintf(&page, size, &len,
3190                                          "completed_clients: %d/%d\n",
3191                                          obd->obd_max_recoverable_clients -
3192                                          obd->obd_stale_clients,
3193        &nb