Whamcloud - gitweb
LU-1842 quota: remove quota code
[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, ping);
1713         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1714         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1715         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1716         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1717         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1718         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1719 }
1720 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1721
1722 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1723 {
1724         struct lprocfs_stats *stats;
1725         unsigned int num_stats;
1726         int rc, i;
1727
1728         LASSERT(obd->obd_stats == NULL);
1729         LASSERT(obd->obd_proc_entry != NULL);
1730         LASSERT(obd->obd_cntr_base == 0);
1731
1732         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1733                 num_private_stats - 1 /* o_owner */;
1734         stats = lprocfs_alloc_stats(num_stats, 0);
1735         if (stats == NULL)
1736                 return -ENOMEM;
1737
1738         lprocfs_init_ops_stats(num_private_stats, stats);
1739
1740         for (i = num_private_stats; i < num_stats; i++) {
1741                 /* If this LBUGs, it is likely that an obd
1742                  * operation was added to struct obd_ops in
1743                  * <obd.h>, and that the corresponding line item
1744                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1745                  * is missing from the list above. */
1746                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1747                          "Missing obd_stat initializer obd_op "
1748                          "operation at offset %d.\n", i - num_private_stats);
1749         }
1750         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1751         if (rc < 0) {
1752                 lprocfs_free_stats(&stats);
1753         } else {
1754                 obd->obd_stats  = stats;
1755                 obd->obd_cntr_base = num_private_stats;
1756         }
1757         return rc;
1758 }
1759 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1760
1761 void lprocfs_free_obd_stats(struct obd_device *obd)
1762 {
1763         if (obd->obd_stats)
1764                 lprocfs_free_stats(&obd->obd_stats);
1765 }
1766 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1767
1768 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1769 do {                                                                    \
1770         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1771         LASSERT(coffset < stats->ls_num);                               \
1772         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1773 } while (0)
1774
1775 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1776 {
1777         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1778         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1779         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1780         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1781         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1782         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1783         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1784         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1785         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1786         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1787         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1788         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1789         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1790         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1791         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1792         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1793         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1794         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1795         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1796         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1797         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1798         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1799         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1800         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1801         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1802         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1803         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1804         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1805         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1806         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1807         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1808         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1809 }
1810 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1811
1812 int lprocfs_alloc_md_stats(struct obd_device *obd,
1813                            unsigned num_private_stats)
1814 {
1815         struct lprocfs_stats *stats;
1816         unsigned int num_stats;
1817         int rc, i;
1818
1819         LASSERT(obd->md_stats == NULL);
1820         LASSERT(obd->obd_proc_entry != NULL);
1821         LASSERT(obd->md_cntr_base == 0);
1822
1823         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1824                     num_private_stats;
1825         stats = lprocfs_alloc_stats(num_stats, 0);
1826         if (stats == NULL)
1827                 return -ENOMEM;
1828
1829         lprocfs_init_mps_stats(num_private_stats, stats);
1830
1831         for (i = num_private_stats; i < num_stats; i++) {
1832                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1833                         CERROR("Missing md_stat initializer md_op "
1834                                "operation at offset %d. Aborting.\n",
1835                                i - num_private_stats);
1836                         LBUG();
1837                 }
1838         }
1839         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1840         if (rc < 0) {
1841                 lprocfs_free_stats(&stats);
1842         } else {
1843                 obd->md_stats  = stats;
1844                 obd->md_cntr_base = num_private_stats;
1845         }
1846         return rc;
1847 }
1848 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1849
1850 void lprocfs_free_md_stats(struct obd_device *obd)
1851 {
1852         struct lprocfs_stats *stats = obd->md_stats;
1853
1854         if (stats != NULL) {
1855                 obd->md_stats = NULL;
1856                 obd->md_cntr_base = 0;
1857                 lprocfs_free_stats(&stats);
1858         }
1859 }
1860 EXPORT_SYMBOL(lprocfs_free_md_stats);
1861
1862 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1863 {
1864         lprocfs_counter_init(ldlm_stats,
1865                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1866                              0, "ldlm_enqueue", "reqs");
1867         lprocfs_counter_init(ldlm_stats,
1868                              LDLM_CONVERT - LDLM_FIRST_OPC,
1869                              0, "ldlm_convert", "reqs");
1870         lprocfs_counter_init(ldlm_stats,
1871                              LDLM_CANCEL - LDLM_FIRST_OPC,
1872                              0, "ldlm_cancel", "reqs");
1873         lprocfs_counter_init(ldlm_stats,
1874                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1875                              0, "ldlm_bl_callback", "reqs");
1876         lprocfs_counter_init(ldlm_stats,
1877                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1878                              0, "ldlm_cp_callback", "reqs");
1879         lprocfs_counter_init(ldlm_stats,
1880                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1881                              0, "ldlm_gl_callback", "reqs");
1882 }
1883 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1884
1885 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1886                          int *eof,  void *data)
1887 {
1888         struct obd_export *exp = data;
1889         LASSERT(exp != NULL);
1890         *eof = 1;
1891         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1892 }
1893
1894 struct exp_uuid_cb_data {
1895         char                   *page;
1896         int                     count;
1897         int                    *eof;
1898         int                    *len;
1899 };
1900
1901 static void
1902 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1903                             int count, int *eof, int *len)
1904 {
1905         cb_data->page = page;
1906         cb_data->count = count;
1907         cb_data->eof = eof;
1908         cb_data->len = len;
1909 }
1910
1911 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1912                            cfs_hlist_node_t *hnode, void *cb_data)
1913
1914 {
1915         struct obd_export *exp = cfs_hash_object(hs, hnode);
1916         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1917
1918         if (exp->exp_nid_stats)
1919                 *data->len += snprintf((data->page + *data->len),
1920                                        data->count, "%s\n",
1921                                        obd_uuid2str(&exp->exp_client_uuid));
1922         return 0;
1923 }
1924
1925 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1926                         int *eof,  void *data)
1927 {
1928         struct nid_stat *stats = (struct nid_stat *)data;
1929         struct exp_uuid_cb_data cb_data;
1930         struct obd_device *obd = stats->nid_obd;
1931         int len = 0;
1932
1933         *eof = 1;
1934         page[0] = '\0';
1935         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1936         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1937                               lprocfs_exp_print_uuid, &cb_data);
1938         return (*cb_data.len);
1939 }
1940
1941 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1942                            cfs_hlist_node_t *hnode, void *cb_data)
1943
1944 {
1945         struct exp_uuid_cb_data *data = cb_data;
1946         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1947
1948         if (exp->exp_lock_hash != NULL) {
1949                 if (!*data->len) {
1950                         *data->len += cfs_hash_debug_header(data->page,
1951                                                             data->count);
1952                 }
1953                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1954                                                  data->count);
1955         }
1956
1957         return 0;
1958 }
1959
1960 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1961                         int *eof,  void *data)
1962 {
1963         struct nid_stat *stats = (struct nid_stat *)data;
1964         struct exp_uuid_cb_data cb_data;
1965         struct obd_device *obd = stats->nid_obd;
1966         int len = 0;
1967
1968         *eof = 1;
1969         page[0] = '\0';
1970         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1971
1972         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1973                               lprocfs_exp_print_hash, &cb_data);
1974         return (*cb_data.len);
1975 }
1976
1977 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1978                                         int count, int *eof,  void *data)
1979 {
1980         *eof = 1;
1981         return snprintf(page, count, "%s\n",
1982                         "Write into this file to clear all nid stats and "
1983                         "stale nid entries");
1984 }
1985 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1986
1987 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1988 {
1989         struct nid_stat *stat = obj;
1990         int i;
1991         ENTRY;
1992
1993         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1994         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1995                 /* object has only hash references. */
1996                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
1997                 cfs_list_move(&stat->nid_list, data);
1998                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
1999                 RETURN(1);
2000         }
2001         /* we has reference to object - only clear data*/
2002         if (stat->nid_stats)
2003                 lprocfs_clear_stats(stat->nid_stats);
2004
2005         if (stat->nid_brw_stats) {
2006                 for (i = 0; i < BRW_LAST; i++)
2007                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
2008         }
2009         RETURN(0);
2010 }
2011
2012 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
2013                                   unsigned long count, void *data)
2014 {
2015         struct obd_device *obd = (struct obd_device *)data;
2016         struct nid_stat *client_stat;
2017         CFS_LIST_HEAD(free_list);
2018
2019         cfs_hash_cond_del(obd->obd_nid_stats_hash,
2020                           lprocfs_nid_stats_clear_write_cb, &free_list);
2021
2022         while (!cfs_list_empty(&free_list)) {
2023                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
2024                                              nid_list);
2025                 cfs_list_del_init(&client_stat->nid_list);
2026                 lprocfs_free_client_stats(client_stat);
2027         }
2028
2029         return count;
2030 }
2031 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
2032
2033 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2034 {
2035         struct nid_stat *new_stat, *old_stat;
2036         struct obd_device *obd = NULL;
2037         cfs_proc_dir_entry_t *entry;
2038         char *buffer = NULL;
2039         int rc = 0;
2040         ENTRY;
2041
2042         *newnid = 0;
2043
2044         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2045             !exp->exp_obd->obd_nid_stats_hash)
2046                 RETURN(-EINVAL);
2047
2048         /* not test against zero because eric say:
2049          * You may only test nid against another nid, or LNET_NID_ANY.
2050          * Anything else is nonsense.*/
2051         if (!nid || *nid == LNET_NID_ANY)
2052                 RETURN(0);
2053
2054         obd = exp->exp_obd;
2055
2056         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2057
2058         OBD_ALLOC_PTR(new_stat);
2059         if (new_stat == NULL)
2060                 RETURN(-ENOMEM);
2061
2062         new_stat->nid               = *nid;
2063         new_stat->nid_obd           = exp->exp_obd;
2064         /* we need set default refcount to 1 to balance obd_disconnect */
2065         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
2066
2067         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2068                                            nid, &new_stat->nid_hash);
2069         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2070                old_stat, libcfs_nid2str(*nid),
2071                cfs_atomic_read(&new_stat->nid_exp_ref_count));
2072
2073         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
2074          * been and will never be called. */
2075         if (exp->exp_nid_stats) {
2076                 nidstat_putref(exp->exp_nid_stats);
2077                 exp->exp_nid_stats = NULL;
2078         }
2079
2080         /* Return -EALREADY here so that we know that the /proc
2081          * entry already has been created */
2082         if (old_stat != new_stat) {
2083                 exp->exp_nid_stats = old_stat;
2084                 GOTO(destroy_new, rc = -EALREADY);
2085         }
2086         /* not found - create */
2087         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2088         if (buffer == NULL)
2089                 GOTO(destroy_new, rc = -ENOMEM);
2090
2091         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2092         new_stat->nid_proc = lprocfs_register(buffer,
2093                                               obd->obd_proc_exports_entry,
2094                                               NULL, NULL);
2095         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2096
2097         if (new_stat->nid_proc == NULL) {
2098                 CERROR("Error making export directory for nid %s\n",
2099                        libcfs_nid2str(*nid));
2100                 GOTO(destroy_new_ns, rc = -ENOMEM);
2101         }
2102
2103         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2104                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2105         if (IS_ERR(entry)) {
2106                 CWARN("Error adding the NID stats file\n");
2107                 rc = PTR_ERR(entry);
2108                 GOTO(destroy_new_ns, rc);
2109         }
2110
2111         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2112                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2113         if (IS_ERR(entry)) {
2114                 CWARN("Error adding the hash file\n");
2115                 rc = PTR_ERR(entry);
2116                 GOTO(destroy_new_ns, rc);
2117         }
2118
2119         exp->exp_nid_stats = new_stat;
2120         *newnid = 1;
2121         /* protect competitive add to list, not need locking on destroy */
2122         cfs_spin_lock(&obd->obd_nid_lock);
2123         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2124         cfs_spin_unlock(&obd->obd_nid_lock);
2125
2126         RETURN(rc);
2127
2128 destroy_new_ns:
2129         if (new_stat->nid_proc != NULL)
2130                 lprocfs_remove(&new_stat->nid_proc);
2131         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2132
2133 destroy_new:
2134         nidstat_putref(new_stat);
2135         OBD_FREE_PTR(new_stat);
2136         RETURN(rc);
2137 }
2138 EXPORT_SYMBOL(lprocfs_exp_setup);
2139
2140 int lprocfs_exp_cleanup(struct obd_export *exp)
2141 {
2142         struct nid_stat *stat = exp->exp_nid_stats;
2143
2144         if(!stat || !exp->exp_obd)
2145                 RETURN(0);
2146
2147         nidstat_putref(exp->exp_nid_stats);
2148         exp->exp_nid_stats = NULL;
2149
2150         return 0;
2151 }
2152 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2153
2154 int lprocfs_write_helper(const char *buffer, unsigned long count,
2155                          int *val)
2156 {
2157         return lprocfs_write_frac_helper(buffer, count, val, 1);
2158 }
2159 EXPORT_SYMBOL(lprocfs_write_helper);
2160
2161 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2162                               int *val, int mult)
2163 {
2164         char kernbuf[20], *end, *pbuf;
2165
2166         if (count > (sizeof(kernbuf) - 1))
2167                 return -EINVAL;
2168
2169         if (cfs_copy_from_user(kernbuf, buffer, count))
2170                 return -EFAULT;
2171
2172         kernbuf[count] = '\0';
2173         pbuf = kernbuf;
2174         if (*pbuf == '-') {
2175                 mult = -mult;
2176                 pbuf++;
2177         }
2178
2179         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2180         if (pbuf == end)
2181                 return -EINVAL;
2182
2183         if (end != NULL && *end == '.') {
2184                 int temp_val, pow = 1;
2185                 int i;
2186
2187                 pbuf = end + 1;
2188                 if (strlen(pbuf) > 5)
2189                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2190
2191                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2192
2193                 if (pbuf < end) {
2194                         for (i = 0; i < (end - pbuf); i++)
2195                                 pow *= 10;
2196
2197                         *val += temp_val / pow;
2198                 }
2199         }
2200         return 0;
2201 }
2202 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2203
2204 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2205                              int mult)
2206 {
2207         long decimal_val, frac_val;
2208         int prtn;
2209
2210         if (count < 10)
2211                 return -EINVAL;
2212
2213         decimal_val = val / mult;
2214         prtn = snprintf(buffer, count, "%ld", decimal_val);
2215         frac_val = val % mult;
2216
2217         if (prtn < (count - 4) && frac_val > 0) {
2218                 long temp_frac;
2219                 int i, temp_mult = 1, frac_bits = 0;
2220
2221                 temp_frac = frac_val * 10;
2222                 buffer[prtn++] = '.';
2223                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2224                         /* only reserved 2 bits fraction */
2225                         buffer[prtn++] ='0';
2226                         temp_frac *= 10;
2227                         frac_bits++;
2228                 }
2229                 /*
2230                  * Need to think these cases :
2231                  *      1. #echo x.00 > /proc/xxx       output result : x
2232                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2233                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2234                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2235                  *      Only reserved 2 bits fraction.
2236                  */
2237                 for (i = 0; i < (5 - prtn); i++)
2238                         temp_mult *= 10;
2239
2240                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2241                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2242                                  frac_val * temp_mult / mult);
2243
2244                 prtn--;
2245                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2246                         prtn--;
2247                         if (buffer[prtn] == '.') {
2248                                 prtn--;
2249                                 break;
2250                         }
2251                 }
2252                 prtn++;
2253         }
2254         buffer[prtn++] ='\n';
2255         return prtn;
2256 }
2257 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2258
2259 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2260 {
2261         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2262 }
2263 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2264
2265 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2266                               __u64 *val, int mult)
2267 {
2268         char kernbuf[22], *end, *pbuf;
2269         __u64 whole, frac = 0, units;
2270         unsigned frac_d = 1;
2271
2272         if (count > (sizeof(kernbuf) - 1))
2273                 return -EINVAL;
2274
2275         if (cfs_copy_from_user(kernbuf, buffer, count))
2276                 return -EFAULT;
2277
2278         kernbuf[count] = '\0';
2279         pbuf = kernbuf;
2280         if (*pbuf == '-') {
2281                 mult = -mult;
2282                 pbuf++;
2283         }
2284
2285         whole = simple_strtoull(pbuf, &end, 10);
2286         if (pbuf == end)
2287                 return -EINVAL;
2288
2289         if (end != NULL && *end == '.') {
2290                 int i;
2291                 pbuf = end + 1;
2292
2293                 /* need to limit frac_d to a __u32 */
2294                 if (strlen(pbuf) > 10)
2295                         pbuf[10] = '\0';
2296
2297                 frac = simple_strtoull(pbuf, &end, 10);
2298                 /* count decimal places */
2299                 for (i = 0; i < (end - pbuf); i++)
2300                         frac_d *= 10;
2301         }
2302
2303         units = 1;
2304         switch(*end) {
2305         case 'p': case 'P':
2306                 units <<= 10;
2307         case 't': case 'T':
2308                 units <<= 10;
2309         case 'g': case 'G':
2310                 units <<= 10;
2311         case 'm': case 'M':
2312                 units <<= 10;
2313         case 'k': case 'K':
2314                 units <<= 10;
2315         }
2316         /* Specified units override the multiplier */
2317         if (units)
2318                 mult = mult < 0 ? -units : units;
2319
2320         frac *= mult;
2321         do_div(frac, frac_d);
2322         *val = whole * mult + frac;
2323         return 0;
2324 }
2325 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2326
2327 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2328                        struct file_operations *seq_fops, void *data)
2329 {
2330         struct proc_dir_entry *entry;
2331         ENTRY;
2332
2333         LPROCFS_WRITE_ENTRY();
2334         entry = create_proc_entry(name, mode, parent);
2335         if (entry) {
2336                 entry->proc_fops = seq_fops;
2337                 entry->data = data;
2338         }
2339         LPROCFS_WRITE_EXIT();
2340
2341         if (entry == NULL)
2342                 RETURN(-ENOMEM);
2343
2344         RETURN(0);
2345 }
2346 EXPORT_SYMBOL(lprocfs_seq_create);
2347
2348 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2349                                       mode_t mode,
2350                                       struct file_operations *seq_fops,
2351                                       void *data)
2352 {
2353         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2354                                    mode, seq_fops, data));
2355 }
2356 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2357
2358 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2359 {
2360         if (value >= OBD_HIST_MAX)
2361                 value = OBD_HIST_MAX - 1;
2362
2363         cfs_spin_lock(&oh->oh_lock);
2364         oh->oh_buckets[value]++;
2365         cfs_spin_unlock(&oh->oh_lock);
2366 }
2367 EXPORT_SYMBOL(lprocfs_oh_tally);
2368
2369 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2370 {
2371         unsigned int val;
2372
2373         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2374                 ;
2375
2376         lprocfs_oh_tally(oh, val);
2377 }
2378 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2379
2380 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2381 {
2382         unsigned long ret = 0;
2383         int i;
2384
2385         for (i = 0; i < OBD_HIST_MAX; i++)
2386                 ret +=  oh->oh_buckets[i];
2387         return ret;
2388 }
2389 EXPORT_SYMBOL(lprocfs_oh_sum);
2390
2391 void lprocfs_oh_clear(struct obd_histogram *oh)
2392 {
2393         cfs_spin_lock(&oh->oh_lock);
2394         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2395         cfs_spin_unlock(&oh->oh_lock);
2396 }
2397 EXPORT_SYMBOL(lprocfs_oh_clear);
2398
2399 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2400                         int count, int *eof, void *data)
2401 {
2402         struct obd_device *obd = data;
2403         int c = 0;
2404
2405         if (obd == NULL)
2406                 return 0;
2407
2408         c += cfs_hash_debug_header(page, count);
2409         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2410         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2411         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2412
2413         return c;
2414 }
2415 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2416
2417 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2418                                    int count, int *eof, void *data)
2419 {
2420         struct obd_device *obd = data;
2421         int len = 0, size;
2422
2423         LASSERT(obd != NULL);
2424         LASSERT(count >= 0);
2425
2426         /* Set start of user data returned to
2427            page + off since the user may have
2428            requested to read much smaller than
2429            what we need to read */
2430         *start = page + off;
2431
2432         /* We know we are allocated a page here.
2433            Also we know that this function will
2434            not need to write more than a page
2435            so we can truncate at CFS_PAGE_SIZE.  */
2436         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2437
2438         /* Initialize the page */
2439         memset(page, 0, size);
2440
2441         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2442                 goto out;
2443         if (obd->obd_max_recoverable_clients == 0) {
2444                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2445                         goto out;
2446
2447                 goto fclose;
2448         }
2449
2450         /* sampled unlocked, but really... */
2451         if (obd->obd_recovering == 0) {
2452                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2453                         goto out;
2454                 if (lprocfs_obd_snprintf(&page, size, &len,
2455                                          "recovery_start: %lu\n",
2456                                          obd->obd_recovery_start) <= 0)
2457                         goto out;
2458                 if (lprocfs_obd_snprintf(&page, size, &len,
2459                                          "recovery_duration: %lu\n",
2460                                          obd->obd_recovery_end -
2461                                          obd->obd_recovery_start) <= 0)
2462                         goto out;
2463                 /* Number of clients that have completed recovery */
2464                 if (lprocfs_obd_snprintf(&page, size, &len,
2465                                          "completed_clients: %d/%d\n",
2466                                          obd->obd_max_recoverable_clients -
2467                                          obd->obd_stale_clients,
2468                                          obd->obd_max_recoverable_clients) <= 0)
2469                         goto out;
2470                 if (lprocfs_obd_snprintf(&page, size, &len,
2471                                          "replayed_requests: %d\n",
2472                                          obd->obd_replayed_requests) <= 0)
2473                         goto out;
2474                 if (lprocfs_obd_snprintf(&page, size, &len,
2475                                          "last_transno: "LPD64"\n",
2476                                          obd->obd_next_recovery_transno - 1)<=0)
2477                         goto out;
2478                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2479                                          obd->obd_version_recov ?
2480                                          "ENABLED" : "DISABLED") <=0)
2481                         goto out;
2482                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2483                                          obd->obd_no_ir ?
2484                                          "DISABLED" : "ENABLED") <= 0)
2485                         goto out;
2486                 goto fclose;
2487         }
2488
2489         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2490                 goto out;
2491         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2492                                  obd->obd_recovery_start) <= 0)
2493                 goto out;
2494         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2495                                  cfs_time_current_sec() >=
2496                                  obd->obd_recovery_start +
2497                                  obd->obd_recovery_timeout ? 0 :
2498                                  obd->obd_recovery_start +
2499                                  obd->obd_recovery_timeout -
2500                                  cfs_time_current_sec()) <= 0)
2501                 goto out;
2502         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2503                                  cfs_atomic_read(&obd->obd_connected_clients),
2504                                  obd->obd_max_recoverable_clients) <= 0)
2505                 goto out;
2506         /* Number of clients that have completed recovery */
2507         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2508                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2509                 <= 0)
2510                 goto out;
2511         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2512                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2513                 <=0)
2514                 goto out;
2515         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2516                                  cfs_atomic_read(&obd->obd_connected_clients) -
2517                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2518                 <=0)
2519                 goto out;
2520         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2521                                  obd->obd_stale_clients) <= 0)
2522                 goto out;
2523         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2524                                  obd->obd_replayed_requests) <= 0)
2525                 goto out;
2526         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2527                                  obd->obd_requests_queued_for_recovery) <= 0)
2528                 goto out;
2529
2530         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2531                                  obd->obd_next_recovery_transno) <= 0)
2532                 goto out;
2533
2534 fclose:
2535         *eof = 1;
2536 out:
2537         return min(count, len - (int)off);
2538 }
2539 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2540
2541 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2542                              int count, int *eof, void *data)
2543 {
2544         struct obd_device *obd = (struct obd_device *)data;
2545         LASSERT(obd != NULL);
2546
2547         return snprintf(page, count, "%d\n",
2548                         obd->obd_recovery_ir_factor);
2549 }
2550 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2551
2552 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2553                              unsigned long count, void *data)
2554 {
2555         struct obd_device *obd = (struct obd_device *)data;
2556         int val, rc;
2557         LASSERT(obd != NULL);
2558
2559         rc = lprocfs_write_helper(buffer, count, &val);
2560         if (rc)
2561                 return rc;
2562
2563         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2564                 return -EINVAL;
2565
2566         obd->obd_recovery_ir_factor = val;
2567         return count;
2568 }
2569 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2570
2571 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2572                                       int count, int *eof, void *data)
2573 {
2574         struct obd_device *obd = (struct obd_device *)data;
2575         LASSERT(obd != NULL);
2576
2577         return snprintf(page, count, "%d\n",
2578                         obd->obd_recovery_timeout);
2579 }
2580 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2581
2582 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2583                                       unsigned long count, void *data)
2584 {
2585         struct obd_device *obd = (struct obd_device *)data;
2586         int val, rc;
2587         LASSERT(obd != NULL);
2588
2589         rc = lprocfs_write_helper(buffer, count, &val);
2590         if (rc)
2591                 return rc;
2592
2593         obd->obd_recovery_timeout = val;
2594         return count;
2595 }
2596 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2597
2598 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2599                                       int count, int *eof, void *data)
2600 {
2601         struct obd_device *obd = data;
2602         LASSERT(obd != NULL);
2603
2604         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2605 }
2606 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2607
2608 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2609                                       unsigned long count, void *data)
2610 {
2611         struct obd_device *obd = data;
2612         int val, rc;
2613         LASSERT(obd != NULL);
2614
2615         rc = lprocfs_write_helper(buffer, count, &val);
2616         if (rc)
2617                 return rc;
2618
2619         obd->obd_recovery_time_hard = val;
2620         return count;
2621 }
2622 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2623
2624 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2625                           int count, int *eof, void *data)
2626 {
2627         struct obd_device *obd = (struct obd_device *)data;
2628
2629         LASSERT(obd != NULL);
2630         LASSERT(mnt_get_devname(obd->u.obt.obt_vfsmnt));
2631         *eof = 1;
2632         return snprintf(page, count, "%s\n",
2633                         mnt_get_devname(obd->u.obt.obt_vfsmnt));
2634 }
2635 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2636
2637 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2638                                      int count, int *eof, void *data)
2639 {
2640         struct obd_device *dev = data;
2641         struct client_obd *cli = &dev->u.cli;
2642         int rc;
2643
2644         client_obd_list_lock(&cli->cl_loi_list_lock);
2645         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2646         client_obd_list_unlock(&cli->cl_loi_list_lock);
2647         return rc;
2648 }
2649 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2650
2651 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2652                                int count, int *eof, void *data)
2653 {
2654         struct obd_device *obd = (struct obd_device *)data;
2655         struct obd_device_target *target = &obd->u.obt;
2656
2657         LASSERT(obd != NULL);
2658         LASSERT(target->obt_magic == OBT_MAGIC);
2659         *eof = 1;
2660         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2661 }
2662 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2663 #endif /* LPROCFS*/