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