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