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