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