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