Whamcloud - gitweb
Revert "b=22176 Add .sync_fs super block handler"
[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         LASSERT(hs == exp->exp_lock_hash);
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         return 0;
1729 }
1730
1731 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1732                         int *eof,  void *data)
1733 {
1734         struct nid_stat *stats = (struct nid_stat *)data;
1735         struct exp_uuid_cb_data cb_data;
1736         struct obd_device *obd = stats->nid_obd;
1737         int len = 0;
1738
1739         *eof = 1;
1740         page[0] = '\0';
1741         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1742
1743         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1744                               lprocfs_exp_print_hash, &cb_data);
1745         return (*cb_data.len);
1746 }
1747
1748 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1749                                         int count, int *eof,  void *data)
1750 {
1751         *eof = 1;
1752         return snprintf(page, count, "%s\n",
1753                         "Write into this file to clear all nid stats and "
1754                         "stale nid entries");
1755 }
1756 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1757
1758 int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1759 {
1760         struct nid_stat *stat = obj;
1761         int i;
1762         ENTRY;
1763
1764         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1765         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1766                 /* object has only hash references. */
1767                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
1768                 cfs_list_move(&stat->nid_list, data);
1769                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
1770                 RETURN(1);
1771         }
1772         /* we has reference to object - only clear data*/
1773         if (stat->nid_stats)
1774                 lprocfs_clear_stats(stat->nid_stats);
1775
1776         if (stat->nid_brw_stats) {
1777                 for (i = 0; i < BRW_LAST; i++)
1778                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1779         }
1780         RETURN(0);
1781 }
1782
1783 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1784                                   unsigned long count, void *data)
1785 {
1786         struct obd_device *obd = (struct obd_device *)data;
1787         struct nid_stat *client_stat;
1788         CFS_LIST_HEAD(free_list);
1789
1790         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1791                           lprocfs_nid_stats_clear_write_cb, &free_list);
1792
1793         while (!cfs_list_empty(&free_list)) {
1794                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1795                                              nid_list);
1796                 cfs_list_del_init(&client_stat->nid_list);
1797                 lprocfs_free_client_stats(client_stat);
1798         }
1799
1800         return count;
1801 }
1802 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1803
1804 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
1805                       int *newnid)
1806 {
1807         struct nid_stat *new_stat, *old_stat;
1808         struct obd_device *obd = NULL;
1809         cfs_proc_dir_entry_t *entry;
1810         char *buffer = NULL;
1811         int rc = 0;
1812         ENTRY;
1813
1814         *newnid = 0;
1815
1816         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1817             !exp->exp_obd->obd_nid_stats_hash)
1818                 RETURN(-EINVAL);
1819
1820         /* not test against zero because eric say:
1821          * You may only test nid against another nid, or LNET_NID_ANY.
1822          * Anything else is nonsense.*/
1823         if (!nid || *nid == LNET_NID_ANY)
1824                 RETURN(0);
1825
1826         obd = exp->exp_obd;
1827
1828         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1829
1830         OBD_ALLOC_PTR(new_stat);
1831         if (new_stat == NULL)
1832                 RETURN(-ENOMEM);
1833
1834         new_stat->nid               = *nid;
1835         new_stat->nid_obd           = exp->exp_obd;
1836         /* we need set default refcount to 1 to balance obd_disconnect */
1837         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1838
1839         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1840                                            nid, &new_stat->nid_hash);
1841         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1842                old_stat, libcfs_nid2str(*nid),
1843                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1844
1845         /* Return -EALREADY here so that we know that the /proc
1846          * entry already has been created */
1847         if (old_stat != new_stat) {
1848                 /* if this connects to the existing export of same nid,
1849                  * we need to release old stats for obd_disconnect won't
1850                  * balance the reference gotten in "cfs_hash_findadd_uinque" */
1851                 if (reconnect && exp->exp_nid_stats)
1852                         nidstat_putref(old_stat);
1853
1854                 exp->exp_nid_stats = old_stat;
1855                 GOTO(destroy_new, rc = -EALREADY);
1856         }
1857         /* not found - create */
1858         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1859         if (buffer == NULL)
1860                 GOTO(destroy_new, rc = -ENOMEM);
1861
1862         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1863         new_stat->nid_proc = lprocfs_register(buffer,
1864                                               obd->obd_proc_exports_entry,
1865                                               NULL, NULL);
1866         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1867
1868         if (new_stat->nid_proc == NULL) {
1869                 CERROR("Error making export directory for nid %s\n",
1870                        libcfs_nid2str(*nid));
1871                 GOTO(destroy_new_ns, rc = -ENOMEM);
1872         }
1873
1874         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1875                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1876         if (IS_ERR(entry)) {
1877                 CWARN("Error adding the NID stats file\n");
1878                 rc = PTR_ERR(entry);
1879                 GOTO(destroy_new_ns, rc);
1880         }
1881
1882         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1883                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1884         if (IS_ERR(entry)) {
1885                 CWARN("Error adding the hash file\n");
1886                 rc = PTR_ERR(entry);
1887                 GOTO(destroy_new_ns, rc);
1888         }
1889
1890         exp->exp_nid_stats = new_stat;
1891         *newnid = 1;
1892         /* protect competitive add to list, not need locking on destroy */
1893         cfs_spin_lock(&obd->obd_nid_lock);
1894         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1895         cfs_spin_unlock(&obd->obd_nid_lock);
1896
1897         RETURN(rc);
1898
1899 destroy_new_ns:
1900         if (new_stat->nid_proc != NULL)
1901                 lprocfs_remove(&new_stat->nid_proc);
1902         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1903
1904 destroy_new:
1905         nidstat_putref(new_stat);
1906         OBD_FREE_PTR(new_stat);
1907         RETURN(rc);
1908 }
1909
1910 int lprocfs_exp_cleanup(struct obd_export *exp)
1911 {
1912         struct nid_stat *stat = exp->exp_nid_stats;
1913
1914         if(!stat || !exp->exp_obd)
1915                 RETURN(0);
1916
1917         nidstat_putref(exp->exp_nid_stats);
1918         exp->exp_nid_stats = NULL;
1919
1920         return 0;
1921 }
1922
1923 int lprocfs_write_helper(const char *buffer, unsigned long count,
1924                          int *val)
1925 {
1926         return lprocfs_write_frac_helper(buffer, count, val, 1);
1927 }
1928
1929 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1930                               int *val, int mult)
1931 {
1932         char kernbuf[20], *end, *pbuf;
1933
1934         if (count > (sizeof(kernbuf) - 1))
1935                 return -EINVAL;
1936
1937         if (cfs_copy_from_user(kernbuf, buffer, count))
1938                 return -EFAULT;
1939
1940         kernbuf[count] = '\0';
1941         pbuf = kernbuf;
1942         if (*pbuf == '-') {
1943                 mult = -mult;
1944                 pbuf++;
1945         }
1946
1947         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1948         if (pbuf == end)
1949                 return -EINVAL;
1950
1951         if (end != NULL && *end == '.') {
1952                 int temp_val, pow = 1;
1953                 int i;
1954
1955                 pbuf = end + 1;
1956                 if (strlen(pbuf) > 5)
1957                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1958
1959                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1960
1961                 if (pbuf < end) {
1962                         for (i = 0; i < (end - pbuf); i++)
1963                                 pow *= 10;
1964
1965                         *val += temp_val / pow;
1966                 }
1967         }
1968         return 0;
1969 }
1970
1971 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1972                              int mult)
1973 {
1974         long decimal_val, frac_val;
1975         int prtn;
1976
1977         if (count < 10)
1978                 return -EINVAL;
1979
1980         decimal_val = val / mult;
1981         prtn = snprintf(buffer, count, "%ld", decimal_val);
1982         frac_val = val % mult;
1983
1984         if (prtn < (count - 4) && frac_val > 0) {
1985                 long temp_frac;
1986                 int i, temp_mult = 1, frac_bits = 0;
1987
1988                 temp_frac = frac_val * 10;
1989                 buffer[prtn++] = '.';
1990                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1991                         /* only reserved 2 bits fraction */
1992                         buffer[prtn++] ='0';
1993                         temp_frac *= 10;
1994                         frac_bits++;
1995                 }
1996                 /*
1997                  * Need to think these cases :
1998                  *      1. #echo x.00 > /proc/xxx       output result : x
1999                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2000                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2001                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2002                  *      Only reserved 2 bits fraction.
2003                  */
2004                 for (i = 0; i < (5 - prtn); i++)
2005                         temp_mult *= 10;
2006
2007                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2008                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2009                                  frac_val * temp_mult / mult);
2010
2011                 prtn--;
2012                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2013                         prtn--;
2014                         if (buffer[prtn] == '.') {
2015                                 prtn--;
2016                                 break;
2017                         }
2018                 }
2019                 prtn++;
2020         }
2021         buffer[prtn++] ='\n';
2022         return prtn;
2023 }
2024
2025 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2026 {
2027         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2028 }
2029
2030 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2031                               __u64 *val, int mult)
2032 {
2033         char kernbuf[22], *end, *pbuf;
2034         __u64 whole, frac = 0, units;
2035         unsigned frac_d = 1;
2036
2037         if (count > (sizeof(kernbuf) - 1))
2038                 return -EINVAL;
2039
2040         if (cfs_copy_from_user(kernbuf, buffer, count))
2041                 return -EFAULT;
2042
2043         kernbuf[count] = '\0';
2044         pbuf = kernbuf;
2045         if (*pbuf == '-') {
2046                 mult = -mult;
2047                 pbuf++;
2048         }
2049
2050         whole = simple_strtoull(pbuf, &end, 10);
2051         if (pbuf == end)
2052                 return -EINVAL;
2053
2054         if (end != NULL && *end == '.') {
2055                 int i;
2056                 pbuf = end + 1;
2057
2058                 /* need to limit frac_d to a __u32 */
2059                 if (strlen(pbuf) > 10)
2060                         pbuf[10] = '\0';
2061
2062                 frac = simple_strtoull(pbuf, &end, 10);
2063                 /* count decimal places */
2064                 for (i = 0; i < (end - pbuf); i++)
2065                         frac_d *= 10;
2066         }
2067
2068         units = 1;
2069         switch(*end) {
2070         case 'p': case 'P':
2071                 units <<= 10;
2072         case 't': case 'T':
2073                 units <<= 10;
2074         case 'g': case 'G':
2075                 units <<= 10;
2076         case 'm': case 'M':
2077                 units <<= 10;
2078         case 'k': case 'K':
2079                 units <<= 10;
2080         }
2081         /* Specified units override the multiplier */
2082         if (units)
2083                 mult = mult < 0 ? -units : units;
2084
2085         frac *= mult;
2086         do_div(frac, frac_d);
2087         *val = whole * mult + frac;
2088         return 0;
2089 }
2090
2091 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2092                        struct file_operations *seq_fops, void *data)
2093 {
2094         struct proc_dir_entry *entry;
2095         ENTRY;
2096
2097         LPROCFS_WRITE_ENTRY();
2098         entry = create_proc_entry(name, mode, parent);
2099         if (entry) {
2100                 entry->proc_fops = seq_fops;
2101                 entry->data = data;
2102         }
2103         LPROCFS_WRITE_EXIT();
2104
2105         if (entry == NULL)
2106                 RETURN(-ENOMEM);
2107
2108         RETURN(0);
2109 }
2110 EXPORT_SYMBOL(lprocfs_seq_create);
2111
2112 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2113                                       mode_t mode,
2114                                       struct file_operations *seq_fops,
2115                                       void *data)
2116 {
2117         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2118                                    mode, seq_fops, data));
2119 }
2120 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2121
2122 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2123 {
2124         if (value >= OBD_HIST_MAX)
2125                 value = OBD_HIST_MAX - 1;
2126
2127         cfs_spin_lock(&oh->oh_lock);
2128         oh->oh_buckets[value]++;
2129         cfs_spin_unlock(&oh->oh_lock);
2130 }
2131 EXPORT_SYMBOL(lprocfs_oh_tally);
2132
2133 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2134 {
2135         unsigned int val;
2136
2137         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2138                 ;
2139
2140         lprocfs_oh_tally(oh, val);
2141 }
2142 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2143
2144 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2145 {
2146         unsigned long ret = 0;
2147         int i;
2148
2149         for (i = 0; i < OBD_HIST_MAX; i++)
2150                 ret +=  oh->oh_buckets[i];
2151         return ret;
2152 }
2153 EXPORT_SYMBOL(lprocfs_oh_sum);
2154
2155 void lprocfs_oh_clear(struct obd_histogram *oh)
2156 {
2157         cfs_spin_lock(&oh->oh_lock);
2158         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2159         cfs_spin_unlock(&oh->oh_lock);
2160 }
2161 EXPORT_SYMBOL(lprocfs_oh_clear);
2162
2163 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2164                         int count, int *eof, void *data)
2165 {
2166         struct obd_device *obd = data;
2167         int c = 0;
2168
2169         if (obd == NULL)
2170                 return 0;
2171
2172         c += cfs_hash_debug_header(page, count);
2173         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2174         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2175         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2176 #ifdef HAVE_QUOTA_SUPPORT
2177         if (obd->u.obt.obt_qctxt.lqc_lqs_hash)
2178                 c += cfs_hash_debug_str(obd->u.obt.obt_qctxt.lqc_lqs_hash,
2179                                         page + c, count - c);
2180 #endif
2181
2182         return c;
2183 }
2184 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2185
2186 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2187                                    int count, int *eof, void *data)
2188 {
2189         struct obd_device *obd = data;
2190         int len = 0, size;
2191
2192         LASSERT(obd != NULL);
2193         LASSERT(count >= 0);
2194
2195         /* Set start of user data returned to
2196            page + off since the user may have
2197            requested to read much smaller than
2198            what we need to read */
2199         *start = page + off;
2200
2201         /* We know we are allocated a page here.
2202            Also we know that this function will
2203            not need to write more than a page
2204            so we can truncate at CFS_PAGE_SIZE.  */
2205         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2206
2207         /* Initialize the page */
2208         memset(page, 0, size);
2209
2210         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2211                 goto out;
2212         if (obd->obd_max_recoverable_clients == 0) {
2213                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2214                         goto out;
2215
2216                 goto fclose;
2217         }
2218
2219         /* sampled unlocked, but really... */
2220         if (obd->obd_recovering == 0) {
2221                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2222                         goto out;
2223                 if (lprocfs_obd_snprintf(&page, size, &len,
2224                                          "recovery_start: %lu\n",
2225                                          obd->obd_recovery_start) <= 0)
2226                         goto out;
2227                 if (lprocfs_obd_snprintf(&page, size, &len,
2228                                          "recovery_duration: %lu\n",
2229                                          obd->obd_recovery_end -
2230                                          obd->obd_recovery_start) <= 0)
2231                         goto out;
2232                 /* Number of clients that have completed recovery */
2233                 if (lprocfs_obd_snprintf(&page, size, &len,
2234                                          "completed_clients: %d/%d\n",
2235                                          obd->obd_max_recoverable_clients -
2236                                          obd->obd_stale_clients,
2237                                          obd->obd_max_recoverable_clients) <= 0)
2238                         goto out;
2239                 if (lprocfs_obd_snprintf(&page, size, &len,
2240                                          "replayed_requests: %d\n",
2241                                          obd->obd_replayed_requests) <= 0)
2242                         goto out;
2243                 if (lprocfs_obd_snprintf(&page, size, &len,
2244                                          "last_transno: "LPD64"\n",
2245                                          obd->obd_next_recovery_transno - 1)<=0)
2246                         goto out;
2247                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2248                                          obd->obd_version_recov ? "ON" : "OFF")<=0)
2249                         goto out;
2250                 goto fclose;
2251         }
2252
2253         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2254                 goto out;
2255         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2256                                  obd->obd_recovery_start) <= 0)
2257                 goto out;
2258         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2259                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2260                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2261                 goto out;
2262         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2263                                  obd->obd_connected_clients,
2264                                  obd->obd_max_recoverable_clients) <= 0)
2265                 goto out;
2266         /* Number of clients that have completed recovery */
2267         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2268                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2269                 <= 0)
2270                 goto out;
2271         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2272                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2273                 <=0)
2274                 goto out;
2275         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2276                                  obd->obd_connected_clients -
2277                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2278                 <=0)
2279                 goto out;
2280         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2281                                  obd->obd_stale_clients) <= 0)
2282                 goto out;
2283         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2284                                  obd->obd_replayed_requests) <= 0)
2285                 goto out;
2286         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2287                                  obd->obd_requests_queued_for_recovery) <= 0)
2288                 goto out;
2289
2290         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2291                                  obd->obd_next_recovery_transno) <= 0)
2292                 goto out;
2293
2294 fclose:
2295         *eof = 1;
2296 out:
2297         return min(count, len - (int)off);
2298 }
2299 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2300
2301 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2302                                       int count, int *eof, void *data)
2303 {
2304         struct obd_device *obd = (struct obd_device *)data;
2305         LASSERT(obd != NULL);
2306
2307         return snprintf(page, count, "%d\n",
2308                         obd->obd_recovery_timeout);
2309 }
2310 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2311
2312 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2313                                       unsigned long count, void *data)
2314 {
2315         struct obd_device *obd = (struct obd_device *)data;
2316         int val, rc;
2317         LASSERT(obd != NULL);
2318
2319         rc = lprocfs_write_helper(buffer, count, &val);
2320         if (rc)
2321                 return rc;
2322
2323         obd->obd_recovery_timeout = val;
2324         return count;
2325 }
2326 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2327
2328 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2329                                       int count, int *eof, void *data)
2330 {
2331         struct obd_device *obd = data;
2332         LASSERT(obd != NULL);
2333
2334         return snprintf(page, count, "%lu\n", obd->obd_recovery_time_hard);
2335 }
2336 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2337
2338 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2339                                       unsigned long count, void *data)
2340 {
2341         struct obd_device *obd = data;
2342         int val, rc;
2343         LASSERT(obd != NULL);
2344
2345         rc = lprocfs_write_helper(buffer, count, &val);
2346         if (rc)
2347                 return rc;
2348
2349         obd->obd_recovery_time_hard = val;
2350         return count;
2351 }
2352 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2353
2354 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2355                           int count, int *eof, void *data)
2356 {
2357         struct obd_device *obd = (struct obd_device *)data;
2358
2359         LASSERT(obd != NULL);
2360         LASSERT(obd->u.obt.obt_vfsmnt->mnt_devname);
2361         *eof = 1;
2362         return snprintf(page, count, "%s\n",
2363                         obd->u.obt.obt_vfsmnt->mnt_devname);
2364 }
2365 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2366
2367 EXPORT_SYMBOL(lprocfs_register);
2368 EXPORT_SYMBOL(lprocfs_srch);
2369 EXPORT_SYMBOL(lprocfs_remove);
2370 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2371 EXPORT_SYMBOL(lprocfs_add_vars);
2372 EXPORT_SYMBOL(lprocfs_obd_setup);
2373 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2374 EXPORT_SYMBOL(lprocfs_add_simple);
2375 EXPORT_SYMBOL(lprocfs_add_symlink);
2376 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2377 EXPORT_SYMBOL(lprocfs_alloc_stats);
2378 EXPORT_SYMBOL(lprocfs_free_stats);
2379 EXPORT_SYMBOL(lprocfs_clear_stats);
2380 EXPORT_SYMBOL(lprocfs_register_stats);
2381 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2382 EXPORT_SYMBOL(lprocfs_init_mps_stats);
2383 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2384 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2385 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2386 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2387 EXPORT_SYMBOL(lprocfs_free_md_stats);
2388 EXPORT_SYMBOL(lprocfs_exp_setup);
2389 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2390
2391 EXPORT_SYMBOL(lprocfs_rd_u64);
2392 EXPORT_SYMBOL(lprocfs_rd_atomic);
2393 EXPORT_SYMBOL(lprocfs_wr_atomic);
2394 EXPORT_SYMBOL(lprocfs_rd_uint);
2395 EXPORT_SYMBOL(lprocfs_wr_uint);
2396 EXPORT_SYMBOL(lprocfs_rd_uuid);
2397 EXPORT_SYMBOL(lprocfs_rd_name);
2398 EXPORT_SYMBOL(lprocfs_rd_fstype);
2399 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2400 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2401 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2402 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2403 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2404 EXPORT_SYMBOL(lprocfs_rd_import);
2405 EXPORT_SYMBOL(lprocfs_rd_state);
2406 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2407 EXPORT_SYMBOL(lprocfs_rd_blksize);
2408 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2409 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2410 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2411 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2412 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2413
2414 EXPORT_SYMBOL(lprocfs_write_helper);
2415 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2416 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2417 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2418 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2419 EXPORT_SYMBOL(lprocfs_stats_collect);
2420 #endif /* LPROCFS*/