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