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