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