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