Whamcloud - gitweb
LU-3906 tests: fix space estimation codes in run_compilebench()
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lprocfs_status.c
37  *
38  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
39  */
40
41 #define DEBUG_SUBSYSTEM S_CLASS
42
43 #ifndef __KERNEL__
44 # include <liblustre.h>
45 #endif
46
47 #include <obd_class.h>
48 #include <lprocfs_status.h>
49 #include <lustre/lustre_idl.h>
50
51 #if defined(LPROCFS)
52
53 static int lprocfs_no_percpu_stats = 0;
54 CFS_MODULE_PARM(lprocfs_no_percpu_stats, "i", int, 0644,
55                 "Do not alloc percpu data for lprocfs stats");
56
57 #define MAX_STRING_SIZE 128
58
59 /* for bug 10866, global variable */
60 DECLARE_RWSEM(_lprocfs_lock);
61 EXPORT_SYMBOL(_lprocfs_lock);
62
63 int lprocfs_single_release(struct inode *inode, struct file *file)
64 {
65         return single_release(inode, file);
66 }
67 EXPORT_SYMBOL(lprocfs_single_release);
68
69 int lprocfs_seq_release(struct inode *inode, struct file *file)
70 {
71         return seq_release(inode, file);
72 }
73 EXPORT_SYMBOL(lprocfs_seq_release);
74
75 static struct proc_dir_entry *__lprocfs_srch(struct proc_dir_entry *head,
76                                              const char *name)
77 {
78         struct proc_dir_entry *temp;
79
80         if (head == NULL)
81                 return NULL;
82
83         temp = head->subdir;
84         while (temp != NULL) {
85                 if (strcmp(temp->name, name) == 0) {
86                         return temp;
87                 }
88
89                 temp = temp->next;
90         }
91         return NULL;
92 }
93
94 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
95                                     const char *name)
96 {
97         struct proc_dir_entry *temp;
98
99         LPROCFS_SRCH_ENTRY();
100         temp = __lprocfs_srch(head, name);
101         LPROCFS_SRCH_EXIT();
102         return temp;
103 }
104 EXPORT_SYMBOL(lprocfs_srch);
105
106 /* lprocfs API calls */
107
108 /* Function that emulates snprintf but also has the side effect of advancing
109    the page pointer for the next write into the buffer, incrementing the total
110    length written to the buffer, and decrementing the size left in the
111    buffer. */
112 static int lprocfs_obd_snprintf(char **page, int end, int *len,
113                                 const char *format, ...)
114 {
115         va_list list;
116         int n;
117
118         if (*len >= end)
119                 return 0;
120
121         va_start(list, format);
122         n = vsnprintf(*page, end - *len, format, list);
123         va_end(list);
124
125         *page += n; *len += n;
126         return n;
127 }
128
129 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
130                                          char *name,
131                                          read_proc_t *read_proc,
132                                          write_proc_t *write_proc,
133                                          void *data,
134                                          struct file_operations *fops)
135 {
136         cfs_proc_dir_entry_t *proc;
137         mode_t mode = 0;
138
139         if (root == NULL || name == NULL)
140                 return ERR_PTR(-EINVAL);
141         if (read_proc)
142                 mode = 0444;
143         if (write_proc)
144                 mode |= 0200;
145         if (fops)
146                 mode = 0644;
147         LPROCFS_WRITE_ENTRY();
148         proc = create_proc_entry(name, mode, root);
149         if (!proc) {
150                 CERROR("LprocFS: No memory to create /proc entry %s", name);
151                 LPROCFS_WRITE_EXIT();
152                 return ERR_PTR(-ENOMEM);
153         }
154         proc->read_proc = read_proc;
155         proc->write_proc = write_proc;
156         proc->data = data;
157         if (fops)
158                 proc->proc_fops = fops;
159         LPROCFS_WRITE_EXIT();
160         return proc;
161 }
162 EXPORT_SYMBOL(lprocfs_add_simple);
163
164 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
165                         struct proc_dir_entry *parent, const char *format, ...)
166 {
167         struct proc_dir_entry *entry;
168         char *dest;
169         va_list ap;
170
171         if (parent == NULL || format == NULL)
172                 return NULL;
173
174         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
175         if (dest == NULL)
176                 return NULL;
177
178         va_start(ap, format);
179         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
180         va_end(ap);
181
182         entry = proc_symlink(name, parent, dest);
183         if (entry == NULL)
184                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
185                         name, dest);
186
187         OBD_FREE(dest, MAX_STRING_SIZE + 1);
188         return entry;
189 }
190 EXPORT_SYMBOL(lprocfs_add_symlink);
191
192 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
193                                  size_t size, loff_t *ppos)
194 {
195         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
196         char *page, *start = NULL;
197         int rc = 0, eof = 1, count;
198
199         if (*ppos >= PAGE_CACHE_SIZE)
200                 return 0;
201
202         page = (char *)__get_free_page(GFP_KERNEL);
203         if (page == NULL)
204                 return -ENOMEM;
205
206         if (LPROCFS_ENTRY_CHECK(dp)) {
207                 rc = -ENOENT;
208                 goto out;
209         }
210
211         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
212         if (dp->read_proc)
213                 rc = dp->read_proc(page, &start, *ppos, PAGE_CACHE_SIZE,
214                                    &eof, dp->data);
215         if (rc <= 0)
216                 goto out;
217
218         /* for lustre proc read, the read count must be less than PAGE_SIZE */
219         LASSERT(eof == 1);
220
221         if (start == NULL) {
222                 rc -= *ppos;
223                 if (rc < 0)
224                         rc = 0;
225                 if (rc == 0)
226                         goto out;
227                 start = page + *ppos;
228         } else if (start < page) {
229                 start = page;
230         }
231
232         count = (rc < size) ? rc : size;
233         if (copy_to_user(buf, start, count)) {
234                 rc = -EFAULT;
235                 goto out;
236         }
237         *ppos += count;
238
239 out:
240         free_page((unsigned long)page);
241         return rc;
242 }
243
244 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf,
245                                   size_t size, loff_t *ppos)
246 {
247         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
248         int rc = -EIO;
249
250         if (LPROCFS_ENTRY_CHECK(dp))
251                 return -ENOENT;
252         if (dp->write_proc)
253                 rc = dp->write_proc(f, buf, size, dp->data);
254         return rc;
255 }
256
257 static struct file_operations lprocfs_generic_fops = {
258         .owner = THIS_MODULE,
259         .read = lprocfs_fops_read,
260         .write = lprocfs_fops_write,
261 };
262
263 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
264 {
265         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
266         struct obd_device *obd = dp->data;
267
268         cfs_atomic_inc(&obd->obd_evict_inprogress);
269
270         return 0;
271 }
272
273 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
274 {
275         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
276         struct obd_device *obd = dp->data;
277
278         cfs_atomic_dec(&obd->obd_evict_inprogress);
279         wake_up(&obd->obd_evict_inprogress_waitq);
280
281         return 0;
282 }
283
284 struct file_operations lprocfs_evict_client_fops = {
285         .owner = THIS_MODULE,
286         .read = lprocfs_fops_read,
287         .write = lprocfs_fops_write,
288         .open = lprocfs_evict_client_open,
289         .release = lprocfs_evict_client_release,
290 };
291 EXPORT_SYMBOL(lprocfs_evict_client_fops);
292
293 static int __lprocfs_add_vars(struct proc_dir_entry *root,
294                               struct lprocfs_vars *list,
295                               void *data)
296 {
297         int rc = 0;
298
299         if (root == NULL || list == NULL)
300                 return -EINVAL;
301
302         while (list->name != NULL) {
303                 struct proc_dir_entry *cur_root, *proc;
304                 char *pathcopy, *cur, *next, pathbuf[64];
305                 int pathsize = strlen(list->name) + 1;
306
307                 proc = NULL;
308                 cur_root = root;
309
310                 /* need copy of path for strsep */
311                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
312                         OBD_ALLOC(pathcopy, pathsize);
313                         if (pathcopy == NULL)
314                                 GOTO(out, rc = -ENOMEM);
315                 } else {
316                         pathcopy = pathbuf;
317                 }
318
319                 next = pathcopy;
320                 strcpy(pathcopy, list->name);
321
322                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
323                         if (*cur =='\0') /* skip double/trailing "/" */
324                                 continue;
325
326                         proc = __lprocfs_srch(cur_root, cur);
327                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
328                                cur_root->name, cur, next,
329                                (proc ? "exists" : "new"));
330                         if (next != NULL) {
331                                 cur_root = (proc ? proc :
332                                             proc_mkdir(cur, cur_root));
333                         } else if (proc == NULL) {
334                                 mode_t mode = 0;
335                                 if (list->proc_mode != 0000) {
336                                         mode = list->proc_mode;
337                                 } else {
338                                         if (list->read_fptr)
339                                                 mode = 0444;
340                                         if (list->write_fptr)
341                                                 mode |= 0200;
342                                 }
343                                 proc = create_proc_entry(cur, mode, cur_root);
344                         }
345                 }
346
347                 if (pathcopy != pathbuf)
348                         OBD_FREE(pathcopy, pathsize);
349
350                 if (cur_root == NULL || proc == NULL) {
351                         CERROR("LprocFS: No memory to create /proc entry %s",
352                                list->name);
353                         GOTO(out, rc = -ENOMEM);
354                 }
355
356                 if (list->fops)
357                         proc->proc_fops = list->fops;
358                 else
359                         proc->proc_fops = &lprocfs_generic_fops;
360                 proc->read_proc = list->read_fptr;
361                 proc->write_proc = list->write_fptr;
362                 proc->data = (list->data ? list->data : data);
363                 list++;
364         }
365 out:
366         return rc;
367 }
368
369 /**
370  * Add /proc entries.
371  *
372  * \param root [in]  The parent proc entry on which new entry will be added.
373  * \param list [in]  Array of proc entries to be added.
374  * \param data [in]  The argument to be passed when entries read/write routines
375  *                   are called through /proc file.
376  *
377  * \retval 0   on success
378  *         < 0 on error
379  */
380 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
381                      void *data)
382 {
383         int rc;
384
385         LPROCFS_WRITE_ENTRY();
386         rc = __lprocfs_add_vars(root, list, data);
387         LPROCFS_WRITE_EXIT();
388
389         return rc;
390 }
391 EXPORT_SYMBOL(lprocfs_add_vars);
392
393 void lprocfs_remove_nolock(struct proc_dir_entry **proot)
394 {
395         struct proc_dir_entry *root = *proot;
396         struct proc_dir_entry *temp = root;
397         struct proc_dir_entry *rm_entry;
398         struct proc_dir_entry *parent;
399
400         *proot = NULL;
401         if (root == NULL || IS_ERR(root))
402                 return;
403
404         parent = root->parent;
405         LASSERT(parent != NULL);
406
407         while (1) {
408                 while (temp->subdir != NULL)
409                         temp = temp->subdir;
410
411                 rm_entry = temp;
412                 temp = temp->parent;
413
414                 /* Memory corruption once caused this to fail, and
415                    without this LASSERT we would loop here forever. */
416                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
417                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
418                          rm_entry->name, (int)strlen(rm_entry->name));
419
420                 remove_proc_entry(rm_entry->name, temp);
421                 if (temp == parent)
422                         break;
423         }
424 }
425
426 void lprocfs_remove(struct proc_dir_entry **rooth)
427 {
428         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
429         lprocfs_remove_nolock(rooth);
430         LPROCFS_WRITE_EXIT();
431 }
432 EXPORT_SYMBOL(lprocfs_remove);
433
434 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
435 {
436         LASSERT(parent != NULL);
437         remove_proc_entry(name, parent);
438 }
439 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
440
441 void lprocfs_try_remove_proc_entry(const char *name,
442                                    struct proc_dir_entry *parent)
443 {
444         struct proc_dir_entry    *t = NULL;
445         struct proc_dir_entry   **p;
446         int                       len, busy = 0;
447
448         LASSERT(parent != NULL);
449         len = strlen(name);
450
451         LPROCFS_WRITE_ENTRY();
452
453         /* lookup target name */
454         for (p = &parent->subdir; *p; p = &(*p)->next) {
455                 if ((*p)->namelen != len)
456                         continue;
457                 if (memcmp(name, (*p)->name, len))
458                         continue;
459                 t = *p;
460                 break;
461         }
462
463         if (t) {
464                 /* verify it's empty: do not count "num_refs" */
465                 for (p = &t->subdir; *p; p = &(*p)->next) {
466                         if ((*p)->namelen != strlen("num_refs")) {
467                                 busy = 1;
468                                 break;
469                         }
470                         if (memcmp("num_refs", (*p)->name,
471                                    strlen("num_refs"))) {
472                                 busy = 1;
473                                 break;
474                         }
475                 }
476         }
477
478         if (busy == 0)
479                 lprocfs_remove_nolock(&t);
480
481         LPROCFS_WRITE_EXIT();
482
483         return;
484 }
485 EXPORT_SYMBOL(lprocfs_try_remove_proc_entry);
486
487 struct proc_dir_entry *lprocfs_register(const char *name,
488                                         struct proc_dir_entry *parent,
489                                         struct lprocfs_vars *list, void *data)
490 {
491         struct proc_dir_entry *entry;
492         int rc;
493
494         LPROCFS_WRITE_ENTRY();
495         entry = __lprocfs_srch(parent, name);
496         if (entry != NULL) {
497                 CERROR("entry '%s' already registered\n", name);
498                 GOTO(out, entry = ERR_PTR(-EALREADY));
499         }
500
501         entry = proc_mkdir(name, parent);
502         if (entry == NULL)
503                 GOTO(out, entry = ERR_PTR(-ENOMEM));
504
505         if (list != NULL) {
506                 rc = __lprocfs_add_vars(entry, list, data);
507                 if (rc != 0) {
508                         lprocfs_remove_nolock(&entry);
509                         GOTO(out, entry = ERR_PTR(rc));
510                 }
511         }
512 out:
513         LPROCFS_WRITE_EXIT();
514
515         return entry;
516 }
517 EXPORT_SYMBOL(lprocfs_register);
518
519 /* Generic callbacks */
520 int lprocfs_rd_uint(char *page, char **start, off_t off,
521                     int count, int *eof, void *data)
522 {
523         unsigned int *temp = data;
524         return snprintf(page, count, "%u\n", *temp);
525 }
526 EXPORT_SYMBOL(lprocfs_rd_uint);
527
528 int lprocfs_wr_uint(struct file *file, const char *buffer,
529                     unsigned long count, void *data)
530 {
531         unsigned *p = data;
532         char dummy[MAX_STRING_SIZE + 1], *end;
533         unsigned long tmp;
534
535         dummy[MAX_STRING_SIZE] = '\0';
536         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
537                 return -EFAULT;
538
539         tmp = simple_strtoul(dummy, &end, 0);
540         if (dummy == end)
541                 return -EINVAL;
542
543         *p = (unsigned int)tmp;
544         return count;
545 }
546 EXPORT_SYMBOL(lprocfs_wr_uint);
547
548 int lprocfs_rd_u64(char *page, char **start, off_t off,
549                    int count, int *eof, void *data)
550 {
551         LASSERT(data != NULL);
552         *eof = 1;
553         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
554 }
555 EXPORT_SYMBOL(lprocfs_rd_u64);
556
557 int lprocfs_rd_atomic(char *page, char **start, off_t off,
558                    int count, int *eof, void *data)
559 {
560         cfs_atomic_t *atom = data;
561         LASSERT(atom != NULL);
562         *eof = 1;
563         return snprintf(page, count, "%d\n", cfs_atomic_read(atom));
564 }
565 EXPORT_SYMBOL(lprocfs_rd_atomic);
566
567 int lprocfs_wr_atomic(struct file *file, const char *buffer,
568                       unsigned long count, void *data)
569 {
570         cfs_atomic_t *atm = data;
571         int val = 0;
572         int rc;
573
574         rc = lprocfs_write_helper(buffer, count, &val);
575         if (rc < 0)
576                 return rc;
577
578         if (val <= 0)
579                 return -ERANGE;
580
581         cfs_atomic_set(atm, val);
582         return count;
583 }
584 EXPORT_SYMBOL(lprocfs_wr_atomic);
585
586 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
587                     int *eof, void *data)
588 {
589         struct obd_device *obd = data;
590
591         LASSERT(obd != NULL);
592         *eof = 1;
593         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
594 }
595 EXPORT_SYMBOL(lprocfs_rd_uuid);
596
597 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
598                     int *eof, void *data)
599 {
600         struct obd_device *dev = data;
601
602         LASSERT(dev != NULL);
603         *eof = 1;
604         return snprintf(page, count, "%s\n", dev->obd_name);
605 }
606 EXPORT_SYMBOL(lprocfs_rd_name);
607
608 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
609                        int *eof, void *data)
610 {
611         struct obd_device *obd = data;
612         struct obd_statfs  osfs;
613         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
614                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
615                             OBD_STATFS_NODELAY);
616         if (!rc) {
617                 *eof = 1;
618                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
619         }
620         return rc;
621 }
622 EXPORT_SYMBOL(lprocfs_rd_blksize);
623
624 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
625                            int *eof, void *data)
626 {
627         struct obd_device *obd = data;
628         struct obd_statfs  osfs;
629         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
630                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
631                             OBD_STATFS_NODELAY);
632         if (!rc) {
633                 __u32 blk_size = osfs.os_bsize >> 10;
634                 __u64 result = osfs.os_blocks;
635
636                 while (blk_size >>= 1)
637                         result <<= 1;
638
639                 *eof = 1;
640                 rc = snprintf(page, count, LPU64"\n", result);
641         }
642         return rc;
643 }
644 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
645
646 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
647                           int *eof, void *data)
648 {
649         struct obd_device *obd = data;
650         struct obd_statfs  osfs;
651         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
652                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
653                             OBD_STATFS_NODELAY);
654         if (!rc) {
655                 __u32 blk_size = osfs.os_bsize >> 10;
656                 __u64 result = osfs.os_bfree;
657
658                 while (blk_size >>= 1)
659                         result <<= 1;
660
661                 *eof = 1;
662                 rc = snprintf(page, count, LPU64"\n", result);
663         }
664         return rc;
665 }
666 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
667
668 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
669                            int *eof, void *data)
670 {
671         struct obd_device *obd = data;
672         struct obd_statfs  osfs;
673         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
674                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
675                             OBD_STATFS_NODELAY);
676         if (!rc) {
677                 __u32 blk_size = osfs.os_bsize >> 10;
678                 __u64 result = osfs.os_bavail;
679
680                 while (blk_size >>= 1)
681                         result <<= 1;
682
683                 *eof = 1;
684                 rc = snprintf(page, count, LPU64"\n", result);
685         }
686         return rc;
687 }
688 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
689
690 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
691                           int *eof, void *data)
692 {
693         struct obd_device *obd = data;
694         struct obd_statfs  osfs;
695         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
696                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
697                             OBD_STATFS_NODELAY);
698         if (!rc) {
699                 *eof = 1;
700                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
701         }
702
703         return rc;
704 }
705 EXPORT_SYMBOL(lprocfs_rd_filestotal);
706
707 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
708                          int *eof, void *data)
709 {
710         struct obd_device *obd = data;
711         struct obd_statfs  osfs;
712         int rc = obd_statfs(NULL, obd->obd_self_export, &osfs,
713                             cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
714                             OBD_STATFS_NODELAY);
715         if (!rc) {
716                 *eof = 1;
717                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
718         }
719         return rc;
720 }
721 EXPORT_SYMBOL(lprocfs_rd_filesfree);
722
723 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
724                            int *eof, void *data)
725 {
726         struct obd_device *obd = data;
727         struct obd_import *imp;
728         char *imp_state_name = NULL;
729         int rc = 0;
730
731         LASSERT(obd != NULL);
732         LPROCFS_CLIMP_CHECK(obd);
733         imp = obd->u.cli.cl_import;
734         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
735         *eof = 1;
736         rc = snprintf(page, count, "%s\t%s%s\n",
737                       obd2cli_tgt(obd), imp_state_name,
738                       imp->imp_deactive ? "\tDEACTIVATED" : "");
739
740         LPROCFS_CLIMP_EXIT(obd);
741         return rc;
742 }
743 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
744
745 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
746                          int *eof,  void *data)
747 {
748         struct obd_device *obd = data;
749         struct ptlrpc_connection *conn;
750         int rc = 0;
751
752         LASSERT(obd != NULL);
753
754         LPROCFS_CLIMP_CHECK(obd);
755         conn = obd->u.cli.cl_import->imp_connection;
756         *eof = 1;
757         if (conn && obd->u.cli.cl_import) {
758                 rc = snprintf(page, count, "%s\n",
759                               conn->c_remote_uuid.uuid);
760         } else {
761                 rc = snprintf(page, count, "%s\n", "<none>");
762         }
763
764         LPROCFS_CLIMP_EXIT(obd);
765         return rc;
766 }
767 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
768
769 /** add up per-cpu counters */
770 void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx,
771                            struct lprocfs_counter *cnt)
772 {
773         unsigned int                    num_entry;
774         struct lprocfs_counter          *percpu_cntr;
775         int                             i;
776         unsigned long                   flags = 0;
777
778         memset(cnt, 0, sizeof(*cnt));
779
780         if (stats == NULL) {
781                 /* set count to 1 to avoid divide-by-zero errs in callers */
782                 cnt->lc_count = 1;
783                 return;
784         }
785
786         cnt->lc_min = LC_MIN_INIT;
787
788         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
789
790         for (i = 0; i < num_entry; i++) {
791                 if (stats->ls_percpu[i] == NULL)
792                         continue;
793                 percpu_cntr = lprocfs_stats_counter_get(stats, i, idx);
794
795                 cnt->lc_count += percpu_cntr->lc_count;
796                 cnt->lc_sum += percpu_cntr->lc_sum;
797                 if (percpu_cntr->lc_min < cnt->lc_min)
798                         cnt->lc_min = percpu_cntr->lc_min;
799                 if (percpu_cntr->lc_max > cnt->lc_max)
800                         cnt->lc_max = percpu_cntr->lc_max;
801                 cnt->lc_sumsquare += percpu_cntr->lc_sumsquare;
802         }
803
804         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
805 }
806 EXPORT_SYMBOL(lprocfs_stats_collect);
807
808 /**
809  * Append a space separated list of current set flags to str.
810  */
811 #define flag2str(flag) \
812         if (imp->imp_##flag && max - len > 0) \
813              len += snprintf(str + len, max - len, "%s" #flag, len ? ", " : "");
814 static int obd_import_flags2str(struct obd_import *imp, char *str, int max)
815 {
816         int len = 0;
817
818         if (imp->imp_obd->obd_no_recov)
819                 len += snprintf(str, max - len, "no_recov");
820
821         flag2str(invalid);
822         flag2str(deactive);
823         flag2str(replayable);
824         flag2str(pingable);
825         return len;
826 }
827 #undef flags2str
828
829 static const char *obd_connect_names[] = {
830         "read_only",
831         "lov_index",
832         "unused",
833         "write_grant",
834         "server_lock",
835         "version",
836         "request_portal",
837         "acl",
838         "xattr",
839         "create_on_write",
840         "truncate_lock",
841         "initial_transno",
842         "inode_bit_locks",
843         "join_file(obsolete)",
844         "getattr_by_fid",
845         "no_oh_for_devices",
846         "remote_client",
847         "remote_client_by_force",
848         "max_byte_per_rpc",
849         "64bit_qdata",
850         "mds_capability",
851         "oss_capability",
852         "early_lock_cancel",
853         "som",
854         "adaptive_timeouts",
855         "lru_resize",
856         "mds_mds_connection",
857         "real_conn",
858         "change_qunit_size",
859         "alt_checksum_algorithm",
860         "fid_is_enabled",
861         "version_recovery",
862         "pools",
863         "grant_shrink",
864         "skip_orphan",
865         "large_ea",
866         "full20",
867         "layout_lock",
868         "64bithash",
869         "object_max_bytes",
870         "imp_recov",
871         "jobstats",
872         "umask",
873         "einprogress",
874         "grant_param",
875         "flock_owner",
876         "lvb_type",
877         "nanoseconds_times",
878         "lightweight_conn",
879         "short_io",
880         "pingless",
881         "flock_deadlock",
882         "disp_stripe",
883         "unknown",
884         NULL
885 };
886
887 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
888 {
889         __u64 mask = 1;
890         int i, ret = 0;
891
892         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
893                 if (flags & mask)
894                         ret += snprintf(page + ret, count - ret, "%s%s",
895                                         ret ? sep : "", obd_connect_names[i]);
896         }
897         if (flags & ~(mask - 1))
898                 ret += snprintf(page + ret, count - ret,
899                                 "%sunknown flags "LPX64,
900                                 ret ? sep : "", flags & ~(mask - 1));
901         return ret;
902 }
903 EXPORT_SYMBOL(obd_connect_flags2str);
904
905 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
906                       int *eof, void *data)
907 {
908         struct lprocfs_counter          ret;
909         struct lprocfs_counter_header   *header;
910         struct obd_device               *obd    = (struct obd_device *)data;
911         struct obd_import               *imp;
912         struct obd_import_conn          *conn;
913         int                             i;
914         int                             j;
915         int                             k;
916         int                             rw      = 0;
917
918         LASSERT(obd != NULL);
919         LPROCFS_CLIMP_CHECK(obd);
920         imp = obd->u.cli.cl_import;
921         *eof = 1;
922
923         i = snprintf(page, count,
924                      "import:\n"
925                      "    name: %s\n"
926                      "    target: %s\n"
927                      "    state: %s\n"
928                      "    instance: %u\n"
929                      "    connect_flags: [",
930                      obd->obd_name,
931                      obd2cli_tgt(obd),
932                      ptlrpc_import_state_name(imp->imp_state),
933                      imp->imp_connect_data.ocd_instance);
934         i += obd_connect_flags2str(page + i, count - i,
935                                    imp->imp_connect_data.ocd_connect_flags,
936                                    ", ");
937         i += snprintf(page + i, count - i,
938                       "]\n"
939                       "    import_flags: [");
940         i += obd_import_flags2str(imp, page + i, count - i);
941
942         i += snprintf(page + i, count - i,
943                       "]\n"
944                       "    connection:\n"
945                       "       failover_nids: [");
946         spin_lock(&imp->imp_lock);
947         j = 0;
948         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
949                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
950                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
951                 j++;
952         }
953         i += snprintf(page + i, count - i,
954                       "]\n"
955                       "       current_connection: %s\n"
956                       "       connection_attempts: %u\n"
957                       "       generation: %u\n"
958                       "       in-progress_invalidations: %u\n",
959                       imp->imp_connection == NULL ? "<none>" :
960                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
961                       imp->imp_conn_cnt,
962                       imp->imp_generation,
963                       cfs_atomic_read(&imp->imp_inval_count));
964         spin_unlock(&imp->imp_lock);
965
966         if (obd->obd_svc_stats == NULL)
967                 goto out_climp;
968
969         header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR];
970         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
971         if (ret.lc_count != 0) {
972                 /* first argument to do_div MUST be __u64 */
973                 __u64 sum = ret.lc_sum;
974                 do_div(sum, ret.lc_count);
975                 ret.lc_sum = sum;
976         } else
977                 ret.lc_sum = 0;
978         i += snprintf(page + i, count - i,
979                       "    rpcs:\n"
980                       "       inflight: %u\n"
981                       "       unregistering: %u\n"
982                       "       timeouts: %u\n"
983                       "       avg_waittime: "LPU64" %s\n",
984                       cfs_atomic_read(&imp->imp_inflight),
985                       cfs_atomic_read(&imp->imp_unregistering),
986                       cfs_atomic_read(&imp->imp_timeouts),
987                       ret.lc_sum, header->lc_units);
988
989         k = 0;
990         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
991                 if (imp->imp_at.iat_portal[j] == 0)
992                         break;
993                 k = max_t(unsigned int, k,
994                           at_get(&imp->imp_at.iat_service_estimate[j]));
995         }
996         i += snprintf(page + i, count - i,
997                       "    service_estimates:\n"
998                       "       services: %u sec\n"
999                       "       network: %u sec\n",
1000                       k,
1001                       at_get(&imp->imp_at.iat_net_latency));
1002
1003         i += snprintf(page + i, count - i,
1004                       "    transactions:\n"
1005                       "       last_replay: "LPU64"\n"
1006                       "       peer_committed: "LPU64"\n"
1007                       "       last_checked: "LPU64"\n",
1008                       imp->imp_last_replay_transno,
1009                       imp->imp_peer_committed_transno,
1010                       imp->imp_last_transno_checked);
1011
1012         /* avg data rates */
1013         for (rw = 0; rw <= 1; rw++) {
1014                 lprocfs_stats_collect(obd->obd_svc_stats,
1015                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1016                                       &ret);
1017                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1018                         /* first argument to do_div MUST be __u64 */
1019                         __u64 sum = ret.lc_sum;
1020                         do_div(sum, ret.lc_count);
1021                         ret.lc_sum = sum;
1022                         i += snprintf(page + i, count - i,
1023                                       "    %s_data_averages:\n"
1024                                       "       bytes_per_rpc: "LPU64"\n",
1025                                       rw ? "write" : "read",
1026                                       ret.lc_sum);
1027                 }
1028                 k = (int)ret.lc_sum;
1029                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1030                 header = &obd->obd_svc_stats->ls_cnt_header[j];
1031                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1032                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1033                         /* first argument to do_div MUST be __u64 */
1034                         __u64 sum = ret.lc_sum;
1035                         do_div(sum, ret.lc_count);
1036                         ret.lc_sum = sum;
1037                         i += snprintf(page + i, count - i,
1038                                       "       %s_per_rpc: "LPU64"\n",
1039                                       header->lc_units, ret.lc_sum);
1040                         j = (int)ret.lc_sum;
1041                         if (j > 0)
1042                                 i += snprintf(page + i, count - i,
1043                                               "       MB_per_sec: %u.%.02u\n",
1044                                               k / j, (100 * k / j) % 100);
1045                 }
1046         }
1047
1048 out_climp:
1049         LPROCFS_CLIMP_EXIT(obd);
1050         return i;
1051 }
1052 EXPORT_SYMBOL(lprocfs_rd_import);
1053
1054 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1055                       int *eof, void *data)
1056 {
1057         struct obd_device *obd = (struct obd_device *)data;
1058         struct obd_import *imp;
1059         int i, j, k;
1060
1061         LASSERT(obd != NULL);
1062         LPROCFS_CLIMP_CHECK(obd);
1063         imp = obd->u.cli.cl_import;
1064         *eof = 1;
1065
1066         i = snprintf(page, count, "current_state: %s\n",
1067                      ptlrpc_import_state_name(imp->imp_state));
1068         i += snprintf(page + i, count - i,
1069                       "state_history:\n");
1070         k = imp->imp_state_hist_idx;
1071         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1072                 struct import_state_hist *ish =
1073                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1074                 if (ish->ish_state == 0)
1075                         continue;
1076                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1077                               ish->ish_time,
1078                               ptlrpc_import_state_name(ish->ish_state));
1079         }
1080
1081         LPROCFS_CLIMP_EXIT(obd);
1082         return i;
1083 }
1084 EXPORT_SYMBOL(lprocfs_rd_state);
1085
1086 int lprocfs_at_hist_helper(char *page, int count, int rc,
1087                            struct adaptive_timeout *at)
1088 {
1089         int i;
1090         for (i = 0; i < AT_BINS; i++)
1091                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1092         rc += snprintf(page + rc, count - rc, "\n");
1093         return rc;
1094 }
1095 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1096
1097 /* See also ptlrpc_lprocfs_rd_timeouts */
1098 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1099                         int *eof, void *data)
1100 {
1101         struct obd_device *obd = (struct obd_device *)data;
1102         struct obd_import *imp;
1103         unsigned int cur, worst;
1104         time_t now, worstt;
1105         struct dhms ts;
1106         int i, rc = 0;
1107
1108         LASSERT(obd != NULL);
1109         LPROCFS_CLIMP_CHECK(obd);
1110         imp = obd->u.cli.cl_import;
1111         *eof = 1;
1112
1113         now = cfs_time_current_sec();
1114
1115         /* Some network health info for kicks */
1116         s2dhms(&ts, now - imp->imp_last_reply_time);
1117         rc += snprintf(page + rc, count - rc,
1118                        "%-10s : %ld, "DHMS_FMT" ago\n",
1119                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1120
1121         cur = at_get(&imp->imp_at.iat_net_latency);
1122         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1123         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1124         s2dhms(&ts, now - worstt);
1125         rc += snprintf(page + rc, count - rc,
1126                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1127                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1128         rc = lprocfs_at_hist_helper(page, count, rc,
1129                                     &imp->imp_at.iat_net_latency);
1130
1131         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1132                 if (imp->imp_at.iat_portal[i] == 0)
1133                         break;
1134                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1135                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1136                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1137                 s2dhms(&ts, now - worstt);
1138                 rc += snprintf(page + rc, count - rc,
1139                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1140                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1141                                cur, worst, worstt, DHMS_VARS(&ts));
1142                 rc = lprocfs_at_hist_helper(page, count, rc,
1143                                           &imp->imp_at.iat_service_estimate[i]);
1144         }
1145
1146         LPROCFS_CLIMP_EXIT(obd);
1147         return rc;
1148 }
1149 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1150
1151 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1152                              int count, int *eof, void *data)
1153 {
1154         struct obd_device *obd = data;
1155         __u64 flags;
1156         int ret = 0;
1157
1158         LPROCFS_CLIMP_CHECK(obd);
1159         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1160         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1161         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1162         ret += snprintf(page + ret, count - ret, "\n");
1163         LPROCFS_CLIMP_EXIT(obd);
1164         return ret;
1165 }
1166 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1167
1168 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1169                            int *eof,  void *data)
1170 {
1171         struct obd_device *obd = data;
1172
1173         LASSERT(obd != NULL);
1174         *eof = 1;
1175         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1176 }
1177 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1178
1179 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1180                        int *eof, void *data)
1181 {
1182         struct obd_type *class = (struct obd_type*) data;
1183
1184         LASSERT(class != NULL);
1185         *eof = 1;
1186         return snprintf(page, count, "%d\n", class->typ_refcnt);
1187 }
1188 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1189
1190 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1191 {
1192         int rc = 0;
1193
1194         LASSERT(obd != NULL);
1195         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1196         LASSERT(obd->obd_type->typ_procroot != NULL);
1197
1198         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1199                                                obd->obd_type->typ_procroot,
1200                                                list, obd);
1201         if (IS_ERR(obd->obd_proc_entry)) {
1202                 rc = PTR_ERR(obd->obd_proc_entry);
1203                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1204                 obd->obd_proc_entry = NULL;
1205         }
1206         return rc;
1207 }
1208 EXPORT_SYMBOL(lprocfs_obd_setup);
1209
1210 int lprocfs_obd_cleanup(struct obd_device *obd)
1211 {
1212         if (!obd)
1213                 return -EINVAL;
1214         if (obd->obd_proc_exports_entry) {
1215                 /* Should be no exports left */
1216                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1217                 lprocfs_remove(&obd->obd_proc_exports_entry);
1218                 obd->obd_proc_exports_entry = NULL;
1219         }
1220         if (obd->obd_proc_entry) {
1221                 lprocfs_remove(&obd->obd_proc_entry);
1222                 obd->obd_proc_entry = NULL;
1223         }
1224         return 0;
1225 }
1226 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1227
1228 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1229 {
1230         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
1231                client_stat->nid_proc, client_stat->nid_stats);
1232
1233         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1234                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1235                  atomic_read(&client_stat->nid_exp_ref_count));
1236
1237         if (client_stat->nid_proc)
1238                 lprocfs_remove(&client_stat->nid_proc);
1239
1240         if (client_stat->nid_stats)
1241                 lprocfs_free_stats(&client_stat->nid_stats);
1242
1243         if (client_stat->nid_ldlm_stats)
1244                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1245
1246         OBD_FREE_PTR(client_stat);
1247         return;
1248
1249 }
1250
1251 void lprocfs_free_per_client_stats(struct obd_device *obd)
1252 {
1253         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1254         struct nid_stat *stat;
1255         ENTRY;
1256
1257         /* we need extra list - because hash_exit called to early */
1258         /* not need locking because all clients is died */
1259         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1260                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1261                                       struct nid_stat, nid_list);
1262                 cfs_list_del_init(&stat->nid_list);
1263                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1264                 lprocfs_free_client_stats(stat);
1265         }
1266         EXIT;
1267 }
1268 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1269
1270 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1271                                           enum lprocfs_stats_flags flags)
1272 {
1273         struct lprocfs_stats    *stats;
1274         unsigned int            num_entry;
1275         unsigned int            percpusize = 0;
1276         int                     i;
1277
1278         if (num == 0)
1279                 return NULL;
1280
1281         if (lprocfs_no_percpu_stats != 0)
1282                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1283
1284         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1285                 num_entry = 1;
1286         else
1287                 num_entry = num_possible_cpus();
1288
1289         /* alloc percpu pointers for all possible cpu slots */
1290         LIBCFS_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1291         if (stats == NULL)
1292                 return NULL;
1293
1294         stats->ls_num = num;
1295         stats->ls_flags = flags;
1296         spin_lock_init(&stats->ls_lock);
1297
1298         /* alloc num of counter headers */
1299         LIBCFS_ALLOC(stats->ls_cnt_header,
1300                      stats->ls_num * sizeof(struct lprocfs_counter_header));
1301         if (stats->ls_cnt_header == NULL)
1302                 goto fail;
1303
1304         if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) {
1305                 /* contains only one set counters */
1306                 percpusize = lprocfs_stats_counter_size(stats);
1307                 LIBCFS_ALLOC_ATOMIC(stats->ls_percpu[0], percpusize);
1308                 if (stats->ls_percpu[0] == NULL)
1309                         goto fail;
1310                 stats->ls_biggest_alloc_num = 1;
1311         } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) {
1312                 /* alloc all percpu data, currently only obd_memory use this */
1313                 for (i = 0; i < num_entry; ++i)
1314                         if (lprocfs_stats_alloc_one(stats, i) < 0)
1315                                 goto fail;
1316         }
1317
1318         return stats;
1319
1320 fail:
1321         lprocfs_free_stats(&stats);
1322         return NULL;
1323 }
1324 EXPORT_SYMBOL(lprocfs_alloc_stats);
1325
1326 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1327 {
1328         struct lprocfs_stats *stats = *statsh;
1329         unsigned int num_entry;
1330         unsigned int percpusize;
1331         unsigned int i;
1332
1333         if (stats == NULL || stats->ls_num == 0)
1334                 return;
1335         *statsh = NULL;
1336
1337         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1338                 num_entry = 1;
1339         else
1340                 num_entry = num_possible_cpus();
1341
1342         percpusize = lprocfs_stats_counter_size(stats);
1343         for (i = 0; i < num_entry; i++)
1344                 if (stats->ls_percpu[i] != NULL)
1345                         LIBCFS_FREE(stats->ls_percpu[i], percpusize);
1346         if (stats->ls_cnt_header != NULL)
1347                 LIBCFS_FREE(stats->ls_cnt_header, stats->ls_num *
1348                                         sizeof(struct lprocfs_counter_header));
1349         LIBCFS_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1350 }
1351 EXPORT_SYMBOL(lprocfs_free_stats);
1352
1353 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1354 {
1355         struct lprocfs_counter          *percpu_cntr;
1356         int                             i;
1357         int                             j;
1358         unsigned int                    num_entry;
1359         unsigned long                   flags = 0;
1360
1361         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1362
1363         for (i = 0; i < num_entry; i++) {
1364                 if (stats->ls_percpu[i] == NULL)
1365                         continue;
1366                 for (j = 0; j < stats->ls_num; j++) {
1367                         percpu_cntr = lprocfs_stats_counter_get(stats, i, j);
1368                         percpu_cntr->lc_count           = 0;
1369                         percpu_cntr->lc_min             = LC_MIN_INIT;
1370                         percpu_cntr->lc_max             = 0;
1371                         percpu_cntr->lc_sumsquare       = 0;
1372                         percpu_cntr->lc_sum             = 0;
1373                         if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE)
1374                                 percpu_cntr->lc_sum_irq = 0;
1375                 }
1376         }
1377
1378         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1379 }
1380 EXPORT_SYMBOL(lprocfs_clear_stats);
1381
1382 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1383                                        size_t len, loff_t *off)
1384 {
1385         struct seq_file *seq = file->private_data;
1386         struct lprocfs_stats *stats = seq->private;
1387
1388         lprocfs_clear_stats(stats);
1389
1390         return len;
1391 }
1392
1393 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1394 {
1395         struct lprocfs_stats *stats = p->private;
1396
1397         return (*pos < stats->ls_num) ? pos : NULL;
1398 }
1399
1400 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1401 {
1402 }
1403
1404 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1405 {
1406         (*pos)++;
1407
1408         return lprocfs_stats_seq_start(p, pos);
1409 }
1410
1411 /* seq file export of one lprocfs counter */
1412 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1413 {
1414         struct lprocfs_stats            *stats  = p->private;
1415         struct lprocfs_counter_header   *hdr;
1416         struct lprocfs_counter           ctr;
1417         int                              idx    = *(loff_t *)v;
1418         int                              rc     = 0;
1419
1420         if (idx == 0) {
1421                 struct timeval now;
1422
1423                 do_gettimeofday(&now);
1424                 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1425                                 "snapshot_time", now.tv_sec, now.tv_usec);
1426                 if (rc < 0)
1427                         return rc;
1428         }
1429
1430         hdr = &stats->ls_cnt_header[idx];
1431         lprocfs_stats_collect(stats, idx, &ctr);
1432
1433         if (ctr.lc_count == 0)
1434                 goto out;
1435
1436         rc = seq_printf(p, "%-25s "LPD64" samples [%s]", hdr->lc_name,
1437                         ctr.lc_count, hdr->lc_units);
1438         if (rc < 0)
1439                 goto out;
1440
1441         if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && ctr.lc_count > 0) {
1442                 rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1443                                 ctr.lc_min, ctr.lc_max, ctr.lc_sum);
1444                 if (rc < 0)
1445                         goto out;
1446                 if (hdr->lc_config & LPROCFS_CNTR_STDDEV)
1447                         rc = seq_printf(p, " "LPD64, ctr.lc_sumsquare);
1448                 if (rc < 0)
1449                         goto out;
1450         }
1451         rc = seq_printf(p, "\n");
1452 out:
1453         return (rc < 0) ? rc : 0;
1454 }
1455
1456 struct seq_operations lprocfs_stats_seq_sops = {
1457         .start  = lprocfs_stats_seq_start,
1458         .stop   = lprocfs_stats_seq_stop,
1459         .next   = lprocfs_stats_seq_next,
1460         .show   = lprocfs_stats_seq_show,
1461 };
1462
1463 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1464 {
1465         struct proc_dir_entry *dp = PDE(inode);
1466         struct seq_file *seq;
1467         int rc;
1468
1469         if (LPROCFS_ENTRY_CHECK(dp))
1470                 return -ENOENT;
1471
1472         rc = seq_open(file, &lprocfs_stats_seq_sops);
1473         if (rc)
1474                 return rc;
1475         seq = file->private_data;
1476         seq->private = dp->data;
1477         return 0;
1478 }
1479
1480 struct file_operations lprocfs_stats_seq_fops = {
1481         .owner   = THIS_MODULE,
1482         .open    = lprocfs_stats_seq_open,
1483         .read    = seq_read,
1484         .write   = lprocfs_stats_seq_write,
1485         .llseek  = seq_lseek,
1486         .release = lprocfs_seq_release,
1487 };
1488
1489 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1490                            struct lprocfs_stats *stats)
1491 {
1492         struct proc_dir_entry *entry;
1493         LASSERT(root != NULL);
1494
1495         LPROCFS_WRITE_ENTRY();
1496         entry = create_proc_entry(name, 0644, root);
1497         if (entry) {
1498                 entry->proc_fops = &lprocfs_stats_seq_fops;
1499                 entry->data = stats;
1500         }
1501
1502         LPROCFS_WRITE_EXIT();
1503
1504         if (entry == NULL)
1505                 return -ENOMEM;
1506
1507         return 0;
1508 }
1509 EXPORT_SYMBOL(lprocfs_register_stats);
1510
1511 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1512                           unsigned conf, const char *name, const char *units)
1513 {
1514         struct lprocfs_counter_header   *header;
1515         struct lprocfs_counter          *percpu_cntr;
1516         unsigned long                   flags = 0;
1517         unsigned int                    i;
1518         unsigned int                    num_cpu;
1519
1520         LASSERT(stats != NULL);
1521
1522         header = &stats->ls_cnt_header[index];
1523         LASSERTF(header != NULL, "Failed to allocate stats header:[%d]%s/%s\n",
1524                  index, name, units);
1525
1526         header->lc_config = conf;
1527         header->lc_name   = name;
1528         header->lc_units  = units;
1529
1530         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1531         for (i = 0; i < num_cpu; ++i) {
1532                 if (stats->ls_percpu[i] == NULL)
1533                         continue;
1534                 percpu_cntr = lprocfs_stats_counter_get(stats, i, index);
1535                 percpu_cntr->lc_count           = 0;
1536                 percpu_cntr->lc_min             = LC_MIN_INIT;
1537                 percpu_cntr->lc_max             = 0;
1538                 percpu_cntr->lc_sumsquare       = 0;
1539                 percpu_cntr->lc_sum             = 0;
1540                 if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0)
1541                         percpu_cntr->lc_sum_irq = 0;
1542         }
1543         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1544 }
1545 EXPORT_SYMBOL(lprocfs_counter_init);
1546
1547 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1548 do {                                                                       \
1549         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1550         LASSERT(coffset < stats->ls_num);                                  \
1551         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1552 } while (0)
1553
1554 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1555 {
1556         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1557         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1558         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1559         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1560         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1561         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1562         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1563         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1564         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1565         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1566         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1567         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1568         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1569         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1570         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1571         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1572         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1573         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1574         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1575         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1576         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1577         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1578         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1579         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1580         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1581         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1582         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1583         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1584         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1585         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1586         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1587         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1588         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1589         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1590         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1591         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1592         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1593         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1594         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1595         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1596         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1597         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1598         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1599         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1600         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1601         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1602         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1603         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1604         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1605         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1606         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1607         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1608         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1609         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1610         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1611         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1612         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1613         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1614         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1615         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1616         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1617         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1618         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1619         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1620         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1621         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1622         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1623
1624         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
1625 }
1626 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1627
1628 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1629 {
1630         struct lprocfs_stats *stats;
1631         unsigned int num_stats;
1632         int rc, i;
1633
1634         LASSERT(obd->obd_stats == NULL);
1635         LASSERT(obd->obd_proc_entry != NULL);
1636         LASSERT(obd->obd_cntr_base == 0);
1637
1638         num_stats = NUM_OBD_STATS + num_private_stats;
1639         stats = lprocfs_alloc_stats(num_stats, 0);
1640         if (stats == NULL)
1641                 return -ENOMEM;
1642
1643         lprocfs_init_ops_stats(num_private_stats, stats);
1644
1645         for (i = num_private_stats; i < num_stats; i++) {
1646                 /* If this LBUGs, it is likely that an obd
1647                  * operation was added to struct obd_ops in
1648                  * <obd.h>, and that the corresponding line item
1649                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1650                  * is missing from the list above. */
1651                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
1652                          "Missing obd_stat initializer obd_op "
1653                          "operation at offset %d.\n", i - num_private_stats);
1654         }
1655         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1656         if (rc < 0) {
1657                 lprocfs_free_stats(&stats);
1658         } else {
1659                 obd->obd_stats  = stats;
1660                 obd->obd_cntr_base = num_private_stats;
1661         }
1662         return rc;
1663 }
1664 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1665
1666 void lprocfs_free_obd_stats(struct obd_device *obd)
1667 {
1668         if (obd->obd_stats)
1669                 lprocfs_free_stats(&obd->obd_stats);
1670 }
1671 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1672
1673 /* Note that we only init md counters for ops whose offset is less
1674  * than NUM_MD_STATS. This is explained in a comment in the definition
1675  * of struct md_ops. */
1676 #define LPROCFS_MD_OP_INIT(base, stats, op)                                    \
1677         do {                                                                   \
1678                 unsigned int _idx = base + MD_COUNTER_OFFSET(op);              \
1679                                                                                \
1680                 if (MD_COUNTER_OFFSET(op) < NUM_MD_STATS) {                    \
1681                         LASSERT(_idx < stats->ls_num);                         \
1682                         lprocfs_counter_init(stats, _idx, 0, #op, "reqs");     \
1683                 }                                                              \
1684         } while (0)
1685
1686 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1687 {
1688         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1689         LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode);
1690         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1691         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1692         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1693         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1694         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1695         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1696         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1697         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1698         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1699         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1700         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1701         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1702         LPROCFS_MD_OP_INIT(num_private_stats, stats, fsync);
1703         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1704         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1705         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1706         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1707         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1708         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1709         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1710         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1711         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1712         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1713         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1714         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1715         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1716         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1717         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1718         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1719         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1720 }
1721 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1722
1723 int lprocfs_alloc_md_stats(struct obd_device *obd,
1724                            unsigned int num_private_stats)
1725 {
1726         struct lprocfs_stats *stats;
1727         unsigned int num_stats;
1728         int rc, i;
1729
1730         CLASSERT(offsetof(struct md_ops, MD_STATS_FIRST_OP) == 0);
1731         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_FIRST_OP) == 0);
1732         CLASSERT(_MD_COUNTER_OFFSET(MD_STATS_LAST_OP) > 0);
1733
1734         /* TODO Ensure that this function is only used where
1735          * appropriate by adding an assertion to the effect that
1736          * obd->obd_type->typ_md_ops is not NULL. We can't do this now
1737          * because mdt_procfs_init() uses this function to allocate
1738          * the stats backing /proc/fs/lustre/mdt/.../md_stats but the
1739          * mdt layer does not use the md_ops interface. This is
1740          * confusing and a waste of memory. See LU-2484.
1741          */
1742         LASSERT(obd->obd_proc_entry != NULL);
1743         LASSERT(obd->obd_md_stats == NULL);
1744         LASSERT(obd->obd_md_cntr_base == 0);
1745
1746         num_stats = NUM_MD_STATS + num_private_stats;
1747         stats = lprocfs_alloc_stats(num_stats, 0);
1748         if (stats == NULL)
1749                 return -ENOMEM;
1750
1751         lprocfs_init_mps_stats(num_private_stats, stats);
1752
1753         for (i = num_private_stats; i < num_stats; i++) {
1754                 if (stats->ls_cnt_header[i].lc_name == NULL) {
1755                         CERROR("Missing md_stat initializer md_op "
1756                                "operation at offset %d. Aborting.\n",
1757                                i - num_private_stats);
1758                         LBUG();
1759                 }
1760         }
1761
1762         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1763         if (rc < 0) {
1764                 lprocfs_free_stats(&stats);
1765         } else {
1766                 obd->obd_md_stats = stats;
1767                 obd->obd_md_cntr_base = num_private_stats;
1768         }
1769
1770         return rc;
1771 }
1772 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1773
1774 void lprocfs_free_md_stats(struct obd_device *obd)
1775 {
1776         struct lprocfs_stats *stats = obd->obd_md_stats;
1777
1778         if (stats != NULL) {
1779                 obd->obd_md_stats = NULL;
1780                 obd->obd_md_cntr_base = 0;
1781                 lprocfs_free_stats(&stats);
1782         }
1783 }
1784 EXPORT_SYMBOL(lprocfs_free_md_stats);
1785
1786 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1787 {
1788         lprocfs_counter_init(ldlm_stats,
1789                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1790                              0, "ldlm_enqueue", "reqs");
1791         lprocfs_counter_init(ldlm_stats,
1792                              LDLM_CONVERT - LDLM_FIRST_OPC,
1793                              0, "ldlm_convert", "reqs");
1794         lprocfs_counter_init(ldlm_stats,
1795                              LDLM_CANCEL - LDLM_FIRST_OPC,
1796                              0, "ldlm_cancel", "reqs");
1797         lprocfs_counter_init(ldlm_stats,
1798                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1799                              0, "ldlm_bl_callback", "reqs");
1800         lprocfs_counter_init(ldlm_stats,
1801                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1802                              0, "ldlm_cp_callback", "reqs");
1803         lprocfs_counter_init(ldlm_stats,
1804                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1805                              0, "ldlm_gl_callback", "reqs");
1806 }
1807 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1808
1809 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1810                          int *eof,  void *data)
1811 {
1812         struct obd_export *exp = data;
1813         LASSERT(exp != NULL);
1814         *eof = 1;
1815         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1816 }
1817
1818 struct exp_uuid_cb_data {
1819         char                   *page;
1820         int                     count;
1821         int                    *eof;
1822         int                    *len;
1823 };
1824
1825 static void
1826 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1827                             int count, int *eof, int *len)
1828 {
1829         cb_data->page = page;
1830         cb_data->count = count;
1831         cb_data->eof = eof;
1832         cb_data->len = len;
1833 }
1834
1835 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1836                            cfs_hlist_node_t *hnode, void *cb_data)
1837
1838 {
1839         struct obd_export *exp = cfs_hash_object(hs, hnode);
1840         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1841
1842         if (exp->exp_nid_stats)
1843                 *data->len += snprintf((data->page + *data->len),
1844                                        data->count, "%s\n",
1845                                        obd_uuid2str(&exp->exp_client_uuid));
1846         return 0;
1847 }
1848
1849 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1850                         int *eof,  void *data)
1851 {
1852         struct nid_stat *stats = (struct nid_stat *)data;
1853         struct exp_uuid_cb_data cb_data;
1854         struct obd_device *obd = stats->nid_obd;
1855         int len = 0;
1856
1857         *eof = 1;
1858         page[0] = '\0';
1859         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1860         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1861                               lprocfs_exp_print_uuid, &cb_data);
1862         return (*cb_data.len);
1863 }
1864
1865 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1866                            cfs_hlist_node_t *hnode, void *cb_data)
1867
1868 {
1869         struct exp_uuid_cb_data *data = cb_data;
1870         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1871
1872         if (exp->exp_lock_hash != NULL) {
1873                 if (!*data->len) {
1874                         *data->len += cfs_hash_debug_header(data->page,
1875                                                             data->count);
1876                 }
1877                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1878                                                  data->count);
1879         }
1880
1881         return 0;
1882 }
1883
1884 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1885                         int *eof,  void *data)
1886 {
1887         struct nid_stat *stats = (struct nid_stat *)data;
1888         struct exp_uuid_cb_data cb_data;
1889         struct obd_device *obd = stats->nid_obd;
1890         int len = 0;
1891
1892         *eof = 1;
1893         page[0] = '\0';
1894         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1895
1896         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1897                               lprocfs_exp_print_hash, &cb_data);
1898         return (*cb_data.len);
1899 }
1900
1901 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1902                                         int count, int *eof,  void *data)
1903 {
1904         *eof = 1;
1905         return snprintf(page, count, "%s\n",
1906                         "Write into this file to clear all nid stats and "
1907                         "stale nid entries");
1908 }
1909 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1910
1911 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1912 {
1913         struct nid_stat *stat = obj;
1914         ENTRY;
1915
1916         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1917         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1918                 /* object has only hash references. */
1919                 spin_lock(&stat->nid_obd->obd_nid_lock);
1920                 cfs_list_move(&stat->nid_list, data);
1921                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1922                 RETURN(1);
1923         }
1924         /* we has reference to object - only clear data*/
1925         if (stat->nid_stats)
1926                 lprocfs_clear_stats(stat->nid_stats);
1927
1928         RETURN(0);
1929 }
1930
1931 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1932                                   unsigned long count, void *data)
1933 {
1934         struct obd_device *obd = (struct obd_device *)data;
1935         struct nid_stat *client_stat;
1936         CFS_LIST_HEAD(free_list);
1937
1938         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1939                           lprocfs_nid_stats_clear_write_cb, &free_list);
1940
1941         while (!cfs_list_empty(&free_list)) {
1942                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1943                                              nid_list);
1944                 cfs_list_del_init(&client_stat->nid_list);
1945                 lprocfs_free_client_stats(client_stat);
1946         }
1947
1948         return count;
1949 }
1950 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1951
1952 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1953 {
1954         struct nid_stat *new_stat, *old_stat;
1955         struct obd_device *obd = NULL;
1956         cfs_proc_dir_entry_t *entry;
1957         char *buffer = NULL;
1958         int rc = 0;
1959         ENTRY;
1960
1961         *newnid = 0;
1962
1963         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1964             !exp->exp_obd->obd_nid_stats_hash)
1965                 RETURN(-EINVAL);
1966
1967         /* not test against zero because eric say:
1968          * You may only test nid against another nid, or LNET_NID_ANY.
1969          * Anything else is nonsense.*/
1970         if (!nid || *nid == LNET_NID_ANY)
1971                 RETURN(0);
1972
1973         spin_lock(&exp->exp_lock);
1974         if (exp->exp_nid_stats != NULL) {
1975                 spin_unlock(&exp->exp_lock);
1976                 RETURN(-EALREADY);
1977         }
1978         spin_unlock(&exp->exp_lock);
1979
1980         obd = exp->exp_obd;
1981
1982         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1983
1984         OBD_ALLOC_PTR(new_stat);
1985         if (new_stat == NULL)
1986                 RETURN(-ENOMEM);
1987
1988         new_stat->nid               = *nid;
1989         new_stat->nid_obd           = exp->exp_obd;
1990         /* we need set default refcount to 1 to balance obd_disconnect */
1991         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1992
1993         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1994                                            nid, &new_stat->nid_hash);
1995         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1996                old_stat, libcfs_nid2str(*nid),
1997                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1998
1999         /* Return -EALREADY here so that we know that the /proc
2000          * entry already has been created */
2001         if (old_stat != new_stat) {
2002                 nidstat_putref(old_stat);
2003                 GOTO(destroy_new, rc = -EALREADY);
2004         }
2005         /* not found - create */
2006         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2007         if (buffer == NULL)
2008                 GOTO(destroy_new, rc = -ENOMEM);
2009
2010         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2011         new_stat->nid_proc = lprocfs_register(buffer,
2012                                               obd->obd_proc_exports_entry,
2013                                               NULL, NULL);
2014         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2015
2016         if (IS_ERR(new_stat->nid_proc)) {
2017                 rc = PTR_ERR(new_stat->nid_proc);
2018                 new_stat->nid_proc = NULL;
2019                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
2020                        obd->obd_name, libcfs_nid2str(*nid), rc);
2021                 GOTO(destroy_new_ns, rc);
2022         }
2023
2024         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2025                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2026         if (IS_ERR(entry)) {
2027                 CWARN("Error adding the NID stats file\n");
2028                 rc = PTR_ERR(entry);
2029                 GOTO(destroy_new_ns, rc);
2030         }
2031
2032         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2033                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2034         if (IS_ERR(entry)) {
2035                 CWARN("Error adding the hash file\n");
2036                 rc = PTR_ERR(entry);
2037                 GOTO(destroy_new_ns, rc);
2038         }
2039
2040         spin_lock(&exp->exp_lock);
2041         exp->exp_nid_stats = new_stat;
2042         spin_unlock(&exp->exp_lock);
2043         *newnid = 1;
2044         /* protect competitive add to list, not need locking on destroy */
2045         spin_lock(&obd->obd_nid_lock);
2046         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2047         spin_unlock(&obd->obd_nid_lock);
2048
2049         RETURN(rc);
2050
2051 destroy_new_ns:
2052         if (new_stat->nid_proc != NULL)
2053                 lprocfs_remove(&new_stat->nid_proc);
2054         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2055
2056 destroy_new:
2057         nidstat_putref(new_stat);
2058         OBD_FREE_PTR(new_stat);
2059         RETURN(rc);
2060 }
2061 EXPORT_SYMBOL(lprocfs_exp_setup);
2062
2063 int lprocfs_exp_cleanup(struct obd_export *exp)
2064 {
2065         struct nid_stat *stat = exp->exp_nid_stats;
2066
2067         if(!stat || !exp->exp_obd)
2068                 RETURN(0);
2069
2070         nidstat_putref(exp->exp_nid_stats);
2071         exp->exp_nid_stats = NULL;
2072
2073         return 0;
2074 }
2075 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2076
2077 int lprocfs_write_helper(const char *buffer, unsigned long count,
2078                          int *val)
2079 {
2080         return lprocfs_write_frac_helper(buffer, count, val, 1);
2081 }
2082 EXPORT_SYMBOL(lprocfs_write_helper);
2083
2084 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2085                               int *val, int mult)
2086 {
2087         char kernbuf[20], *end, *pbuf;
2088
2089         if (count > (sizeof(kernbuf) - 1))
2090                 return -EINVAL;
2091
2092         if (copy_from_user(kernbuf, buffer, count))
2093                 return -EFAULT;
2094
2095         kernbuf[count] = '\0';
2096         pbuf = kernbuf;
2097         if (*pbuf == '-') {
2098                 mult = -mult;
2099                 pbuf++;
2100         }
2101
2102         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2103         if (pbuf == end)
2104                 return -EINVAL;
2105
2106         if (end != NULL && *end == '.') {
2107                 int temp_val, pow = 1;
2108                 int i;
2109
2110                 pbuf = end + 1;
2111                 if (strlen(pbuf) > 5)
2112                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2113
2114                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2115
2116                 if (pbuf < end) {
2117                         for (i = 0; i < (end - pbuf); i++)
2118                                 pow *= 10;
2119
2120                         *val += temp_val / pow;
2121                 }
2122         }
2123         return 0;
2124 }
2125 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2126
2127 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2128                              int mult)
2129 {
2130         long decimal_val, frac_val;
2131         int prtn;
2132
2133         if (count < 10)
2134                 return -EINVAL;
2135
2136         decimal_val = val / mult;
2137         prtn = snprintf(buffer, count, "%ld", decimal_val);
2138         frac_val = val % mult;
2139
2140         if (prtn < (count - 4) && frac_val > 0) {
2141                 long temp_frac;
2142                 int i, temp_mult = 1, frac_bits = 0;
2143
2144                 temp_frac = frac_val * 10;
2145                 buffer[prtn++] = '.';
2146                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2147                         /* only reserved 2 bits fraction */
2148                         buffer[prtn++] ='0';
2149                         temp_frac *= 10;
2150                         frac_bits++;
2151                 }
2152                 /*
2153                  * Need to think these cases :
2154                  *      1. #echo x.00 > /proc/xxx       output result : x
2155                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2156                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2157                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2158                  *      Only reserved 2 bits fraction.
2159                  */
2160                 for (i = 0; i < (5 - prtn); i++)
2161                         temp_mult *= 10;
2162
2163                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2164                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2165                                  frac_val * temp_mult / mult);
2166
2167                 prtn--;
2168                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2169                         prtn--;
2170                         if (buffer[prtn] == '.') {
2171                                 prtn--;
2172                                 break;
2173                         }
2174                 }
2175                 prtn++;
2176         }
2177         buffer[prtn++] ='\n';
2178         return prtn;
2179 }
2180 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2181
2182 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2183 {
2184         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2185 }
2186 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2187
2188 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2189                               __u64 *val, int mult)
2190 {
2191         char kernbuf[22], *end, *pbuf;
2192         __u64 whole, frac = 0, units;
2193         unsigned frac_d = 1;
2194
2195         if (count > (sizeof(kernbuf) - 1))
2196                 return -EINVAL;
2197
2198         if (copy_from_user(kernbuf, buffer, count))
2199                 return -EFAULT;
2200
2201         kernbuf[count] = '\0';
2202         pbuf = kernbuf;
2203         if (*pbuf == '-') {
2204                 mult = -mult;
2205                 pbuf++;
2206         }
2207
2208         whole = simple_strtoull(pbuf, &end, 10);
2209         if (pbuf == end)
2210                 return -EINVAL;
2211
2212         if (end != NULL && *end == '.') {
2213                 int i;
2214                 pbuf = end + 1;
2215
2216                 /* need to limit frac_d to a __u32 */
2217                 if (strlen(pbuf) > 10)
2218                         pbuf[10] = '\0';
2219
2220                 frac = simple_strtoull(pbuf, &end, 10);
2221                 /* count decimal places */
2222                 for (i = 0; i < (end - pbuf); i++)
2223                         frac_d *= 10;
2224         }
2225
2226         units = 1;
2227         if (end != NULL) {
2228                 switch (*end) {
2229                 case 'p': case 'P':
2230                         units <<= 10;
2231                 case 't': case 'T':
2232                         units <<= 10;
2233                 case 'g': case 'G':
2234                         units <<= 10;
2235                 case 'm': case 'M':
2236                         units <<= 10;
2237                 case 'k': case 'K':
2238                         units <<= 10;
2239                 }
2240         }
2241         /* Specified units override the multiplier */
2242         if (units)
2243                 mult = mult < 0 ? -units : units;
2244
2245         frac *= mult;
2246         do_div(frac, frac_d);
2247         *val = whole * mult + frac;
2248         return 0;
2249 }
2250 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2251
2252 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2253 {
2254         size_t l2;
2255
2256         l2 = strlen(s2);
2257         if (!l2)
2258                 return (char *)s1;
2259         while (len >= l2) {
2260                 len--;
2261                 if (!memcmp(s1, s2, l2))
2262                         return (char *)s1;
2263                 s1++;
2264         }
2265         return NULL;
2266 }
2267
2268 /**
2269  * Find the string \a name in the input \a buffer, and return a pointer to the
2270  * value immediately following \a name, reducing \a count appropriately.
2271  * If \a name is not found the original \a buffer is returned.
2272  */
2273 char *lprocfs_find_named_value(const char *buffer, const char *name,
2274                                 unsigned long *count)
2275 {
2276         char *val;
2277         size_t buflen = *count;
2278
2279         /* there is no strnstr() in rhel5 and ubuntu kernels */
2280         val = lprocfs_strnstr(buffer, name, buflen);
2281         if (val == NULL)
2282                 return (char *)buffer;
2283
2284         val += strlen(name);                             /* skip prefix */
2285         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2286                 val++;
2287
2288         *count = 0;
2289         while (val < buffer + buflen && isalnum(*val)) {
2290                 ++*count;
2291                 ++val;
2292         }
2293
2294         return val - *count;
2295 }
2296 EXPORT_SYMBOL(lprocfs_find_named_value);
2297
2298 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
2299                        const char *name,
2300                        mode_t mode,
2301                        const struct file_operations *seq_fops,
2302                        void *data)
2303 {
2304         struct proc_dir_entry *entry;
2305         ENTRY;
2306
2307         /* Disallow secretly (un)writable entries. */
2308         LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
2309
2310         LPROCFS_WRITE_ENTRY();
2311         entry = create_proc_entry(name, mode, parent);
2312         if (entry) {
2313                 entry->proc_fops = seq_fops;
2314                 entry->data = data;
2315         }
2316         LPROCFS_WRITE_EXIT();
2317
2318         if (entry == NULL)
2319                 RETURN(-ENOMEM);
2320
2321         RETURN(0);
2322 }
2323 EXPORT_SYMBOL(lprocfs_seq_create);
2324
2325 int lprocfs_obd_seq_create(struct obd_device *dev,
2326                            const char *name,
2327                            mode_t mode,
2328                            const struct file_operations *seq_fops,
2329                            void *data)
2330 {
2331         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2332                                    mode, seq_fops, data));
2333 }
2334 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2335
2336 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2337 {
2338         if (value >= OBD_HIST_MAX)
2339                 value = OBD_HIST_MAX - 1;
2340
2341         spin_lock(&oh->oh_lock);
2342         oh->oh_buckets[value]++;
2343         spin_unlock(&oh->oh_lock);
2344 }
2345 EXPORT_SYMBOL(lprocfs_oh_tally);
2346
2347 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2348 {
2349         unsigned int val = 0;
2350
2351         if (likely(value != 0))
2352                 val = min(fls(value - 1), OBD_HIST_MAX);
2353
2354         lprocfs_oh_tally(oh, val);
2355 }
2356 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2357
2358 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2359 {
2360         unsigned long ret = 0;
2361         int i;
2362
2363         for (i = 0; i < OBD_HIST_MAX; i++)
2364                 ret +=  oh->oh_buckets[i];
2365         return ret;
2366 }
2367 EXPORT_SYMBOL(lprocfs_oh_sum);
2368
2369 void lprocfs_oh_clear(struct obd_histogram *oh)
2370 {
2371         spin_lock(&oh->oh_lock);
2372         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2373         spin_unlock(&oh->oh_lock);
2374 }
2375 EXPORT_SYMBOL(lprocfs_oh_clear);
2376
2377 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2378                         int count, int *eof, void *data)
2379 {
2380         struct obd_device *obd = data;
2381         int c = 0;
2382
2383         if (obd == NULL)
2384                 return 0;
2385
2386         c += cfs_hash_debug_header(page, count);
2387         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2388         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2389         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2390
2391         return c;
2392 }
2393 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2394
2395 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2396                                    int count, int *eof, void *data)
2397 {
2398         struct obd_device *obd = data;
2399         int len = 0, size;
2400
2401         LASSERT(obd != NULL);
2402         LASSERT(count >= 0);
2403
2404         /* Set start of user data returned to
2405            page + off since the user may have
2406            requested to read much smaller than
2407            what we need to read */
2408         *start = page + off;
2409
2410         /*
2411          * We know we are allocated a page here.
2412          * Also we know that this function will
2413          * not need to write more than a page
2414          * so we can truncate at PAGE_CACHE_SIZE.
2415          */
2416         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
2417
2418         /* Initialize the page */
2419         memset(page, 0, size);
2420
2421         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2422                 goto out;
2423         if (obd->obd_max_recoverable_clients == 0) {
2424                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2425                         goto out;
2426
2427                 goto fclose;
2428         }
2429
2430         /* sampled unlocked, but really... */
2431         if (obd->obd_recovering == 0) {
2432                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2433                         goto out;
2434                 if (lprocfs_obd_snprintf(&page, size, &len,
2435                                          "recovery_start: %lu\n",
2436                                          obd->obd_recovery_start) <= 0)
2437                         goto out;
2438                 if (lprocfs_obd_snprintf(&page, size, &len,
2439                                          "recovery_duration: %lu\n",
2440                                          obd->obd_recovery_end -
2441                                          obd->obd_recovery_start) <= 0)
2442                         goto out;
2443                 /* Number of clients that have completed recovery */
2444                 if (lprocfs_obd_snprintf(&page, size, &len,
2445                                          "completed_clients: %d/%d\n",
2446                                          obd->obd_max_recoverable_clients -
2447                                          obd->obd_stale_clients,
2448                                          obd->obd_max_recoverable_clients) <= 0)
2449                         goto out;
2450                 if (lprocfs_obd_snprintf(&page, size, &len,
2451                                          "replayed_requests: %d\n",
2452                                          obd->obd_replayed_requests) <= 0)
2453                         goto out;
2454                 if (lprocfs_obd_snprintf(&page, size, &len,
2455                                          "last_transno: "LPD64"\n",
2456                                          obd->obd_next_recovery_transno - 1)<=0)
2457                         goto out;
2458                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2459                                          obd->obd_version_recov ?
2460                                          "ENABLED" : "DISABLED") <=0)
2461                         goto out;
2462                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2463                                          obd->obd_no_ir ?
2464                                          "DISABLED" : "ENABLED") <= 0)
2465                         goto out;
2466                 goto fclose;
2467         }
2468
2469         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2470                 goto out;
2471         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2472                                  obd->obd_recovery_start) <= 0)
2473                 goto out;
2474         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2475                                  cfs_time_current_sec() >=
2476                                  obd->obd_recovery_start +
2477                                  obd->obd_recovery_timeout ? 0 :
2478                                  obd->obd_recovery_start +
2479                                  obd->obd_recovery_timeout -
2480                                  cfs_time_current_sec()) <= 0)
2481                 goto out;
2482         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2483                                  cfs_atomic_read(&obd->obd_connected_clients),
2484                                  obd->obd_max_recoverable_clients) <= 0)
2485                 goto out;
2486         /* Number of clients that have completed recovery */
2487         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2488                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2489                 <= 0)
2490                 goto out;
2491         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2492                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2493                 <=0)
2494                 goto out;
2495         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2496                                  cfs_atomic_read(&obd->obd_connected_clients) -
2497                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2498                 <=0)
2499                 goto out;
2500         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2501                                  obd->obd_stale_clients) <= 0)
2502                 goto out;
2503         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2504                                  obd->obd_replayed_requests) <= 0)
2505                 goto out;
2506         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2507                                  obd->obd_requests_queued_for_recovery) <= 0)
2508                 goto out;
2509
2510         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2511                                  obd->obd_next_recovery_transno) <= 0)
2512                 goto out;
2513
2514 fclose:
2515         *eof = 1;
2516 out:
2517         return min(count, len - (int)off);
2518 }
2519 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2520
2521 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2522                              int count, int *eof, void *data)
2523 {
2524         struct obd_device *obd = (struct obd_device *)data;
2525         LASSERT(obd != NULL);
2526
2527         return snprintf(page, count, "%d\n",
2528                         obd->obd_recovery_ir_factor);
2529 }
2530 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2531
2532 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2533                              unsigned long count, void *data)
2534 {
2535         struct obd_device *obd = (struct obd_device *)data;
2536         int val, rc;
2537         LASSERT(obd != NULL);
2538
2539         rc = lprocfs_write_helper(buffer, count, &val);
2540         if (rc)
2541                 return rc;
2542
2543         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2544                 return -EINVAL;
2545
2546         obd->obd_recovery_ir_factor = val;
2547         return count;
2548 }
2549 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2550
2551 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2552                                       int count, int *eof, void *data)
2553 {
2554         struct obd_device *obd = (struct obd_device *)data;
2555         LASSERT(obd != NULL);
2556
2557         return snprintf(page, count, "%d\n",
2558                         obd->obd_recovery_timeout);
2559 }
2560 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2561
2562 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2563                                       unsigned long count, void *data)
2564 {
2565         struct obd_device *obd = (struct obd_device *)data;
2566         int val, rc;
2567         LASSERT(obd != NULL);
2568
2569         rc = lprocfs_write_helper(buffer, count, &val);
2570         if (rc)
2571                 return rc;
2572
2573         obd->obd_recovery_timeout = val;
2574         return count;
2575 }
2576 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2577
2578 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2579                                       int count, int *eof, void *data)
2580 {
2581         struct obd_device *obd = data;
2582         LASSERT(obd != NULL);
2583
2584         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2585 }
2586 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2587
2588 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2589                                       unsigned long count, void *data)
2590 {
2591         struct obd_device *obd = data;
2592         int val, rc;
2593         LASSERT(obd != NULL);
2594
2595         rc = lprocfs_write_helper(buffer, count, &val);
2596         if (rc)
2597                 return rc;
2598
2599         obd->obd_recovery_time_hard = val;
2600         return count;
2601 }
2602 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2603
2604 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2605                                      int count, int *eof, void *data)
2606 {
2607         struct obd_device *dev = data;
2608         struct client_obd *cli = &dev->u.cli;
2609         int rc;
2610
2611         client_obd_list_lock(&cli->cl_loi_list_lock);
2612         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2613         client_obd_list_unlock(&cli->cl_loi_list_lock);
2614         return rc;
2615 }
2616 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2617
2618 #ifdef HAVE_SERVER_SUPPORT
2619 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2620                                int count, int *eof, void *data)
2621 {
2622         struct obd_device *obd = (struct obd_device *)data;
2623         struct obd_device_target *target = &obd->u.obt;
2624
2625         LASSERT(obd != NULL);
2626         LASSERT(target->obt_magic == OBT_MAGIC);
2627         *eof = 1;
2628         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2629 }
2630 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2631 #endif
2632 #endif /* LPROCFS*/