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