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