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