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