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