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