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