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