Whamcloud - gitweb
LU-163 MDS returns 32/64-bit dir name hash according to client type
[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         "64bithash",
809         NULL
810 };
811
812 static int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
813 {
814         __u64 mask = 1;
815         int i, ret = 0;
816
817         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
818                 if (flags & mask)
819                         ret += snprintf(page + ret, count - ret, "%s%s",
820                                         ret ? sep : "", obd_connect_names[i]);
821         }
822         if (flags & ~(mask - 1))
823                 ret += snprintf(page + ret, count - ret,
824                                 "%sunknown flags "LPX64,
825                                 ret ? sep : "", flags & ~(mask - 1));
826         return ret;
827 }
828
829 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
830                       int *eof, void *data)
831 {
832         struct lprocfs_counter ret;
833         struct obd_device *obd = (struct obd_device *)data;
834         struct obd_import *imp;
835         struct obd_import_conn *conn;
836         int i, j, k, rw = 0;
837
838         LASSERT(obd != NULL);
839         LPROCFS_CLIMP_CHECK(obd);
840         imp = obd->u.cli.cl_import;
841         *eof = 1;
842
843         i = snprintf(page, count,
844                      "import:\n"
845                      "    name: %s\n"
846                      "    target: %s\n"
847                      "    state: %s\n"
848                      "    connect_flags: [",
849                      obd->obd_name,
850                      obd2cli_tgt(obd),
851                      ptlrpc_import_state_name(imp->imp_state));
852         i += obd_connect_flags2str(page + i, count - i,
853                                    imp->imp_connect_data.ocd_connect_flags,
854                                    ", ");
855         i += snprintf(page + i, count - i,
856                       "]\n"
857                       "    import_flags: [");
858         i += obd_import_flags2str(imp, page + i, count - i);
859
860         i += snprintf(page + i, count - i,
861                       "]\n"
862                       "    connection:\n"
863                       "       failover_nids: [");
864         cfs_spin_lock(&imp->imp_lock);
865         j = 0;
866         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
867                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
868                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
869                 j++;
870         }
871         cfs_spin_unlock(&imp->imp_lock);
872         i += snprintf(page + i, count - i,
873                       "]\n"
874                       "       current_connection: %s\n"
875                       "       connection_attempts: %u\n"
876                       "       generation: %u\n"
877                       "       in-progress_invalidations: %u\n",
878                       libcfs_nid2str(imp->imp_connection->c_peer.nid),
879                       imp->imp_conn_cnt,
880                       imp->imp_generation,
881                       cfs_atomic_read(&imp->imp_inval_count));
882
883         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
884         if (ret.lc_count != 0) {
885                 /* first argument to do_div MUST be __u64 */
886                 __u64 sum = ret.lc_sum;
887                 do_div(sum, ret.lc_count);
888                 ret.lc_sum = sum;
889         } else
890                 ret.lc_sum = 0;
891         i += snprintf(page + i, count - i,
892                       "    rpcs:\n"
893                       "       inflight: %u\n"
894                       "       unregistering: %u\n"
895                       "       timeouts: %u\n"
896                       "       avg_waittime: "LPU64" %s\n",
897                       cfs_atomic_read(&imp->imp_inflight),
898                       cfs_atomic_read(&imp->imp_unregistering),
899                       cfs_atomic_read(&imp->imp_timeouts),
900                       ret.lc_sum, ret.lc_units);
901
902         k = 0;
903         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
904                 if (imp->imp_at.iat_portal[j] == 0)
905                         break;
906                 k = max_t(unsigned int, k,
907                           at_get(&imp->imp_at.iat_service_estimate[j]));
908         }
909         i += snprintf(page + i, count - i,
910                       "    service_estimates:\n"
911                       "       services: %u sec\n"
912                       "       network: %u sec\n",
913                       k,
914                       at_get(&imp->imp_at.iat_net_latency));
915
916         i += snprintf(page + i, count - i,
917                       "    transactions:\n"
918                       "       last_replay: "LPU64"\n"
919                       "       peer_committed: "LPU64"\n"
920                       "       last_checked: "LPU64"\n",
921                       imp->imp_last_replay_transno,
922                       imp->imp_peer_committed_transno,
923                       imp->imp_last_transno_checked);
924
925         /* avg data rates */
926         for (rw = 0; rw <= 1; rw++) {
927                 lprocfs_stats_collect(obd->obd_svc_stats,
928                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
929                                       &ret);
930                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
931                         /* first argument to do_div MUST be __u64 */
932                         __u64 sum = ret.lc_sum;
933                         do_div(sum, ret.lc_count);
934                         ret.lc_sum = sum;
935                         i += snprintf(page + i, count - i,
936                                       "    %s_data_averages:\n"
937                                       "       bytes_per_rpc: "LPU64"\n",
938                                       rw ? "write" : "read",
939                                       ret.lc_sum);
940                 }
941                 k = (int)ret.lc_sum;
942                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
943                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
944                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
945                         /* first argument to do_div MUST be __u64 */
946                         __u64 sum = ret.lc_sum;
947                         do_div(sum, ret.lc_count);
948                         ret.lc_sum = sum;
949                         i += snprintf(page + i, count - i,
950                                       "       %s_per_rpc: "LPU64"\n",
951                                       ret.lc_units, ret.lc_sum);
952                         j = (int)ret.lc_sum;
953                         if (j > 0)
954                                 i += snprintf(page + i, count - i,
955                                               "       MB_per_sec: %u.%.02u\n",
956                                               k / j, (100 * k / j) % 100);
957                 }
958         }
959
960         LPROCFS_CLIMP_EXIT(obd);
961         return i;
962 }
963
964 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
965                       int *eof, void *data)
966 {
967         struct obd_device *obd = (struct obd_device *)data;
968         struct obd_import *imp;
969         int i, j, k;
970
971         LASSERT(obd != NULL);
972         LPROCFS_CLIMP_CHECK(obd);
973         imp = obd->u.cli.cl_import;
974         *eof = 1;
975
976         i = snprintf(page, count, "current_state: %s\n",
977                      ptlrpc_import_state_name(imp->imp_state));
978         i += snprintf(page + i, count - i,
979                       "state_history:\n");
980         k = imp->imp_state_hist_idx;
981         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
982                 struct import_state_hist *ish =
983                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
984                 if (ish->ish_state == 0)
985                         continue;
986                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
987                               ish->ish_time,
988                               ptlrpc_import_state_name(ish->ish_state));
989         }
990
991         LPROCFS_CLIMP_EXIT(obd);
992         return i;
993 }
994
995 int lprocfs_at_hist_helper(char *page, int count, int rc,
996                            struct adaptive_timeout *at)
997 {
998         int i;
999         for (i = 0; i < AT_BINS; i++)
1000                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1001         rc += snprintf(page + rc, count - rc, "\n");
1002         return rc;
1003 }
1004
1005 /* See also ptlrpc_lprocfs_rd_timeouts */
1006 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1007                         int *eof, void *data)
1008 {
1009         struct obd_device *obd = (struct obd_device *)data;
1010         struct obd_import *imp;
1011         unsigned int cur, worst;
1012         time_t now, worstt;
1013         struct dhms ts;
1014         int i, rc = 0;
1015
1016         LASSERT(obd != NULL);
1017         LPROCFS_CLIMP_CHECK(obd);
1018         imp = obd->u.cli.cl_import;
1019         *eof = 1;
1020
1021         now = cfs_time_current_sec();
1022
1023         /* Some network health info for kicks */
1024         s2dhms(&ts, now - imp->imp_last_reply_time);
1025         rc += snprintf(page + rc, count - rc,
1026                        "%-10s : %ld, "DHMS_FMT" ago\n",
1027                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1028
1029         cur = at_get(&imp->imp_at.iat_net_latency);
1030         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1031         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1032         s2dhms(&ts, now - worstt);
1033         rc += snprintf(page + rc, count - rc,
1034                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1035                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1036         rc = lprocfs_at_hist_helper(page, count, rc,
1037                                     &imp->imp_at.iat_net_latency);
1038
1039         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1040                 if (imp->imp_at.iat_portal[i] == 0)
1041                         break;
1042                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1043                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1044                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1045                 s2dhms(&ts, now - worstt);
1046                 rc += snprintf(page + rc, count - rc,
1047                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1048                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1049                                cur, worst, worstt, DHMS_VARS(&ts));
1050                 rc = lprocfs_at_hist_helper(page, count, rc,
1051                                           &imp->imp_at.iat_service_estimate[i]);
1052         }
1053
1054         LPROCFS_CLIMP_EXIT(obd);
1055         return rc;
1056 }
1057
1058 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1059                              int count, int *eof, void *data)
1060 {
1061         struct obd_device *obd = data;
1062         __u64 flags;
1063         int ret = 0;
1064
1065         LPROCFS_CLIMP_CHECK(obd);
1066         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1067         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1068         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1069         ret += snprintf(page + ret, count - ret, "\n");
1070         LPROCFS_CLIMP_EXIT(obd);
1071         return ret;
1072 }
1073 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1074
1075 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1076                            int *eof,  void *data)
1077 {
1078         struct obd_device *obd = data;
1079
1080         LASSERT(obd != NULL);
1081         *eof = 1;
1082         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1083 }
1084
1085 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1086                        int *eof, void *data)
1087 {
1088         struct obd_type *class = (struct obd_type*) data;
1089
1090         LASSERT(class != NULL);
1091         *eof = 1;
1092         return snprintf(page, count, "%d\n", class->typ_refcnt);
1093 }
1094
1095 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1096 {
1097         int rc = 0;
1098
1099         LASSERT(obd != NULL);
1100         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1101         LASSERT(obd->obd_type->typ_procroot != NULL);
1102
1103         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1104                                                obd->obd_type->typ_procroot,
1105                                                list, obd);
1106         if (IS_ERR(obd->obd_proc_entry)) {
1107                 rc = PTR_ERR(obd->obd_proc_entry);
1108                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1109                 obd->obd_proc_entry = NULL;
1110         }
1111         return rc;
1112 }
1113
1114 int lprocfs_obd_cleanup(struct obd_device *obd)
1115 {
1116         if (!obd)
1117                 return -EINVAL;
1118         if (obd->obd_proc_exports_entry) {
1119                 /* Should be no exports left */
1120                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1121                 lprocfs_remove(&obd->obd_proc_exports_entry);
1122                 obd->obd_proc_exports_entry = NULL;
1123         }
1124         if (obd->obd_proc_entry) {
1125                 lprocfs_remove(&obd->obd_proc_entry);
1126                 obd->obd_proc_entry = NULL;
1127         }
1128         return 0;
1129 }
1130
1131 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1132 {
1133         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1134                client_stat->nid_proc, client_stat->nid_stats,
1135                client_stat->nid_brw_stats);
1136
1137         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1138                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1139                  atomic_read(&client_stat->nid_exp_ref_count));
1140
1141         cfs_hlist_del_init(&client_stat->nid_hash);
1142
1143         if (client_stat->nid_proc)
1144                 lprocfs_remove(&client_stat->nid_proc);
1145
1146         if (client_stat->nid_stats)
1147                 lprocfs_free_stats(&client_stat->nid_stats);
1148
1149         if (client_stat->nid_brw_stats)
1150                 OBD_FREE_PTR(client_stat->nid_brw_stats);
1151
1152         if (client_stat->nid_ldlm_stats)
1153                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1154
1155         OBD_FREE_PTR(client_stat);
1156         return;
1157
1158 }
1159
1160 void lprocfs_free_per_client_stats(struct obd_device *obd)
1161 {
1162         struct nid_stat *stat;
1163         ENTRY;
1164
1165         /* we need extra list - because hash_exit called to early */
1166         /* not need locking because all clients is died */
1167         while(!cfs_list_empty(&obd->obd_nid_stats)) {
1168                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1169                                       struct nid_stat, nid_list);
1170                 cfs_list_del_init(&stat->nid_list);
1171                 lprocfs_free_client_stats(stat);
1172         }
1173
1174         EXIT;
1175 }
1176
1177 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1178                                           enum lprocfs_stats_flags flags)
1179 {
1180         struct lprocfs_stats *stats;
1181         unsigned int percpusize;
1182         unsigned int i, j;
1183         unsigned int num_cpu;
1184
1185         if (num == 0)
1186                 return NULL;
1187
1188         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1189                 num_cpu = 1;
1190         else
1191                 num_cpu = cfs_num_possible_cpus();
1192
1193         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1194         if (stats == NULL)
1195                 return NULL;
1196
1197         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
1198                 stats->ls_flags = flags;
1199                 cfs_spin_lock_init(&stats->ls_lock);
1200                 /* Use this lock only if there are no percpu areas */
1201         } else {
1202                 stats->ls_flags = 0;
1203         }
1204
1205         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1206         if (num_cpu > 1)
1207                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1208
1209         for (i = 0; i < num_cpu; i++) {
1210                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
1211                 if (stats->ls_percpu[i] == NULL) {
1212                         for (j = 0; j < i; j++) {
1213                                 OBD_FREE(stats->ls_percpu[j], percpusize);
1214                                 stats->ls_percpu[j] = NULL;
1215                         }
1216                         break;
1217                 }
1218         }
1219         if (stats->ls_percpu[0] == NULL) {
1220                 OBD_FREE(stats, offsetof(typeof(*stats),
1221                                          ls_percpu[num_cpu]));
1222                 return NULL;
1223         }
1224
1225         stats->ls_num = num;
1226         return stats;
1227 }
1228
1229 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1230 {
1231         struct lprocfs_stats *stats = *statsh;
1232         unsigned int num_cpu;
1233         unsigned int percpusize;
1234         unsigned int i;
1235
1236         if (stats == NULL || stats->ls_num == 0)
1237                 return;
1238         *statsh = NULL;
1239
1240         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1241                 num_cpu = 1;
1242         else
1243                 num_cpu = cfs_num_possible_cpus();
1244
1245         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1246         if (num_cpu > 1)
1247                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1248         for (i = 0; i < num_cpu; i++)
1249                 OBD_FREE(stats->ls_percpu[i], percpusize);
1250         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1251 }
1252
1253 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1254 {
1255         struct lprocfs_counter *percpu_cntr;
1256         int i,j;
1257         unsigned int num_cpu;
1258
1259         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1260
1261         for (i = 0; i < num_cpu; i++) {
1262                 for (j = 0; j < stats->ls_num; j++) {
1263                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1264                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1265                         percpu_cntr->lc_count = 0;
1266                         percpu_cntr->lc_sum = 0;
1267                         percpu_cntr->lc_min = LC_MIN_INIT;
1268                         percpu_cntr->lc_max = 0;
1269                         percpu_cntr->lc_sumsquare = 0;
1270                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1271                 }
1272         }
1273
1274         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU);
1275 }
1276
1277 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1278                                        size_t len, loff_t *off)
1279 {
1280         struct seq_file *seq = file->private_data;
1281         struct lprocfs_stats *stats = seq->private;
1282
1283         lprocfs_clear_stats(stats);
1284
1285         return len;
1286 }
1287
1288 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1289 {
1290         struct lprocfs_stats *stats = p->private;
1291         /* return 1st cpu location */
1292         return (*pos >= stats->ls_num) ? NULL :
1293                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1294 }
1295
1296 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1297 {
1298 }
1299
1300 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1301 {
1302         struct lprocfs_stats *stats = p->private;
1303         ++*pos;
1304         return (*pos >= stats->ls_num) ? NULL :
1305                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1306 }
1307
1308 /* seq file export of one lprocfs counter */
1309 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1310 {
1311        struct lprocfs_stats *stats = p->private;
1312        struct lprocfs_counter *cntr = v;
1313        struct lprocfs_counter ret;
1314        int idx, rc = 0;
1315
1316        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1317                struct timeval now;
1318                cfs_gettimeofday(&now);
1319                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1320                                "snapshot_time", now.tv_sec, now.tv_usec);
1321                if (rc < 0)
1322                        return rc;
1323        }
1324        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1325
1326        lprocfs_stats_collect(stats, idx, &ret);
1327
1328        if (ret.lc_count == 0)
1329                goto out;
1330
1331        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1332                        ret.lc_count, cntr->lc_units);
1333
1334        if (rc < 0)
1335                goto out;
1336
1337        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1338                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1339                                ret.lc_min, ret.lc_max, ret.lc_sum);
1340                if (rc < 0)
1341                        goto out;
1342                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1343                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1344                if (rc < 0)
1345                        goto out;
1346        }
1347        rc = seq_printf(p, "\n");
1348  out:
1349        return (rc < 0) ? rc : 0;
1350 }
1351
1352 struct seq_operations lprocfs_stats_seq_sops = {
1353         start: lprocfs_stats_seq_start,
1354         stop:  lprocfs_stats_seq_stop,
1355         next:  lprocfs_stats_seq_next,
1356         show:  lprocfs_stats_seq_show,
1357 };
1358
1359 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1360 {
1361         struct proc_dir_entry *dp = PDE(inode);
1362         struct seq_file *seq;
1363         int rc;
1364
1365         if (LPROCFS_ENTRY_AND_CHECK(dp))
1366                 return -ENOENT;
1367
1368         rc = seq_open(file, &lprocfs_stats_seq_sops);
1369         if (rc) {
1370                 LPROCFS_EXIT();
1371                 return rc;
1372         }
1373         seq = file->private_data;
1374         seq->private = dp->data;
1375         return 0;
1376 }
1377
1378 struct file_operations lprocfs_stats_seq_fops = {
1379         .owner   = THIS_MODULE,
1380         .open    = lprocfs_stats_seq_open,
1381         .read    = seq_read,
1382         .write   = lprocfs_stats_seq_write,
1383         .llseek  = seq_lseek,
1384         .release = lprocfs_seq_release,
1385 };
1386
1387 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1388                            struct lprocfs_stats *stats)
1389 {
1390         struct proc_dir_entry *entry;
1391         LASSERT(root != NULL);
1392
1393         LPROCFS_WRITE_ENTRY();
1394         entry = create_proc_entry(name, 0644, root);
1395         if (entry) {
1396                 entry->proc_fops = &lprocfs_stats_seq_fops;
1397                 entry->data = stats;
1398         }
1399
1400         LPROCFS_WRITE_EXIT();
1401
1402         if (entry == NULL)
1403                 return -ENOMEM;
1404
1405         return 0;
1406 }
1407
1408 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1409                           unsigned conf, const char *name, const char *units)
1410 {
1411         struct lprocfs_counter *c;
1412         int i;
1413         unsigned int num_cpu;
1414
1415         LASSERT(stats != NULL);
1416
1417         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1418
1419         for (i = 0; i < num_cpu; i++) {
1420                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1421                 c->lc_config = conf;
1422                 c->lc_count = 0;
1423                 c->lc_sum = 0;
1424                 c->lc_min = LC_MIN_INIT;
1425                 c->lc_max = 0;
1426                 c->lc_name = name;
1427                 c->lc_units = units;
1428         }
1429
1430         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU);
1431 }
1432 EXPORT_SYMBOL(lprocfs_counter_init);
1433
1434 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1435 do {                                                                       \
1436         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1437         LASSERT(coffset < stats->ls_num);                                  \
1438         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1439 } while (0)
1440
1441 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1442 {
1443         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1444         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1445         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1446         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1447         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1448         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1449         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1450         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1451         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1452         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1453         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1454         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1455         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1456         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1457         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1458         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1459         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1460         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1461         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1462         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1463         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1464         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1465         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1466         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1467         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1468         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1469         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1470         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1471         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1472         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1473         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1474         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1475         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1476         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1477         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1478         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1479         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1480         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1481         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1482         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1483         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1484         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1485         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1486         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1487         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1488         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1489         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1490         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1491         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1492         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1493         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1494         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1495         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1496         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1497         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1498         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1499         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1500         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1501         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1502         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1503         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1504         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1505         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1506         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1507         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1508         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1509         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1510         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1511         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
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 *newnid)
1820 {
1821         struct nid_stat *new_stat, *old_stat;
1822         struct obd_device *obd = NULL;
1823         cfs_proc_dir_entry_t *entry;
1824         char *buffer = NULL;
1825         int rc = 0;
1826         ENTRY;
1827
1828         *newnid = 0;
1829
1830         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1831             !exp->exp_obd->obd_nid_stats_hash)
1832                 RETURN(-EINVAL);
1833
1834         /* not test against zero because eric say:
1835          * You may only test nid against another nid, or LNET_NID_ANY.
1836          * Anything else is nonsense.*/
1837         if (!nid || *nid == LNET_NID_ANY)
1838                 RETURN(0);
1839
1840         obd = exp->exp_obd;
1841
1842         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1843
1844         OBD_ALLOC_PTR(new_stat);
1845         if (new_stat == NULL)
1846                 RETURN(-ENOMEM);
1847
1848         new_stat->nid               = *nid;
1849         new_stat->nid_obd           = exp->exp_obd;
1850         /* we need set default refcount to 1 to balance obd_disconnect */
1851         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1852
1853         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1854                                            nid, &new_stat->nid_hash);
1855         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1856                old_stat, libcfs_nid2str(*nid),
1857                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1858
1859         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
1860          * been and will never be called. */
1861         if (exp->exp_nid_stats) {
1862                 nidstat_putref(exp->exp_nid_stats);
1863                 exp->exp_nid_stats = NULL;
1864         }
1865
1866         /* Return -EALREADY here so that we know that the /proc
1867          * entry already has been created */
1868         if (old_stat != new_stat) {
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*/