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