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