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