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