Whamcloud - gitweb
LU-3386 lproc: improve osc/mdc "imports" connect data
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lprocfs_status.c
37  *
38  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
39  */
40
41 #define DEBUG_SUBSYSTEM S_CLASS
42
43 #ifndef __KERNEL__
44 #include <liblustre.h>
45 #endif
46
47 #include <obd_class.h>
48 #include <lprocfs_status.h>
49 #include <lustre/lustre_idl.h>
50
51 #if defined(LPROCFS)
52
53 static int lprocfs_no_percpu_stats = 0;
54 CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
55                 "Do not alloc percpu data for lprocfs stats");
56
57 #define MAX_STRING_SIZE 128
58
59 int lprocfs_single_release(struct inode *inode, struct file *file)
60 {
61         return single_release(inode, file);
62 }
63 EXPORT_SYMBOL(lprocfs_single_release);
64
65 int lprocfs_seq_release(struct inode *inode, struct file *file)
66 {
67         return seq_release(inode, file);
68 }
69 EXPORT_SYMBOL(lprocfs_seq_release);
70
71 #ifndef HAVE_ONLY_PROCFS_SEQ
72 /* for b=10866, global variable */
73 DECLARE_RWSEM(_lprocfs_lock);
74 EXPORT_SYMBOL(_lprocfs_lock);
75
76 static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
77                                              const char *name)
78 {
79         struct proc_dir_entry *temp;
80
81         if (head == NULL)
82                 return NULL;
83
84         temp = head->subdir;
85         while (temp != NULL) {
86                 if (strcmp(temp->name, name) == 0) {
87                         return temp;
88                 }
89
90                 temp = temp->next;
91         }
92         return NULL;
93 }
94
95 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
96                                     const char *name)
97 {
98         struct proc_dir_entry *temp;
99
100         LPROCFS_SRCH_ENTRY();
101         temp = __lprocfs_srch(head, name);
102         LPROCFS_SRCH_EXIT();
103         return temp;
104 }
105 EXPORT_SYMBOL(lprocfs_srch);
106
107 /* lprocfs API calls */
108
109 /* Function that emulates snprintf but also has the side effect of advancing
110    the page pointer for the next write into the buffer, incrementing the total
111    length written to the buffer, and decrementing the size left in the
112    buffer. */
113 #ifdef HAVE_SERVER_SUPPORT
114 static int lprocfs_obd_snprintf(char **page, int end, int *len,
115                                 const char *format, ...)
116 {
117         va_list list;
118         int n;
119
120         if (*len >= end)
121                 return 0;
122
123         va_start(list, format);
124         n = vsnprintf(*page, end - *len, format, list);
125         va_end(list);
126
127         *page += n; *len += n;
128         return n;
129 }
130 #endif  /* HAVE_SERVER_SUPPORT */
131 #endif  /* HAVE_ONLY_PROCFS_SEQ */
132
133 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
134                                          char *name,
135 #ifndef HAVE_ONLY_PROCFS_SEQ
136                                          read_proc_t *read_proc,
137                                          write_proc_t *write_proc,
138 #endif
139                                          void *data,
140                                          struct file_operations *fops)
141 {
142         cfs_proc_dir_entry_t *proc;
143         mode_t mode = 0;
144
145         if (root == NULL || name == NULL)
146                 return ERR_PTR(-EINVAL);
147
148         if (!fops) {
149 #ifndef HAVE_ONLY_PROCFS_SEQ
150                 if (read_proc)
151                         mode = 0444;
152                 if (write_proc)
153                         mode |= 0200;
154
155                 LPROCFS_WRITE_ENTRY();
156                 proc = create_proc_entry(name, mode, root);
157                 if (!proc) {
158                         CERROR("LprocFS: No memory to create /proc entry %s", name);
159                         LPROCFS_WRITE_EXIT();
160                         return ERR_PTR(-ENOMEM);
161                 }
162                 proc->read_proc = read_proc;
163                 proc->write_proc = write_proc;
164                 proc->data = data;
165                 LPROCFS_WRITE_EXIT();
166 #else
167                 return ERR_PTR(-EINVAL);
168 #endif
169         } else {
170                 if (fops->read)
171                         mode = 0444;
172                 if (fops->write)
173                         mode |= 0200;
174                 proc = proc_create_data(name, mode, root, fops, data);
175                 if (!proc) {
176                         CERROR("LprocFS: No memory to create /proc entry %s",
177                                name);
178                         return ERR_PTR(-ENOMEM);
179                 }
180         }
181         return proc;
182 }
183 EXPORT_SYMBOL(lprocfs_add_simple);
184
185 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
186                         struct proc_dir_entry *parent, const char *format, ...)
187 {
188         struct proc_dir_entry *entry;
189         char *dest;
190         va_list ap;
191
192         if (parent == NULL || format == NULL)
193                 return NULL;
194
195         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
196         if (dest == NULL)
197                 return NULL;
198
199         va_start(ap, format);
200         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
201         va_end(ap);
202
203         entry = proc_symlink(name, parent, dest);
204         if (entry == NULL)
205                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
206                         name, dest);
207
208         OBD_FREE(dest, MAX_STRING_SIZE + 1);
209         return entry;
210 }
211 EXPORT_SYMBOL(lprocfs_add_symlink);
212
213 #ifndef HAVE_ONLY_PROCFS_SEQ
214 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
215                                  size_t size, loff_t *ppos)
216 {
217         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
218         char *page, *start = NULL;
219         int rc = 0, eof = 1, count;
220
221         if (*ppos >= PAGE_CACHE_SIZE)
222                 return 0;
223
224         page = (char *)__get_free_page(GFP_KERNEL);
225         if (page == NULL)
226                 return -ENOMEM;
227
228         if (LPROCFS_ENTRY_CHECK(dp)) {
229                 rc = -ENOENT;
230                 goto out;
231         }
232
233         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
234         if (dp->read_proc)
235                 rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
236                                    &eof, dp->data);
237         if (rc <= 0)
238                 goto out;
239
240         /* for lustre proc read, the read count must be less than PAGE_SIZE */
241         LASSERT(eof == 1);
242
243         if (start == NULL) {
244                 rc -= *ppos;
245                 if (rc < 0)
246                         rc = 0;
247                 if (rc == 0)
248                         goto out;
249                 start = page + *ppos;
250         } else if (start < page) {
251                 start = page;
252         }
253
254         count = (rc < size) ? rc : size;
255         if (copy_to_user(buf, start, count)) {
256                 rc = -EFAULT;
257                 goto out;
258         }
259         *ppos += count;
260
261 out:
262         free_page((unsigned long)page);
263         return rc;
264 }
265
266 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
267                                   size_t size, loff_t *ppos)
268 {
269         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
270         int rc = -EIO;
271
272         if (LPROCFS_ENTRY_CHECK(dp))
273                 return -ENOENT;
274         if (dp->write_proc)
275                 rc = dp->write_proc(f, buf, size, dp->data);
276         return rc;
277 }
278
279 static struct file_operations lprocfs_generic_fops = {
280         .owner = THIS_MODULE,
281         .read = lprocfs_fops_read,
282         .write = lprocfs_fops_write,
283 };
284 #else
285 static struct file_operations lprocfs_generic_fops = { };
286 #endif
287
288 #ifdef HAVE_SERVER_SUPPORT
289 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
290 {
291         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
292         struct obd_device *obd = dp->data;
293
294         cfs_atomic_inc(&obd->obd_evict_inprogress);
295
296         return 0;
297 }
298
299 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
300 {
301         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
302         struct obd_device *obd = dp->data;
303
304         cfs_atomic_dec(&obd->obd_evict_inprogress);
305         wake_up(&obd->obd_evict_inprogress_waitq);
306
307         return 0;
308 }
309
310 struct file_operations lprocfs_evict_client_fops = {
311         .owner = THIS_MODULE,
312         .read = lprocfs_fops_read,
313         .write = lprocfs_fops_write,
314         .open = lprocfs_evict_client_open,
315         .release = lprocfs_evict_client_release,
316 };
317 EXPORT_SYMBOL(lprocfs_evict_client_fops);
318 #endif
319
320 #ifndef HAVE_ONLY_PROCFS_SEQ
321 static int __lprocfs_add_vars(struct proc_dir_entry *root,
322                               struct lprocfs_vars *list,
323                               void *data)
324 {
325         int rc = 0;
326
327         if (root == NULL || list == NULL)
328                 return -EINVAL;
329
330         while (list->name != NULL) {
331                 struct proc_dir_entry *cur_root, *proc;
332                 char *pathcopy, *cur, *next, pathbuf[64];
333                 int pathsize = strlen(list->name) + 1;
334
335                 proc = NULL;
336                 cur_root = root;
337
338                 /* need copy of path for strsep */
339                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
340                         OBD_ALLOC(pathcopy, pathsize);
341                         if (pathcopy == NULL)
342                                 GOTO(out, rc = -ENOMEM);
343                 } else {
344                         pathcopy = pathbuf;
345                 }
346
347                 next = pathcopy;
348                 strcpy(pathcopy, list->name);
349
350                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
351                         if (*cur =='\0') /* skip double/trailing "/" */
352                                 continue;
353
354                         proc = __lprocfs_srch(cur_root, cur);
355                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
356                                cur_root->name, cur, next,
357                                (proc ? "exists" : "new"));
358                         if (next != NULL) {
359                                 cur_root = (proc ? proc :
360                                             proc_mkdir(cur, cur_root));
361                         } else if (proc == NULL) {
362                                 mode_t mode = 0;
363                                 if (list->proc_mode != 0000) {
364                                         mode = list->proc_mode;
365                                 } else {
366                                         if (list->read_fptr)
367                                                 mode = 0444;
368                                         if (list->write_fptr)
369                                                 mode |= 0200;
370                                 }
371                                 proc = create_proc_entry(cur, mode, cur_root);
372                         }
373                 }
374
375                 if (pathcopy != pathbuf)
376                         OBD_FREE(pathcopy, pathsize);
377
378                 if (cur_root == NULL || proc == NULL) {
379                         CERROR("LprocFS: No memory to create /proc entry %s",
380                                list->name);
381                         GOTO(out, rc = -ENOMEM);
382                 }
383
384                 if (list->fops)
385                         proc->proc_fops = list->fops;
386                 else
387                         proc->proc_fops = &lprocfs_generic_fops;
388                 proc->read_proc = list->read_fptr;
389                 proc->write_proc = list->write_fptr;
390                 proc->data = (list->data ? list->data : data);
391                 list++;
392         }
393 out:
394         return rc;
395 }
396
397 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
398                      void *data)
399 {
400         int rc = 0;
401
402         LPROCFS_WRITE_ENTRY();
403         rc = __lprocfs_add_vars(root, list, data);
404         LPROCFS_WRITE_EXIT();
405
406         return rc;
407 }
408 EXPORT_SYMBOL(lprocfs_add_vars);
409
410 #endif
411
412 /**
413  * Add /proc entries.
414  *
415  * \param root [in]  The parent proc entry on which new entry will be added.
416  * \param list [in]  Array of proc entries to be added.
417  * \param data [in]  The argument to be passed when entries read/write routines
418  *                   are called through /proc file.
419  *
420  * \retval 0   on success
421  *         < 0 on error
422  */
423 int
424 lprocfs_seq_add_vars(struct proc_dir_entry *root, struct lprocfs_seq_vars *list,
425                      void *data)
426 {
427         if (root == NULL || list == NULL)
428                 return -EINVAL;
429
430         while (list->name != NULL) {
431                 struct proc_dir_entry *proc;
432                 mode_t mode = 0;
433
434                 if (list->proc_mode != 0000) {
435                         mode = list->proc_mode;
436                 } else if (list->fops) {
437                         if (list->fops->read)
438                                 mode = 0444;
439                         if (list->fops->write)
440                                 mode |= 0200;
441                 }
442                 proc = proc_create_data(list->name, mode, root,
443                                         list->fops ?: &lprocfs_generic_fops,
444                                         list->data ?: data);
445                 if (proc == NULL)
446                         return -ENOMEM;
447                 list++;
448         }
449         return 0;
450 }
451 EXPORT_SYMBOL(lprocfs_seq_add_vars);
452
453 #ifndef HAVE_ONLY_PROCFS_SEQ
454 void lprocfs_remove_nolock(struct proc_dir_entry **proot)
455 {
456         struct proc_dir_entry *root = *proot;
457         struct proc_dir_entry *temp = root;
458         struct proc_dir_entry *rm_entry;
459         struct proc_dir_entry *parent;
460
461         *proot = NULL;
462         if (root == NULL || IS_ERR(root))
463                 return;
464
465         parent = root->parent;
466         LASSERT(parent != NULL);
467
468         while (1) {
469                 while (temp->subdir != NULL)
470                         temp = temp->subdir;
471
472                 rm_entry = temp;
473                 temp = temp->parent;
474
475                 /* Memory corruption once caused this to fail, and
476                    without this LASSERT we would loop here forever. */
477                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
478                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
479                          rm_entry->name, (int)strlen(rm_entry->name));
480
481                 remove_proc_entry(rm_entry->name, temp);
482                 if (temp == parent)
483                         break;
484         }
485 }
486 #endif
487
488 void lprocfs_remove(struct proc_dir_entry **rooth)
489 {
490 #ifndef HAVE_ONLY_PROCFS_SEQ
491         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
492         lprocfs_remove_nolock(rooth);
493         LPROCFS_WRITE_EXIT();
494 #else
495         proc_remove(*rooth);
496         *rooth = NULL;
497 #endif
498 }
499 EXPORT_SYMBOL(lprocfs_remove);
500
501 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
502 {
503         LASSERT(parent != NULL);
504         remove_proc_entry(name, parent);
505 }
506 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
507
508 #ifndef HAVE_ONLY_PROCFS_SEQ
509 void lprocfs_try_remove_proc_entry(const char *name,
510                                    struct proc_dir_entry *parent)
511 {
512         struct proc_dir_entry    *t = NULL;
513         struct proc_dir_entry   **p;
514         int                       len, busy = 0;
515
516         LASSERT(parent != NULL);
517         len = strlen(name);
518
519         LPROCFS_WRITE_ENTRY();
520
521         /* lookup target name */
522         for (p = &parent->subdir; *p; p = &(*p)->next) {
523                 if ((*p)->namelen != len)
524                         continue;
525                 if (memcmp(name, (*p)->name, len))
526                         continue;
527                 t = *p;
528                 break;
529         }
530
531         if (t) {
532                 /* verify it's empty: do not count "num_refs" */
533                 for (p = &t->subdir; *p; p = &(*p)->next) {
534                         if ((*p)->namelen != strlen("num_refs")) {
535                                 busy = 1;
536                                 break;
537                         }
538                         if (memcmp("num_refs", (*p)->name,
539                                    strlen("num_refs"))) {
540                                 busy = 1;
541                                 break;
542                         }
543                 }
544         }
545
546         if (busy == 0)
547                 lprocfs_remove_nolock(&t);
548
549         LPROCFS_WRITE_EXIT();
550
551         return;
552 }
553 EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
554
555 struct proc_dir_entry *lprocfs_register(const char *name,
556                                         struct proc_dir_entry *parent,
557                                         struct lprocfs_vars *list, void *data)
558 {
559         struct proc_dir_entry *entry;
560         int rc;
561
562         LPROCFS_WRITE_ENTRY();
563         entry = __lprocfs_srch(parent, name);
564         if (entry != NULL) {
565                 CERROR("entry '%s' already registered\n", name);
566                 GOTO(out, entry = ERR_PTR(-EALREADY));
567         }
568
569         entry = proc_mkdir(name, parent);
570         if (entry == NULL)
571                 GOTO(out, entry = ERR_PTR(-ENOMEM));
572
573         if (list != NULL) {
574                 rc = __lprocfs_add_vars(entry, list, data);
575                 if (rc != 0) {
576                         lprocfs_remove_nolock(&entry);
577                         GOTO(out, entry = ERR_PTR(rc));
578                 }
579         }
580 out:
581         LPROCFS_WRITE_EXIT();
582         return entry;
583 }
584 EXPORT_SYMBOL(lprocfs_register);
585 #endif
586
587 struct proc_dir_entry *
588 lprocfs_seq_register(const char *name, struct proc_dir_entry *parent,
589                      struct lprocfs_seq_vars *list, void *data)
590 {
591         struct proc_dir_entry *newchild;
592
593         newchild = proc_mkdir(name, parent);
594         if (newchild != NULL && list != NULL) {
595                 int rc = lprocfs_seq_add_vars(newchild, list, data);
596                 if (rc) {
597                         lprocfs_remove(&newchild);
598                         return ERR_PTR(rc);
599                 }
600         }
601         return newchild;
602 }
603 EXPORT_SYMBOL(lprocfs_seq_register);
604
605 /* Generic callbacks */
606 int lprocfs_uint_seq_show(struct seq_file *m, void *data)
607 {
608         return seq_printf(m, "%u\n", *(unsigned int *)data);
609 }
610 EXPORT_SYMBOL(lprocfs_uint_seq_show);
611
612 int lprocfs_wr_uint(struct file *file, const char *buffer,
613                     unsigned long count, void *data)
614 {
615         unsigned *p = data;
616         char dummy[MAX_STRING_SIZE + 1], *end;
617         unsigned long tmp;
618
619         dummy[MAX_STRING_SIZE] = '\0';
620         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
621                 return -EFAULT;
622
623         tmp = simple_strtoul(dummy, &end, 0);
624         if (dummy == end)
625                 return -EINVAL;
626
627         *p = (unsigned int)tmp;
628         return count;
629 }
630 EXPORT_SYMBOL(lprocfs_wr_uint);
631
632 ssize_t lprocfs_uint_seq_write(struct file *file, const char *buffer,
633                                size_t count, loff_t *off)
634 {
635         int *data = ((struct seq_file *)file->private_data)->private;
636         int val = 0, rc;
637
638         rc = lprocfs_write_helper(buffer, count, &val);
639         if (rc < 0)
640                 return rc;
641
642         return lprocfs_wr_uint(file, buffer, count, data);
643 }
644 EXPORT_SYMBOL(lprocfs_uint_seq_write);
645
646 int lprocfs_u64_seq_show(struct seq_file *m, void *data)
647 {
648         LASSERT(data != NULL);
649         return seq_printf(m, LPU64"\n", *(__u64 *)data);
650 }
651 EXPORT_SYMBOL(lprocfs_u64_seq_show);
652
653 int lprocfs_atomic_seq_show(struct seq_file *m, void *data)
654 {
655         cfs_atomic_t *atom = data;
656         LASSERT(atom != NULL);
657         return seq_printf(m, "%d\n", atomic_read(atom));
658 }
659 EXPORT_SYMBOL(lprocfs_atomic_seq_show);
660
661 ssize_t
662 lprocfs_atomic_seq_write(struct file *file, const char *buffer,
663                         size_t count, loff_t *off)
664 {
665         cfs_atomic_t *atm = ((struct seq_file *)file->private_data)->private;
666         int val = 0;
667         int rc;
668
669         rc = lprocfs_write_helper(buffer, count, &val);
670         if (rc < 0)
671                 return rc;
672
673         if (val <= 0)
674                 return -ERANGE;
675
676         cfs_atomic_set(atm, val);
677         return count;
678 }
679 EXPORT_SYMBOL(lprocfs_atomic_seq_write);
680
681 int lprocfs_uuid_seq_show(struct seq_file *m, void *data)
682 {
683         struct obd_device *obd = data;
684
685         LASSERT(obd != NULL);
686         return seq_printf(m, "%s\n", obd->obd_uuid.uuid);
687 }
688 EXPORT_SYMBOL(lprocfs_uuid_seq_show);
689
690 int lprocfs_name_seq_show(struct seq_file *m, void *data)
691 {
692         struct obd_device *dev = data;
693
694         LASSERT(dev != NULL);
695         return seq_printf(m, "%s\n", dev->obd_name);
696 }
697 EXPORT_SYMBOL(lprocfs_name_seq_show);
698
699 int lprocfs_blksize_seq_show(struct seq_file *m, void *data)
700 {
701         struct obd_device *obd = data;
702         struct obd_statfs  osfs;
703         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
704                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
705                             OBD_STATFS_NODELAY);
706         if (!rc)
707                 rc = seq_printf(m, "%u\n", osfs.os_bsize);
708         return rc;
709 }
710 EXPORT_SYMBOL(lprocfs_blksize_seq_show);
711
712 int lprocfs_kbytestotal_seq_show(struct seq_file *m, void *data)
713 {
714         struct obd_device *obd = data;
715         struct obd_statfs  osfs;
716         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
717                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
718                             OBD_STATFS_NODELAY);
719         if (!rc) {
720                 __u32 blk_size = osfs.os_bsize >> 10;
721                 __u64 result = osfs.os_blocks;
722
723                 while (blk_size >>= 1)
724                         result <<= 1;
725
726                 rc = seq_printf(m, LPU64"\n", result);
727         }
728         return rc;
729 }
730 EXPORT_SYMBOL(lprocfs_kbytestotal_seq_show);
731
732 int lprocfs_kbytesfree_seq_show(struct seq_file *m, void *data)
733 {
734         struct obd_device *obd = data;
735         struct obd_statfs  osfs;
736         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
737                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
738                             OBD_STATFS_NODELAY);
739         if (!rc) {
740                 __u32 blk_size = osfs.os_bsize >> 10;
741                 __u64 result = osfs.os_bfree;
742
743                 while (blk_size >>= 1)
744                         result <<= 1;
745
746                 rc = seq_printf(m, LPU64"\n", result);
747         }
748         return rc;
749 }
750 EXPORT_SYMBOL(lprocfs_kbytesfree_seq_show);
751
752 int lprocfs_kbytesavail_seq_show(struct seq_file *m, void *data)
753 {
754         struct obd_device *obd = data;
755         struct obd_statfs  osfs;
756         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
757                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
758                             OBD_STATFS_NODELAY);
759         if (!rc) {
760                 __u32 blk_size = osfs.os_bsize >> 10;
761                 __u64 result = osfs.os_bavail;
762
763                 while (blk_size >>= 1)
764                         result <<= 1;
765
766                 rc = seq_printf(m, LPU64"\n", result);
767         }
768         return rc;
769 }
770 EXPORT_SYMBOL(lprocfs_kbytesavail_seq_show);
771
772 int lprocfs_filestotal_seq_show(struct seq_file *m, void *data)
773 {
774         struct obd_device *obd = data;
775         struct obd_statfs  osfs;
776         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
777                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
778                             OBD_STATFS_NODELAY);
779         if (!rc)
780                 rc = seq_printf(m, LPU64"\n", osfs.os_files);
781         return rc;
782 }
783 EXPORT_SYMBOL(lprocfs_filestotal_seq_show);
784
785 int lprocfs_filesfree_seq_show(struct seq_file *m, void *data)
786 {
787         struct obd_device *obd = data;
788         struct obd_statfs  osfs;
789         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
790                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
791                             OBD_STATFS_NODELAY);
792         if (!rc)
793                 rc = seq_printf(m, LPU64"\n", osfs.os_ffree);
794         return rc;
795 }
796 EXPORT_SYMBOL(lprocfs_filesfree_seq_show);
797
798 int lprocfs_server_uuid_seq_show(struct seq_file *m, void *data)
799 {
800         struct obd_device *obd = data;
801         struct obd_import *imp;
802         char *imp_state_name = NULL;
803         int rc = 0;
804
805         LASSERT(obd != NULL);
806         LPROCFS_CLIMP_CHECK(obd);
807         imp = obd->u.cli.cl_import;
808         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
809         rc = seq_printf(m, "%s\t%s%s\n", obd2cli_tgt(obd), imp_state_name,
810                         imp->imp_deactive ? "\tDEACTIVATED" : "");
811
812         LPROCFS_CLIMP_EXIT(obd);
813         return rc;
814 }
815 EXPORT_SYMBOL(lprocfs_server_uuid_seq_show);
816
817 int lprocfs_conn_uuid_seq_show(struct seq_file *m, void *data)
818 {
819         struct obd_device *obd = data;
820         struct ptlrpc_connection *conn;
821         int rc = 0;
822
823         LASSERT(obd != NULL);
824
825         LPROCFS_CLIMP_CHECK(obd);
826         conn = obd->u.cli.cl_import->imp_connection;
827         if (conn && obd->u.cli.cl_import)
828                 rc = seq_printf(m, "%s\n", conn->c_remote_uuid.uuid);
829         else
830                 rc = seq_printf(m, "%s\n", "<none>");
831
832         LPROCFS_CLIMP_EXIT(obd);
833         return rc;
834 }
835 EXPORT_SYMBOL(lprocfs_conn_uuid_seq_show);
836
837 /** add up per-cpu counters */
838 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
839                            struct lprocfs_counter *cnt)
840 {
841         unsigned int                    num_entry;
842         struct lprocfs_counter          *percpu_cntr;
843         int                             i;
844         unsigned long                   flags = 0;
845
846         memset(cnt, 0, sizeof(*cnt));
847
848         if (stats == NULL) {
849                 /* set count to 1 to avoid divide-by-zero errs in callers */
850                 cnt->lc_count = 1;
851                 return;
852         }
853
854         cnt->lc_min = LC_MIN_INIT;
855
856         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
857
858         for (i = 0; i < num_entry; i++) {
859                 if (stats->ls_percpu[i] == NULL)
860                         continue;
861                 percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
862
863                 cnt->lc_count += percpu_cntr->lc_count;
864                 cnt->lc_sum += percpu_cntr->lc_sum;
865                 if (percpu_cntr->lc_min < cnt->lc_min)
866                         cnt->lc_min = percpu_cntr->lc_min;
867                 if (percpu_cntr->lc_max > cnt->lc_max)
868                         cnt->lc_max = percpu_cntr->lc_max;
869                 cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
870         }
871
872         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
873 }
874 EXPORT_SYMBOL(lprocfs_stats_collect);
875
876 /**
877  * Append a space separated list of current set flags to str.
878  */
879 #define flag2seqstr(flag)                                               \
880         do {                                                            \
881                 if (imp->imp_##flag)                                    \
882                         seq_printf(m, "%s" #flag, first ? "" : ", ");   \
883         } while (0)
884 static int obd_import_flags2seqstr(struct obd_import *imp, struct seq_file *m)
885 {
886         bool first = true;
887
888         if (imp->imp_obd->obd_no_recov) {
889                 seq_printf(m, "no_recov");
890                 first = false;
891         }
892
893         flag2seqstr(invalid);
894         flag2seqstr(deactive);
895         flag2seqstr(replayable);
896         flag2seqstr(pingable);
897         return 0;
898 }
899 #undef flags2seqstr
900
901 static const char *obd_connect_names[] = {
902         "read_only",
903         "lov_index",
904         "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         cfs_atomic_t *atom = data;
1305         LASSERT(atom != NULL);
1306         *eof = 1;
1307         return snprintf(page, count, "%d\n", cfs_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         cfs_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         cfs_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                       cfs_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                       cfs_atomic_read(&imp->imp_inflight),
1614                       cfs_atomic_read(&imp->imp_unregistering),
1615                       cfs_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(cfs_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, unlink);
2386         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
2387         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
2388         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
2389         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
2390         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
2391         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
2392         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
2393         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
2394         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
2395         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
2396         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
2397         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
2398         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
2399         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
2400         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
2401 }
2402 EXPORT_SYMBOL(lprocfs_init_mps_stats);
2403
2404 int lprocfs_alloc_md_stats(struct obd_device *obd,
2405                            unsigned int num_private_stats)
2406 {
2407         struct lprocfs_stats *stats;
2408         unsigned int num_stats;
2409         int rc, i;
2410
2411         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
2412         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
2413         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
2414
2415         /* TODO Ensure that this function is only used where
2416          * appropriate by adding an assertion to the effect that
2417          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
2418          * because mdt_procfs_init() uses this function to allocate
2419          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
2420          * mdt layer does not use the md_ops interface. This is
2421          * confusing and a waste of memory. See LU-2484.
2422          */
2423         LASSERT(obd->obd_proc_entry != NULL);
2424         LASSERT(obd->obd_md_stats == NULL);
2425         LASSERT(obd->obd_md_cntr_base == 0);
2426
2427         num_stats = NUM_MD_STATS + num_private_stats;
2428         stats = lprocfs_alloc_stats(num_stats, 0);
2429         if (stats == NULL)
2430                 return -ENOMEM;
2431
2432         lprocfs_init_mps_stats(num_private_stats, stats);
2433
2434         for (i = num_private_stats; i < num_stats; i++) {
2435                 if (stats->ls_cnt_header[i].lc_name == NULL) {
2436                         CERROR("Missing md_stat initializer md_op "
2437                                "operation at offset %d. Aborting.\n",
2438                                i - num_private_stats);
2439                         LBUG();
2440                 }
2441         }
2442
2443         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
2444         if (rc < 0) {
2445                 lprocfs_free_stats(&stats);
2446         } else {
2447                 obd->obd_md_stats = stats;
2448                 obd->obd_md_cntr_base = num_private_stats;
2449         }
2450
2451         return rc;
2452 }
2453 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2454
2455 void lprocfs_free_md_stats(struct obd_device *obd)
2456 {
2457         struct lprocfs_stats *stats = obd->obd_md_stats;
2458
2459         if (stats != NULL) {
2460                 obd->obd_md_stats = NULL;
2461                 obd->obd_md_cntr_base = 0;
2462                 lprocfs_free_stats(&stats);
2463         }
2464 }
2465 EXPORT_SYMBOL(lprocfs_free_md_stats);
2466
2467 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
2468 {
2469         lprocfs_counter_init(ldlm_stats,
2470                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
2471                              0, "ldlm_enqueue", "reqs");
2472         lprocfs_counter_init(ldlm_stats,
2473                              LDLM_CONVERT - LDLM_FIRST_OPC,
2474                              0, "ldlm_convert", "reqs");
2475         lprocfs_counter_init(ldlm_stats,
2476                              LDLM_CANCEL - LDLM_FIRST_OPC,
2477                              0, "ldlm_cancel", "reqs");
2478         lprocfs_counter_init(ldlm_stats,
2479                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
2480                              0, "ldlm_bl_callback", "reqs");
2481         lprocfs_counter_init(ldlm_stats,
2482                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
2483                              0, "ldlm_cp_callback", "reqs");
2484         lprocfs_counter_init(ldlm_stats,
2485                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
2486                              0, "ldlm_gl_callback", "reqs");
2487 }
2488 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2489
2490 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
2491                          int *eof,  void *data)
2492 {
2493         struct obd_export *exp = data;
2494         LASSERT(exp != NULL);
2495         *eof = 1;
2496         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
2497 }
2498
2499 struct exp_uuid_cb_data {
2500         char                   *page;
2501         int                     count;
2502         int                    *eof;
2503         int                    *len;
2504 };
2505
2506 static void
2507 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
2508                             int count, int *eof, int *len)
2509 {
2510         cb_data->page = page;
2511         cb_data->count = count;
2512         cb_data->eof = eof;
2513         cb_data->len = len;
2514 }
2515
2516 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
2517                            cfs_hlist_node_t *hnode, void *cb_data)
2518
2519 {
2520         struct obd_export *exp = cfs_hash_object(hs, hnode);
2521         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
2522
2523         if (exp->exp_nid_stats)
2524                 *data->len += snprintf((data->page + *data->len),
2525                                        data->count, "%s\n",
2526                                        obd_uuid2str(&exp->exp_client_uuid));
2527         return 0;
2528 }
2529
2530 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
2531                         int *eof,  void *data)
2532 {
2533         struct nid_stat *stats = (struct nid_stat *)data;
2534         struct exp_uuid_cb_data cb_data;
2535         struct obd_device *obd = stats->nid_obd;
2536         int len = 0;
2537
2538         *eof = 1;
2539         page[0] = '\0';
2540         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
2541         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
2542                               lprocfs_exp_print_uuid, &cb_data);
2543         return (*cb_data.len);
2544 }
2545
2546 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
2547                            cfs_hlist_node_t *hnode, void *cb_data)
2548
2549 {
2550         struct exp_uuid_cb_data *data = cb_data;
2551         struct obd_export       *exp = cfs_hash_object(hs, hnode);
2552
2553         if (exp->exp_lock_hash != NULL) {
2554                 if (!*data->len) {
2555                         *data->len += cfs_hash_debug_header(data->page,
2556                                                             data->count);
2557                 }
2558                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
2559                                                  data->count);
2560         }
2561
2562         return 0;
2563 }
2564
2565 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
2566                         int *eof,  void *data)
2567 {
2568         struct nid_stat *stats = (struct nid_stat *)data;
2569         struct exp_uuid_cb_data cb_data;
2570         struct obd_device *obd = stats->nid_obd;
2571         int len = 0;
2572
2573         *eof = 1;
2574         page[0] = '\0';
2575         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
2576
2577         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
2578                               lprocfs_exp_print_hash, &cb_data);
2579         return (*cb_data.len);
2580 }
2581
2582 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
2583                                         int count, int *eof,  void *data)
2584 {
2585         *eof = 1;
2586         return snprintf(page, count, "%s\n",
2587                         "Write into this file to clear all nid stats and "
2588                         "stale nid entries");
2589 }
2590 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
2591
2592 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
2593 {
2594         struct nid_stat *stat = obj;
2595         ENTRY;
2596
2597         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
2598         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
2599                 /* object has only hash references. */
2600                 spin_lock(&stat->nid_obd->obd_nid_lock);
2601                 cfs_list_move(&stat->nid_list, data);
2602                 spin_unlock(&stat->nid_obd->obd_nid_lock);
2603                 RETURN(1);
2604         }
2605         /* we has reference to object - only clear data*/
2606         if (stat->nid_stats)
2607                 lprocfs_clear_stats(stat->nid_stats);
2608
2609         RETURN(0);
2610 }
2611
2612 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
2613                                   unsigned long count, void *data)
2614 {
2615         struct obd_device *obd = (struct obd_device *)data;
2616         struct nid_stat *client_stat;
2617         CFS_LIST_HEAD(free_list);
2618
2619         cfs_hash_cond_del(obd->obd_nid_stats_hash,
2620                           lprocfs_nid_stats_clear_write_cb, &free_list);
2621
2622         while (!cfs_list_empty(&free_list)) {
2623                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
2624                                              nid_list);
2625                 cfs_list_del_init(&client_stat->nid_list);
2626                 lprocfs_free_client_stats(client_stat);
2627         }
2628
2629         return count;
2630 }
2631 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
2632
2633 #ifdef HAVE_SERVER_SUPPORT
2634 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2635 {
2636         struct nid_stat *new_stat, *old_stat;
2637         struct obd_device *obd = NULL;
2638         cfs_proc_dir_entry_t *entry;
2639         char *buffer = NULL;
2640         int rc = 0;
2641         ENTRY;
2642
2643         *newnid = 0;
2644
2645         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2646             !exp->exp_obd->obd_nid_stats_hash)
2647                 RETURN(-EINVAL);
2648
2649         /* not test against zero because eric say:
2650          * You may only test nid against another nid, or LNET_NID_ANY.
2651          * Anything else is nonsense.*/
2652         if (!nid || *nid == LNET_NID_ANY)
2653                 RETURN(0);
2654
2655         spin_lock(&exp->exp_lock);
2656         if (exp->exp_nid_stats != NULL) {
2657                 spin_unlock(&exp->exp_lock);
2658                 RETURN(-EALREADY);
2659         }
2660         spin_unlock(&exp->exp_lock);
2661
2662         obd = exp->exp_obd;
2663
2664         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2665
2666         OBD_ALLOC_PTR(new_stat);
2667         if (new_stat == NULL)
2668                 RETURN(-ENOMEM);
2669
2670         new_stat->nid               = *nid;
2671         new_stat->nid_obd           = exp->exp_obd;
2672         /* we need set default refcount to 1 to balance obd_disconnect */
2673         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
2674
2675         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2676                                            nid, &new_stat->nid_hash);
2677         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2678                old_stat, libcfs_nid2str(*nid),
2679                cfs_atomic_read(&new_stat->nid_exp_ref_count));
2680
2681         /* Return -EALREADY here so that we know that the /proc
2682          * entry already has been created */
2683         if (old_stat != new_stat) {
2684                 nidstat_putref(old_stat);
2685                 GOTO(destroy_new, rc = -EALREADY);
2686         }
2687         /* not found - create */
2688         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2689         if (buffer == NULL)
2690                 GOTO(destroy_new, rc = -ENOMEM);
2691
2692         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2693         new_stat->nid_proc = lprocfs_register(buffer,
2694                                               obd->obd_proc_exports_entry,
2695                                               NULL, NULL);
2696         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2697
2698         if (IS_ERR(new_stat->nid_proc)) {
2699                 rc = PTR_ERR(new_stat->nid_proc);
2700                 new_stat->nid_proc = NULL;
2701                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
2702                        obd->obd_name, libcfs_nid2str(*nid), rc);
2703                 GOTO(destroy_new_ns, rc);
2704         }
2705
2706         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2707                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2708         if (IS_ERR(entry)) {
2709                 CWARN("Error adding the NID stats file\n");
2710                 rc = PTR_ERR(entry);
2711                 GOTO(destroy_new_ns, rc);
2712         }
2713
2714         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2715                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2716         if (IS_ERR(entry)) {
2717                 CWARN("Error adding the hash file\n");
2718                 rc = PTR_ERR(entry);
2719                 GOTO(destroy_new_ns, rc);
2720         }
2721
2722         spin_lock(&exp->exp_lock);
2723         exp->exp_nid_stats = new_stat;
2724         spin_unlock(&exp->exp_lock);
2725         *newnid = 1;
2726         /* protect competitive add to list, not need locking on destroy */
2727         spin_lock(&obd->obd_nid_lock);
2728         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2729         spin_unlock(&obd->obd_nid_lock);
2730
2731         RETURN(rc);
2732
2733 destroy_new_ns:
2734         if (new_stat->nid_proc != NULL)
2735                 lprocfs_remove(&new_stat->nid_proc);
2736         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2737
2738 destroy_new:
2739         nidstat_putref(new_stat);
2740         OBD_FREE_PTR(new_stat);
2741         RETURN(rc);
2742 }
2743 EXPORT_SYMBOL(lprocfs_exp_setup);
2744 #endif
2745
2746 int lprocfs_exp_cleanup(struct obd_export *exp)
2747 {
2748         struct nid_stat *stat = exp->exp_nid_stats;
2749
2750         if(!stat || !exp->exp_obd)
2751                 RETURN(0);
2752
2753         nidstat_putref(exp->exp_nid_stats);
2754         exp->exp_nid_stats = NULL;
2755
2756         return 0;
2757 }
2758 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2759
2760 __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
2761                           struct lprocfs_counter_header *header,
2762                           enum lprocfs_stats_flags flags,
2763                           enum lprocfs_fields_flags field)
2764 {
2765         __s64 ret = 0;
2766
2767         if (lc == NULL || header == NULL)
2768                 RETURN(0);
2769
2770         switch (field) {
2771                 case LPROCFS_FIELDS_FLAGS_CONFIG:
2772                         ret = header->lc_config;
2773                         break;
2774                 case LPROCFS_FIELDS_FLAGS_SUM:
2775                         ret = lc->lc_sum;
2776                         if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
2777                                 ret += lc->lc_sum_irq;
2778                         break;
2779                 case LPROCFS_FIELDS_FLAGS_MIN:
2780                         ret = lc->lc_min;
2781                         break;
2782                 case LPROCFS_FIELDS_FLAGS_MAX:
2783                         ret = lc->lc_max;
2784                         break;
2785                 case LPROCFS_FIELDS_FLAGS_AVG:
2786                         ret = (lc->lc_max - lc->lc_min) / 2;
2787                         break;
2788                 case LPROCFS_FIELDS_FLAGS_SUMSQUARE:
2789                         ret = lc->lc_sumsquare;
2790                         break;
2791                 case LPROCFS_FIELDS_FLAGS_COUNT:
2792                         ret = lc->lc_count;
2793                         break;
2794                 default:
2795                         break;
2796         };
2797         RETURN(ret);
2798 }
2799 EXPORT_SYMBOL(lprocfs_read_helper);
2800
2801 int lprocfs_write_helper(const char *buffer, unsigned long count,
2802                          int *val)
2803 {
2804         return lprocfs_write_frac_helper(buffer, count, val, 1);
2805 }
2806 EXPORT_SYMBOL(lprocfs_write_helper);
2807
2808 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2809                               int *val, int mult)
2810 {
2811         char kernbuf[20], *end, *pbuf;
2812
2813         if (count > (sizeof(kernbuf) - 1))
2814                 return -EINVAL;
2815
2816         if (copy_from_user(kernbuf, buffer, count))
2817                 return -EFAULT;
2818
2819         kernbuf[count] = '\0';
2820         pbuf = kernbuf;
2821         if (*pbuf == '-') {
2822                 mult = -mult;
2823                 pbuf++;
2824         }
2825
2826         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2827         if (pbuf == end)
2828                 return -EINVAL;
2829
2830         if (end != NULL && *end == '.') {
2831                 int temp_val, pow = 1;
2832                 int i;
2833
2834                 pbuf = end + 1;
2835                 if (strlen(pbuf) > 5)
2836                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2837
2838                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2839
2840                 if (pbuf < end) {
2841                         for (i = 0; i < (end - pbuf); i++)
2842                                 pow *= 10;
2843
2844                         *val += temp_val / pow;
2845                 }
2846         }
2847         return 0;
2848 }
2849 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2850
2851 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2852                              int mult)
2853 {
2854         long decimal_val, frac_val;
2855         int prtn;
2856
2857         if (count < 10)
2858                 return -EINVAL;
2859
2860         decimal_val = val / mult;
2861         prtn = snprintf(buffer, count, "%ld", decimal_val);
2862         frac_val = val % mult;
2863
2864         if (prtn < (count - 4) && frac_val > 0) {
2865                 long temp_frac;
2866                 int i, temp_mult = 1, frac_bits = 0;
2867
2868                 temp_frac = frac_val * 10;
2869                 buffer[prtn++] = '.';
2870                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2871                         /* only reserved 2 bits fraction */
2872                         buffer[prtn++] ='0';
2873                         temp_frac *= 10;
2874                         frac_bits++;
2875                 }
2876                 /*
2877                  * Need to think these cases :
2878                  *      1. #echo x.00 > /proc/xxx       output result : x
2879                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2880                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2881                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2882                  *      Only reserved 2 bits fraction.
2883                  */
2884                 for (i = 0; i < (5 - prtn); i++)
2885                         temp_mult *= 10;
2886
2887                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2888                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2889                                  frac_val * temp_mult / mult);
2890
2891                 prtn--;
2892                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2893                         prtn--;
2894                         if (buffer[prtn] == '.') {
2895                                 prtn--;
2896                                 break;
2897                         }
2898                 }
2899                 prtn++;
2900         }
2901         buffer[prtn++] ='\n';
2902         return prtn;
2903 }
2904 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2905
2906 int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
2907 {
2908         long decimal_val, frac_val;
2909
2910         decimal_val = val / mult;
2911         seq_printf(m, "%ld", decimal_val);
2912         frac_val = val % mult;
2913
2914         if (frac_val > 0) {
2915                 frac_val *= 100;
2916                 frac_val /= mult;
2917         }
2918         if (frac_val > 0) {
2919                 /* Three cases: x0, xx, 0x */
2920                 if ((frac_val % 10) != 0)
2921                         seq_printf(m, ".%ld", frac_val);
2922                 else
2923                         seq_printf(m, ".%ld", frac_val / 10);
2924         }
2925
2926         seq_printf(m, "\n");
2927         return 0;
2928 }
2929 EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
2930
2931 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2932 {
2933         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2934 }
2935 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2936
2937 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2938                               __u64 *val, int mult)
2939 {
2940         char kernbuf[22], *end, *pbuf;
2941         __u64 whole, frac = 0, units;
2942         unsigned frac_d = 1;
2943
2944         if (count > (sizeof(kernbuf) - 1))
2945                 return -EINVAL;
2946
2947         if (copy_from_user(kernbuf, buffer, count))
2948                 return -EFAULT;
2949
2950         kernbuf[count] = '\0';
2951         pbuf = kernbuf;
2952         if (*pbuf == '-') {
2953                 mult = -mult;
2954                 pbuf++;
2955         }
2956
2957         whole = simple_strtoull(pbuf, &end, 10);
2958         if (pbuf == end)
2959                 return -EINVAL;
2960
2961         if (end != NULL && *end == '.') {
2962                 int i;
2963                 pbuf = end + 1;
2964
2965                 /* need to limit frac_d to a __u32 */
2966                 if (strlen(pbuf) > 10)
2967                         pbuf[10] = '\0';
2968
2969                 frac = simple_strtoull(pbuf, &end, 10);
2970                 /* count decimal places */
2971                 for (i = 0; i < (end - pbuf); i++)
2972                         frac_d *= 10;
2973         }
2974
2975         units = 1;
2976         if (end != NULL) {
2977                 switch (*end) {
2978                 case 'p': case 'P':
2979                         units <<= 10;
2980                 case 't': case 'T':
2981                         units <<= 10;
2982                 case 'g': case 'G':
2983                         units <<= 10;
2984                 case 'm': case 'M':
2985                         units <<= 10;
2986                 case 'k': case 'K':
2987                         units <<= 10;
2988                 }
2989         }
2990         /* Specified units override the multiplier */
2991         if (units)
2992                 mult = mult < 0 ? -units : units;
2993
2994         frac *= mult;
2995         do_div(frac, frac_d);
2996         *val = whole * mult + frac;
2997         return 0;
2998 }
2999 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
3000
3001 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
3002 {
3003         size_t l2;
3004
3005         l2 = strlen(s2);
3006         if (!l2)
3007                 return (char *)s1;
3008         while (len >= l2) {
3009                 len--;
3010                 if (!memcmp(s1, s2, l2))
3011                         return (char *)s1;
3012                 s1++;
3013         }
3014         return NULL;
3015 }
3016
3017 /**
3018  * Find the string \a name in the input \a buffer, and return a pointer to the
3019  * value immediately following \a name, reducing \a count appropriately.
3020  * If \a name is not found the original \a buffer is returned.
3021  */
3022 char *lprocfs_find_named_value(const char *buffer, const char *name,
3023                                 size_t *count)
3024 {
3025         char *val;
3026         size_t buflen = *count;
3027
3028         /* there is no strnstr() in rhel5 and ubuntu kernels */
3029         val = lprocfs_strnstr(buffer, name, buflen);
3030         if (val == NULL)
3031                 return (char *)buffer;
3032
3033         val += strlen(name);                             /* skip prefix */
3034         while (val < buffer + buflen && isspace(*val)) /* skip separator */
3035                 val++;
3036
3037         *count = 0;
3038         while (val < buffer + buflen && isalnum(*val)) {
3039                 ++*count;
3040                 ++val;
3041         }
3042
3043         return val - *count;
3044 }
3045 EXPORT_SYMBOL(lprocfs_find_named_value);
3046
3047 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
3048                        const char *name,
3049                        mode_t mode,
3050                        const struct file_operations *seq_fops,
3051                        void *data)
3052 {
3053         struct proc_dir_entry *entry;
3054         ENTRY;
3055
3056         /* Disallow secretly (un)writable entries. */
3057         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
3058
3059         entry = proc_create_data(name, mode, parent, seq_fops, data);
3060
3061         if (entry == NULL)
3062                 RETURN(-ENOMEM);
3063
3064         RETURN(0);
3065 }
3066 EXPORT_SYMBOL(lprocfs_seq_create);
3067
3068 int lprocfs_obd_seq_create(struct obd_device *dev,
3069                            const char *name,
3070                            mode_t mode,
3071                            const struct file_operations *seq_fops,
3072                            void *data)
3073 {
3074         return (lprocfs_seq_create(dev->obd_proc_entry, name,
3075                                    mode, seq_fops, data));
3076 }
3077 EXPORT_SYMBOL(lprocfs_obd_seq_create);
3078
3079 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
3080 {
3081         if (value >= OBD_HIST_MAX)
3082                 value = OBD_HIST_MAX - 1;
3083
3084         spin_lock(&oh->oh_lock);
3085         oh->oh_buckets[value]++;
3086         spin_unlock(&oh->oh_lock);
3087 }
3088 EXPORT_SYMBOL(lprocfs_oh_tally);
3089
3090 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
3091 {
3092         unsigned int val = 0;
3093
3094         if (likely(value != 0))
3095                 val = min(fls(value - 1), OBD_HIST_MAX);
3096
3097         lprocfs_oh_tally(oh, val);
3098 }
3099 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
3100
3101 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
3102 {
3103         unsigned long ret = 0;
3104         int i;
3105
3106         for (i = 0; i < OBD_HIST_MAX; i++)
3107                 ret +=  oh->oh_buckets[i];
3108         return ret;
3109 }
3110 EXPORT_SYMBOL(lprocfs_oh_sum);
3111
3112 void lprocfs_oh_clear(struct obd_histogram *oh)
3113 {
3114         spin_lock(&oh->oh_lock);
3115         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
3116         spin_unlock(&oh->oh_lock);
3117 }
3118 EXPORT_SYMBOL(lprocfs_oh_clear);
3119
3120 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
3121                         int count, int *eof, void *data)
3122 {
3123         struct obd_device *obd = data;
3124         int c = 0;
3125
3126         if (obd == NULL)
3127                 return 0;
3128
3129         c += cfs_hash_debug_header(page, count);
3130         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
3131         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
3132         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
3133
3134         return c;
3135 }
3136 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
3137
3138 #ifdef HAVE_SERVER_SUPPORT
3139 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
3140                                    int count, int *eof, void *data)
3141 {
3142         struct obd_device *obd = data;
3143         int len = 0, size;
3144
3145         LASSERT(obd != NULL);
3146         LASSERT(count >= 0);
3147
3148         /* Set start of user data returned to
3149            page + off since the user may have
3150            requested to read much smaller than
3151            what we need to read */
3152         *start = page + off;
3153
3154         /*
3155          * We know we are allocated a page here.
3156          * Also we know that this function will
3157          * not need to write more than a page
3158          * so we can truncate at PAGE_CACHE_SIZE.
3159          */
3160         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
3161
3162         /* Initialize the page */
3163         memset(page, 0, size);
3164
3165         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
3166                 goto out;
3167         if (obd->obd_max_recoverable_clients == 0) {
3168                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
3169                         goto out;
3170
3171                 goto fclose;
3172         }
3173
3174         /* sampled unlocked, but really... */
3175         if (obd->obd_recovering == 0) {
3176                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
3177                         goto out;
3178                 if (lprocfs_obd_snprintf(&page, size, &len,
3179                                          "recovery_start: %lu\n",
3180                                          obd->obd_recovery_start) <= 0)
3181                         goto out;
3182                 if (lprocfs_obd_snprintf(&page, size, &len,
3183                                          "recovery_duration: %lu\n",
3184                                          obd->obd_recovery_end -
3185                                          obd->obd_recovery_start) <= 0)
3186                         goto out;
3187                 /* Number of clients that have completed recovery */
3188                 if (lprocfs_obd_snprintf(&page, size, &len,
3189                                          "completed_clients: %d/%d\n",
3190                                          obd->obd_max_recoverable_clients -
3191                                          obd->obd_stale_clients,
3192                                          obd->obd_max_recoverable_clients) <= 0