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