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