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