Whamcloud - gitweb
LU-812 kernel: AUTOCONF_INCLUDED removed
[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         stats->ls_flags = flags;
1328         cfs_spin_lock_init(&stats->ls_lock);
1329
1330         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1331         if (num_entry > 1)
1332                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1333
1334         /* for no percpu area, the 0th entry is for real use,
1335          * for percpu area, the 0th entry is for intialized entry template */
1336         OBD_ALLOC(stats->ls_percpu[0], percpusize);
1337         if (stats->ls_percpu[0] == NULL) {
1338                 OBD_FREE(stats,
1339                          offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
1340                 stats = NULL;
1341         }
1342         return stats;
1343 }
1344
1345 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1346 {
1347         struct lprocfs_stats *stats = *statsh;
1348         unsigned int num_entry;
1349         unsigned int percpusize;
1350         unsigned int i;
1351
1352         if (stats == NULL || stats->ls_num == 0)
1353                 return;
1354         *statsh = NULL;
1355
1356         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1357                 num_entry = 1;
1358         else
1359                 num_entry = cfs_num_possible_cpus() + 1;
1360
1361         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1362         if (num_entry > 1)
1363                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1364         for (i = 0; i < num_entry; i++)
1365                 if (stats->ls_percpu[i] != NULL)
1366                         OBD_FREE(stats->ls_percpu[i], percpusize);
1367         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1368 }
1369
1370 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1371 {
1372         struct lprocfs_counter *percpu_cntr;
1373         int                     i;
1374         int                     j;
1375         unsigned int            num_entry;
1376         unsigned long           flags = 0;
1377
1378         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1379
1380         for (i = 0; i < num_entry; i++) {
1381                 if (stats->ls_percpu[i] == NULL)
1382                         continue;
1383                 for (j = 0; j < stats->ls_num; j++) {
1384                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1385                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1386                         percpu_cntr->lc_count = 0;
1387                         percpu_cntr->lc_sum = 0;
1388                         percpu_cntr->lc_min = LC_MIN_INIT;
1389                         percpu_cntr->lc_max = 0;
1390                         percpu_cntr->lc_sumsquare = 0;
1391                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1392                 }
1393         }
1394
1395         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1396 }
1397
1398 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1399                                        size_t len, loff_t *off)
1400 {
1401         struct seq_file *seq = file->private_data;
1402         struct lprocfs_stats *stats = seq->private;
1403
1404         lprocfs_clear_stats(stats);
1405
1406         return len;
1407 }
1408
1409 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1410 {
1411         struct lprocfs_stats *stats = p->private;
1412         /* return 1st cpu location */
1413         return (*pos >= stats->ls_num) ? NULL :
1414                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1415 }
1416
1417 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1418 {
1419 }
1420
1421 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1422 {
1423         struct lprocfs_stats *stats = p->private;
1424         ++*pos;
1425         return (*pos >= stats->ls_num) ? NULL :
1426                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1427 }
1428
1429 /* seq file export of one lprocfs counter */
1430 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1431 {
1432        struct lprocfs_stats *stats = p->private;
1433        struct lprocfs_counter *cntr = v;
1434        struct lprocfs_counter ret;
1435        int idx, rc = 0;
1436
1437        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1438                struct timeval now;
1439                cfs_gettimeofday(&now);
1440                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1441                                "snapshot_time", now.tv_sec, now.tv_usec);
1442                if (rc < 0)
1443                        return rc;
1444        }
1445        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1446
1447        lprocfs_stats_collect(stats, idx, &ret);
1448
1449        if (ret.lc_count == 0)
1450                goto out;
1451
1452        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1453                        ret.lc_count, cntr->lc_units);
1454
1455        if (rc < 0)
1456                goto out;
1457
1458        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1459                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1460                                ret.lc_min, ret.lc_max, ret.lc_sum);
1461                if (rc < 0)
1462                        goto out;
1463                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1464                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1465                if (rc < 0)
1466                        goto out;
1467        }
1468        rc = seq_printf(p, "\n");
1469  out:
1470        return (rc < 0) ? rc : 0;
1471 }
1472
1473 struct seq_operations lprocfs_stats_seq_sops = {
1474         start: lprocfs_stats_seq_start,
1475         stop:  lprocfs_stats_seq_stop,
1476         next:  lprocfs_stats_seq_next,
1477         show:  lprocfs_stats_seq_show,
1478 };
1479
1480 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1481 {
1482         struct proc_dir_entry *dp = PDE(inode);
1483         struct seq_file *seq;
1484         int rc;
1485
1486         if (LPROCFS_ENTRY_AND_CHECK(dp))
1487                 return -ENOENT;
1488
1489         rc = seq_open(file, &lprocfs_stats_seq_sops);
1490         if (rc) {
1491                 LPROCFS_EXIT();
1492                 return rc;
1493         }
1494         seq = file->private_data;
1495         seq->private = dp->data;
1496         return 0;
1497 }
1498
1499 struct file_operations lprocfs_stats_seq_fops = {
1500         .owner   = THIS_MODULE,
1501         .open    = lprocfs_stats_seq_open,
1502         .read    = seq_read,
1503         .write   = lprocfs_stats_seq_write,
1504         .llseek  = seq_lseek,
1505         .release = lprocfs_seq_release,
1506 };
1507
1508 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1509                            struct lprocfs_stats *stats)
1510 {
1511         struct proc_dir_entry *entry;
1512         LASSERT(root != NULL);
1513
1514         LPROCFS_WRITE_ENTRY();
1515         entry = create_proc_entry(name, 0644, root);
1516         if (entry) {
1517                 entry->proc_fops = &lprocfs_stats_seq_fops;
1518                 entry->data = stats;
1519         }
1520
1521         LPROCFS_WRITE_EXIT();
1522
1523         if (entry == NULL)
1524                 return -ENOMEM;
1525
1526         return 0;
1527 }
1528
1529 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1530                           unsigned conf, const char *name, const char *units)
1531 {
1532         struct lprocfs_counter *c     = &(stats->ls_percpu[0]->lp_cntr[index]);
1533         unsigned long           flags = 0;
1534
1535         LASSERT(stats != NULL);
1536         LASSERT(stats->ls_percpu[0] != NULL);
1537
1538         lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1539         c->lc_config = conf;
1540         c->lc_count = 0;
1541         c->lc_sum = 0;
1542         c->lc_min = LC_MIN_INIT;
1543         c->lc_max = 0;
1544         c->lc_name = name;
1545         c->lc_units = units;
1546         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1547 }
1548 EXPORT_SYMBOL(lprocfs_counter_init);
1549
1550 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1551 do {                                                                       \
1552         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1553         LASSERT(coffset < stats->ls_num);                                  \
1554         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1555 } while (0)
1556
1557 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1558 {
1559         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1560         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1561         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1562         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1563         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1564         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1565         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1566         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1567         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1568         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1569         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1570         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1571         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1572         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1573         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1574         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1575         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1576         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1577         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1578         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1579         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1580         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1581         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1582         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1583         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1584         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1585         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1586         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1587         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1588         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1589         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1590         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1591         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1592         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1593         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1594         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1595         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1596         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1597         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1598         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1599         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1600         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1601         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1602         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1603         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1604         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1605         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1606         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1607         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1608         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1609         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1610         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1611         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1612         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1613         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1614         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1615         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1616         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1617         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1618         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1619         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1620         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
1621         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1622         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1623         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1624         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1625         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1626         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1627         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1628 }
1629
1630 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1631 {
1632         struct lprocfs_stats *stats;
1633         unsigned int num_stats;
1634         int rc, i;
1635
1636         LASSERT(obd->obd_stats == NULL);
1637         LASSERT(obd->obd_proc_entry != NULL);
1638         LASSERT(obd->obd_cntr_base == 0);
1639
1640         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1641                 num_private_stats - 1 /* o_owner */;
1642         stats = lprocfs_alloc_stats(num_stats, 0);
1643         if (stats == NULL)
1644                 return -ENOMEM;
1645
1646         lprocfs_init_ops_stats(num_private_stats, stats);
1647
1648         for (i = num_private_stats; i < num_stats; i++) {
1649                 /* If this LBUGs, it is likely that an obd
1650                  * operation was added to struct obd_ops in
1651                  * <obd.h>, and that the corresponding line item
1652                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1653                  * is missing from the list above. */
1654                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1655                          "Missing obd_stat initializer obd_op "
1656                          "operation at offset %d.\n", i - num_private_stats);
1657         }
1658         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1659         if (rc < 0) {
1660                 lprocfs_free_stats(&stats);
1661         } else {
1662                 obd->obd_stats  = stats;
1663                 obd->obd_cntr_base = num_private_stats;
1664         }
1665         return rc;
1666 }
1667
1668 void lprocfs_free_obd_stats(struct obd_device *obd)
1669 {
1670         if (obd->obd_stats)
1671                 lprocfs_free_stats(&obd->obd_stats);
1672 }
1673
1674 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1675 do {                                                                    \
1676         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1677         LASSERT(coffset < stats->ls_num);                               \
1678         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1679 } while (0)
1680
1681 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1682 {
1683         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1684         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1685         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1686         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1687         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1688         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1689         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1690         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1691         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1692         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1693         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1694         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1695         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1696         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1697         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1698         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1699         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1700         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1701         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1702         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1703         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1704         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1705         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1706         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1707         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1708         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1709         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1710         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1711         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1712         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1713         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1714         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1715 }
1716
1717 int lprocfs_alloc_md_stats(struct obd_device *obd,
1718                            unsigned num_private_stats)
1719 {
1720         struct lprocfs_stats *stats;
1721         unsigned int num_stats;
1722         int rc, i;
1723
1724         LASSERT(obd->md_stats == NULL);
1725         LASSERT(obd->obd_proc_entry != NULL);
1726         LASSERT(obd->md_cntr_base == 0);
1727
1728         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1729                     num_private_stats;
1730         stats = lprocfs_alloc_stats(num_stats, 0);
1731         if (stats == NULL)
1732                 return -ENOMEM;
1733
1734         lprocfs_init_mps_stats(num_private_stats, stats);
1735
1736         for (i = num_private_stats; i < num_stats; i++) {
1737                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1738                         CERROR("Missing md_stat initializer md_op "
1739                                "operation at offset %d. Aborting.\n",
1740                                i - num_private_stats);
1741                         LBUG();
1742                 }
1743         }
1744         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1745         if (rc < 0) {
1746                 lprocfs_free_stats(&stats);
1747         } else {
1748                 obd->md_stats  = stats;
1749                 obd->md_cntr_base = num_private_stats;
1750         }
1751         return rc;
1752 }
1753
1754 void lprocfs_free_md_stats(struct obd_device *obd)
1755 {
1756         struct lprocfs_stats *stats = obd->md_stats;
1757
1758         if (stats != NULL) {
1759                 obd->md_stats = NULL;
1760                 obd->md_cntr_base = 0;
1761                 lprocfs_free_stats(&stats);
1762         }
1763 }
1764
1765 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1766 {
1767         lprocfs_counter_init(ldlm_stats,
1768                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1769                              0, "ldlm_enqueue", "reqs");
1770         lprocfs_counter_init(ldlm_stats,
1771                              LDLM_CONVERT - LDLM_FIRST_OPC,
1772                              0, "ldlm_convert", "reqs");
1773         lprocfs_counter_init(ldlm_stats,
1774                              LDLM_CANCEL - LDLM_FIRST_OPC,
1775                              0, "ldlm_cancel", "reqs");
1776         lprocfs_counter_init(ldlm_stats,
1777                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1778                              0, "ldlm_bl_callback", "reqs");
1779         lprocfs_counter_init(ldlm_stats,
1780                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1781                              0, "ldlm_cp_callback", "reqs");
1782         lprocfs_counter_init(ldlm_stats,
1783                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1784                              0, "ldlm_gl_callback", "reqs");
1785 }
1786
1787 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1788                          int *eof,  void *data)
1789 {
1790         struct obd_export *exp = data;
1791         LASSERT(exp != NULL);
1792         *eof = 1;
1793         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1794 }
1795
1796 struct exp_uuid_cb_data {
1797         char                   *page;
1798         int                     count;
1799         int                    *eof;
1800         int                    *len;
1801 };
1802
1803 static void
1804 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1805                             int count, int *eof, int *len)
1806 {
1807         cb_data->page = page;
1808         cb_data->count = count;
1809         cb_data->eof = eof;
1810         cb_data->len = len;
1811 }
1812
1813 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1814                            cfs_hlist_node_t *hnode, void *cb_data)
1815
1816 {
1817         struct obd_export *exp = cfs_hash_object(hs, hnode);
1818         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1819
1820         if (exp->exp_nid_stats)
1821                 *data->len += snprintf((data->page + *data->len),
1822                                        data->count, "%s\n",
1823                                        obd_uuid2str(&exp->exp_client_uuid));
1824         return 0;
1825 }
1826
1827 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1828                         int *eof,  void *data)
1829 {
1830         struct nid_stat *stats = (struct nid_stat *)data;
1831         struct exp_uuid_cb_data cb_data;
1832         struct obd_device *obd = stats->nid_obd;
1833         int len = 0;
1834
1835         *eof = 1;
1836         page[0] = '\0';
1837         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1838         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1839                               lprocfs_exp_print_uuid, &cb_data);
1840         return (*cb_data.len);
1841 }
1842
1843 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1844                            cfs_hlist_node_t *hnode, void *cb_data)
1845
1846 {
1847         struct exp_uuid_cb_data *data = cb_data;
1848         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1849
1850         if (exp->exp_lock_hash != NULL) {
1851                 if (!*data->len) {
1852                         *data->len += cfs_hash_debug_header(data->page,
1853                                                             data->count);
1854                 }
1855                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1856                                                  data->count);
1857         }
1858
1859         return 0;
1860 }
1861
1862 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1863                         int *eof,  void *data)
1864 {
1865         struct nid_stat *stats = (struct nid_stat *)data;
1866         struct exp_uuid_cb_data cb_data;
1867         struct obd_device *obd = stats->nid_obd;
1868         int len = 0;
1869
1870         *eof = 1;
1871         page[0] = '\0';
1872         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1873
1874         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1875                               lprocfs_exp_print_hash, &cb_data);
1876         return (*cb_data.len);
1877 }
1878
1879 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1880                                         int count, int *eof,  void *data)
1881 {
1882         *eof = 1;
1883         return snprintf(page, count, "%s\n",
1884                         "Write into this file to clear all nid stats and "
1885                         "stale nid entries");
1886 }
1887 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1888
1889 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1890 {
1891         struct nid_stat *stat = obj;
1892         int i;
1893         ENTRY;
1894
1895         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1896         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
1897                 /* object has only hash references. */
1898                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
1899                 cfs_list_move(&stat->nid_list, data);
1900                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
1901                 RETURN(1);
1902         }
1903         /* we has reference to object - only clear data*/
1904         if (stat->nid_stats)
1905                 lprocfs_clear_stats(stat->nid_stats);
1906
1907         if (stat->nid_brw_stats) {
1908                 for (i = 0; i < BRW_LAST; i++)
1909                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1910         }
1911         RETURN(0);
1912 }
1913
1914 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1915                                   unsigned long count, void *data)
1916 {
1917         struct obd_device *obd = (struct obd_device *)data;
1918         struct nid_stat *client_stat;
1919         CFS_LIST_HEAD(free_list);
1920
1921         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1922                           lprocfs_nid_stats_clear_write_cb, &free_list);
1923
1924         while (!cfs_list_empty(&free_list)) {
1925                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1926                                              nid_list);
1927                 cfs_list_del_init(&client_stat->nid_list);
1928                 lprocfs_free_client_stats(client_stat);
1929         }
1930
1931         return count;
1932 }
1933 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1934
1935 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1936 {
1937         struct nid_stat *new_stat, *old_stat;
1938         struct obd_device *obd = NULL;
1939         cfs_proc_dir_entry_t *entry;
1940         char *buffer = NULL;
1941         int rc = 0;
1942         ENTRY;
1943
1944         *newnid = 0;
1945
1946         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1947             !exp->exp_obd->obd_nid_stats_hash)
1948                 RETURN(-EINVAL);
1949
1950         /* not test against zero because eric say:
1951          * You may only test nid against another nid, or LNET_NID_ANY.
1952          * Anything else is nonsense.*/
1953         if (!nid || *nid == LNET_NID_ANY)
1954                 RETURN(0);
1955
1956         obd = exp->exp_obd;
1957
1958         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1959
1960         OBD_ALLOC_PTR(new_stat);
1961         if (new_stat == NULL)
1962                 RETURN(-ENOMEM);
1963
1964         new_stat->nid               = *nid;
1965         new_stat->nid_obd           = exp->exp_obd;
1966         /* we need set default refcount to 1 to balance obd_disconnect */
1967         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1968
1969         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1970                                            nid, &new_stat->nid_hash);
1971         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1972                old_stat, libcfs_nid2str(*nid),
1973                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1974
1975         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
1976          * been and will never be called. */
1977         if (exp->exp_nid_stats) {
1978                 nidstat_putref(exp->exp_nid_stats);
1979                 exp->exp_nid_stats = NULL;
1980         }
1981
1982         /* Return -EALREADY here so that we know that the /proc
1983          * entry already has been created */
1984         if (old_stat != new_stat) {
1985                 exp->exp_nid_stats = old_stat;
1986                 GOTO(destroy_new, rc = -EALREADY);
1987         }
1988         /* not found - create */
1989         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1990         if (buffer == NULL)
1991                 GOTO(destroy_new, rc = -ENOMEM);
1992
1993         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1994         new_stat->nid_proc = lprocfs_register(buffer,
1995                                               obd->obd_proc_exports_entry,
1996                                               NULL, NULL);
1997         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1998
1999         if (new_stat->nid_proc == NULL) {
2000                 CERROR("Error making export directory for nid %s\n",
2001                        libcfs_nid2str(*nid));
2002                 GOTO(destroy_new_ns, rc = -ENOMEM);
2003         }
2004
2005         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2006                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2007         if (IS_ERR(entry)) {
2008                 CWARN("Error adding the NID stats file\n");
2009                 rc = PTR_ERR(entry);
2010                 GOTO(destroy_new_ns, rc);
2011         }
2012
2013         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2014                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2015         if (IS_ERR(entry)) {
2016                 CWARN("Error adding the hash file\n");
2017                 rc = PTR_ERR(entry);
2018                 GOTO(destroy_new_ns, rc);
2019         }
2020
2021         exp->exp_nid_stats = new_stat;
2022         *newnid = 1;
2023         /* protect competitive add to list, not need locking on destroy */
2024         cfs_spin_lock(&obd->obd_nid_lock);
2025         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2026         cfs_spin_unlock(&obd->obd_nid_lock);
2027
2028         RETURN(rc);
2029
2030 destroy_new_ns:
2031         if (new_stat->nid_proc != NULL)
2032                 lprocfs_remove(&new_stat->nid_proc);
2033         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2034
2035 destroy_new:
2036         nidstat_putref(new_stat);
2037         OBD_FREE_PTR(new_stat);
2038         RETURN(rc);
2039 }
2040
2041 int lprocfs_exp_cleanup(struct obd_export *exp)
2042 {
2043         struct nid_stat *stat = exp->exp_nid_stats;
2044
2045         if(!stat || !exp->exp_obd)
2046                 RETURN(0);
2047
2048         nidstat_putref(exp->exp_nid_stats);
2049         exp->exp_nid_stats = NULL;
2050
2051         return 0;
2052 }
2053
2054 int lprocfs_write_helper(const char *buffer, unsigned long count,
2055                          int *val)
2056 {
2057         return lprocfs_write_frac_helper(buffer, count, val, 1);
2058 }
2059
2060 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2061                               int *val, int mult)
2062 {
2063         char kernbuf[20], *end, *pbuf;
2064
2065         if (count > (sizeof(kernbuf) - 1))
2066                 return -EINVAL;
2067
2068         if (cfs_copy_from_user(kernbuf, buffer, count))
2069                 return -EFAULT;
2070
2071         kernbuf[count] = '\0';
2072         pbuf = kernbuf;
2073         if (*pbuf == '-') {
2074                 mult = -mult;
2075                 pbuf++;
2076         }
2077
2078         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2079         if (pbuf == end)
2080                 return -EINVAL;
2081
2082         if (end != NULL && *end == '.') {
2083                 int temp_val, pow = 1;
2084                 int i;
2085
2086                 pbuf = end + 1;
2087                 if (strlen(pbuf) > 5)
2088                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2089
2090                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2091
2092                 if (pbuf < end) {
2093                         for (i = 0; i < (end - pbuf); i++)
2094                                 pow *= 10;
2095
2096                         *val += temp_val / pow;
2097                 }
2098         }
2099         return 0;
2100 }
2101
2102 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2103                              int mult)
2104 {
2105         long decimal_val, frac_val;
2106         int prtn;
2107
2108         if (count < 10)
2109                 return -EINVAL;
2110
2111         decimal_val = val / mult;
2112         prtn = snprintf(buffer, count, "%ld", decimal_val);
2113         frac_val = val % mult;
2114
2115         if (prtn < (count - 4) && frac_val > 0) {
2116                 long temp_frac;
2117                 int i, temp_mult = 1, frac_bits = 0;
2118
2119                 temp_frac = frac_val * 10;
2120                 buffer[prtn++] = '.';
2121                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2122                         /* only reserved 2 bits fraction */
2123                         buffer[prtn++] ='0';
2124                         temp_frac *= 10;
2125                         frac_bits++;
2126                 }
2127                 /*
2128                  * Need to think these cases :
2129                  *      1. #echo x.00 > /proc/xxx       output result : x
2130                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2131                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2132                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2133                  *      Only reserved 2 bits fraction.
2134                  */
2135                 for (i = 0; i < (5 - prtn); i++)
2136                         temp_mult *= 10;
2137
2138                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2139                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2140                                  frac_val * temp_mult / mult);
2141
2142                 prtn--;
2143                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2144                         prtn--;
2145                         if (buffer[prtn] == '.') {
2146                                 prtn--;
2147                                 break;
2148                         }
2149                 }
2150                 prtn++;
2151         }
2152         buffer[prtn++] ='\n';
2153         return prtn;
2154 }
2155
2156 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2157 {
2158         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2159 }
2160
2161 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2162                               __u64 *val, int mult)
2163 {
2164         char kernbuf[22], *end, *pbuf;
2165         __u64 whole, frac = 0, units;
2166         unsigned frac_d = 1;
2167
2168         if (count > (sizeof(kernbuf) - 1))
2169                 return -EINVAL;
2170
2171         if (cfs_copy_from_user(kernbuf, buffer, count))
2172                 return -EFAULT;
2173
2174         kernbuf[count] = '\0';
2175         pbuf = kernbuf;
2176         if (*pbuf == '-') {
2177                 mult = -mult;
2178                 pbuf++;
2179         }
2180
2181         whole = simple_strtoull(pbuf, &end, 10);
2182         if (pbuf == end)
2183                 return -EINVAL;
2184
2185         if (end != NULL && *end == '.') {
2186                 int i;
2187                 pbuf = end + 1;
2188
2189                 /* need to limit frac_d to a __u32 */
2190                 if (strlen(pbuf) > 10)
2191                         pbuf[10] = '\0';
2192
2193                 frac = simple_strtoull(pbuf, &end, 10);
2194                 /* count decimal places */
2195                 for (i = 0; i < (end - pbuf); i++)
2196                         frac_d *= 10;
2197         }
2198
2199         units = 1;
2200         switch(*end) {
2201         case 'p': case 'P':
2202                 units <<= 10;
2203         case 't': case 'T':
2204                 units <<= 10;
2205         case 'g': case 'G':
2206                 units <<= 10;
2207         case 'm': case 'M':
2208                 units <<= 10;
2209         case 'k': case 'K':
2210                 units <<= 10;
2211         }
2212         /* Specified units override the multiplier */
2213         if (units)
2214                 mult = mult < 0 ? -units : units;
2215
2216         frac *= mult;
2217         do_div(frac, frac_d);
2218         *val = whole * mult + frac;
2219         return 0;
2220 }
2221
2222 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2223                        struct file_operations *seq_fops, void *data)
2224 {
2225         struct proc_dir_entry *entry;
2226         ENTRY;
2227
2228         LPROCFS_WRITE_ENTRY();
2229         entry = create_proc_entry(name, mode, parent);
2230         if (entry) {
2231                 entry->proc_fops = seq_fops;
2232                 entry->data = data;
2233         }
2234         LPROCFS_WRITE_EXIT();
2235
2236         if (entry == NULL)
2237                 RETURN(-ENOMEM);
2238
2239         RETURN(0);
2240 }
2241 EXPORT_SYMBOL(lprocfs_seq_create);
2242
2243 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2244                                       mode_t mode,
2245                                       struct file_operations *seq_fops,
2246                                       void *data)
2247 {
2248         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2249                                    mode, seq_fops, data));
2250 }
2251 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2252
2253 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2254 {
2255         if (value >= OBD_HIST_MAX)
2256                 value = OBD_HIST_MAX - 1;
2257
2258         cfs_spin_lock(&oh->oh_lock);
2259         oh->oh_buckets[value]++;
2260         cfs_spin_unlock(&oh->oh_lock);
2261 }
2262 EXPORT_SYMBOL(lprocfs_oh_tally);
2263
2264 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2265 {
2266         unsigned int val;
2267
2268         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2269                 ;
2270
2271         lprocfs_oh_tally(oh, val);
2272 }
2273 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2274
2275 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2276 {
2277         unsigned long ret = 0;
2278         int i;
2279
2280         for (i = 0; i < OBD_HIST_MAX; i++)
2281                 ret +=  oh->oh_buckets[i];
2282         return ret;
2283 }
2284 EXPORT_SYMBOL(lprocfs_oh_sum);
2285
2286 void lprocfs_oh_clear(struct obd_histogram *oh)
2287 {
2288         cfs_spin_lock(&oh->oh_lock);
2289         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2290         cfs_spin_unlock(&oh->oh_lock);
2291 }
2292 EXPORT_SYMBOL(lprocfs_oh_clear);
2293
2294 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2295                         int count, int *eof, void *data)
2296 {
2297         struct obd_device *obd = data;
2298         int c = 0;
2299
2300         if (obd == NULL)
2301                 return 0;
2302
2303         c += cfs_hash_debug_header(page, count);
2304         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2305         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2306         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2307 #ifdef HAVE_QUOTA_SUPPORT
2308         if (obd->u.obt.obt_qctxt.lqc_lqs_hash)
2309                 c += cfs_hash_debug_str(obd->u.obt.obt_qctxt.lqc_lqs_hash,
2310                                         page + c, count - c);
2311 #endif
2312
2313         return c;
2314 }
2315 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2316
2317 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2318                                    int count, int *eof, void *data)
2319 {
2320         struct obd_device *obd = data;
2321         int len = 0, size;
2322
2323         LASSERT(obd != NULL);
2324         LASSERT(count >= 0);
2325
2326         /* Set start of user data returned to
2327            page + off since the user may have
2328            requested to read much smaller than
2329            what we need to read */
2330         *start = page + off;
2331
2332         /* We know we are allocated a page here.
2333            Also we know that this function will
2334            not need to write more than a page
2335            so we can truncate at CFS_PAGE_SIZE.  */
2336         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2337
2338         /* Initialize the page */
2339         memset(page, 0, size);
2340
2341         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2342                 goto out;
2343         if (obd->obd_max_recoverable_clients == 0) {
2344                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2345                         goto out;
2346
2347                 goto fclose;
2348         }
2349
2350         /* sampled unlocked, but really... */
2351         if (obd->obd_recovering == 0) {
2352                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2353                         goto out;
2354                 if (lprocfs_obd_snprintf(&page, size, &len,
2355                                          "recovery_start: %lu\n",
2356                                          obd->obd_recovery_start) <= 0)
2357                         goto out;
2358                 if (lprocfs_obd_snprintf(&page, size, &len,
2359                                          "recovery_duration: %lu\n",
2360                                          obd->obd_recovery_end -
2361                                          obd->obd_recovery_start) <= 0)
2362                         goto out;
2363                 /* Number of clients that have completed recovery */
2364                 if (lprocfs_obd_snprintf(&page, size, &len,
2365                                          "completed_clients: %d/%d\n",
2366                                          obd->obd_max_recoverable_clients -
2367                                          obd->obd_stale_clients,
2368                                          obd->obd_max_recoverable_clients) <= 0)
2369                         goto out;
2370                 if (lprocfs_obd_snprintf(&page, size, &len,
2371                                          "replayed_requests: %d\n",
2372                                          obd->obd_replayed_requests) <= 0)
2373                         goto out;
2374                 if (lprocfs_obd_snprintf(&page, size, &len,
2375                                          "last_transno: "LPD64"\n",
2376                                          obd->obd_next_recovery_transno - 1)<=0)
2377                         goto out;
2378                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2379                                          obd->obd_version_recov ? "ON" : "OFF")<=0)
2380                         goto out;
2381                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2382                                          obd->obd_no_ir ? "OFF" : "ON") <= 0)
2383                         goto out;
2384                 goto fclose;
2385         }
2386
2387         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2388                 goto out;
2389         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2390                                  obd->obd_recovery_start) <= 0)
2391                 goto out;
2392         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2393                                  cfs_time_current_sec() >=
2394                                  obd->obd_recovery_start +
2395                                  obd->obd_recovery_timeout ? 0 :
2396                                  obd->obd_recovery_start +
2397                                  obd->obd_recovery_timeout -
2398                                  cfs_time_current_sec()) <= 0)
2399                 goto out;
2400         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2401                                  cfs_atomic_read(&obd->obd_connected_clients),
2402                                  obd->obd_max_recoverable_clients) <= 0)
2403                 goto out;
2404         /* Number of clients that have completed recovery */
2405         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2406                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2407                 <= 0)
2408                 goto out;
2409         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2410                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2411                 <=0)
2412                 goto out;
2413         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2414                                  cfs_atomic_read(&obd->obd_connected_clients) -
2415                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2416                 <=0)
2417                 goto out;
2418         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2419                                  obd->obd_stale_clients) <= 0)
2420                 goto out;
2421         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2422                                  obd->obd_replayed_requests) <= 0)
2423                 goto out;
2424         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2425                                  obd->obd_requests_queued_for_recovery) <= 0)
2426                 goto out;
2427
2428         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2429                                  obd->obd_next_recovery_transno) <= 0)
2430                 goto out;
2431
2432 fclose:
2433         *eof = 1;
2434 out:
2435         return min(count, len - (int)off);
2436 }
2437 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2438
2439 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2440                              int count, int *eof, void *data)
2441 {
2442         struct obd_device *obd = (struct obd_device *)data;
2443         LASSERT(obd != NULL);
2444
2445         return snprintf(page, count, "%d\n",
2446                         obd->obd_recovery_ir_factor);
2447 }
2448 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2449
2450 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2451                              unsigned long count, void *data)
2452 {
2453         struct obd_device *obd = (struct obd_device *)data;
2454         int val, rc;
2455         LASSERT(obd != NULL);
2456
2457         rc = lprocfs_write_helper(buffer, count, &val);
2458         if (rc)
2459                 return rc;
2460
2461         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2462                 return -EINVAL;
2463
2464         obd->obd_recovery_ir_factor = val;
2465         return count;
2466 }
2467 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2468
2469 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2470                                       int count, int *eof, void *data)
2471 {
2472         struct obd_device *obd = (struct obd_device *)data;
2473         LASSERT(obd != NULL);
2474
2475         return snprintf(page, count, "%d\n",
2476                         obd->obd_recovery_timeout);
2477 }
2478 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2479
2480 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2481                                       unsigned long count, void *data)
2482 {
2483         struct obd_device *obd = (struct obd_device *)data;
2484         int val, rc;
2485         LASSERT(obd != NULL);
2486
2487         rc = lprocfs_write_helper(buffer, count, &val);
2488         if (rc)
2489                 return rc;
2490
2491         obd->obd_recovery_timeout = val;
2492         return count;
2493 }
2494 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2495
2496 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2497                                       int count, int *eof, void *data)
2498 {
2499         struct obd_device *obd = data;
2500         LASSERT(obd != NULL);
2501
2502         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2503 }
2504 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2505
2506 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2507                                       unsigned long count, void *data)
2508 {
2509         struct obd_device *obd = data;
2510         int val, rc;
2511         LASSERT(obd != NULL);
2512
2513         rc = lprocfs_write_helper(buffer, count, &val);
2514         if (rc)
2515                 return rc;
2516
2517         obd->obd_recovery_time_hard = val;
2518         return count;
2519 }
2520 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2521
2522 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2523                           int count, int *eof, void *data)
2524 {
2525         struct obd_device *obd = (struct obd_device *)data;
2526
2527         LASSERT(obd != NULL);
2528         LASSERT(obd->u.obt.obt_vfsmnt->mnt_devname);
2529         *eof = 1;
2530         return snprintf(page, count, "%s\n",
2531                         obd->u.obt.obt_vfsmnt->mnt_devname);
2532 }
2533 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2534
2535 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2536                                      int count, int *eof, void *data)
2537 {
2538         struct obd_device *dev = data;
2539         struct client_obd *cli = &dev->u.cli;
2540         int rc;
2541
2542         client_obd_list_lock(&cli->cl_loi_list_lock);
2543         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2544         client_obd_list_unlock(&cli->cl_loi_list_lock);
2545         return rc;
2546 }
2547 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2548
2549 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2550                                int count, int *eof, void *data)
2551 {
2552         struct obd_device *obd = (struct obd_device *)data;
2553         struct obd_device_target *target = &obd->u.obt;
2554
2555         LASSERT(obd != NULL);
2556         LASSERT(target->obt_magic == OBT_MAGIC);
2557         *eof = 1;
2558         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2559 }
2560 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2561
2562 EXPORT_SYMBOL(lprocfs_register);
2563 EXPORT_SYMBOL(lprocfs_srch);
2564 EXPORT_SYMBOL(lprocfs_remove);
2565 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2566 EXPORT_SYMBOL(lprocfs_add_vars);
2567 EXPORT_SYMBOL(lprocfs_obd_setup);
2568 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2569 EXPORT_SYMBOL(lprocfs_add_simple);
2570 EXPORT_SYMBOL(lprocfs_add_symlink);
2571 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2572 EXPORT_SYMBOL(lprocfs_alloc_stats);
2573 EXPORT_SYMBOL(lprocfs_free_stats);
2574 EXPORT_SYMBOL(lprocfs_clear_stats);
2575 EXPORT_SYMBOL(lprocfs_register_stats);
2576 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2577 EXPORT_SYMBOL(lprocfs_init_mps_stats);
2578 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2579 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2580 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2581 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2582 EXPORT_SYMBOL(lprocfs_free_md_stats);
2583 EXPORT_SYMBOL(lprocfs_exp_setup);
2584 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2585
2586 EXPORT_SYMBOL(lprocfs_rd_u64);
2587 EXPORT_SYMBOL(lprocfs_rd_atomic);
2588 EXPORT_SYMBOL(lprocfs_wr_atomic);
2589 EXPORT_SYMBOL(lprocfs_rd_uint);
2590 EXPORT_SYMBOL(lprocfs_wr_uint);
2591 EXPORT_SYMBOL(lprocfs_rd_uuid);
2592 EXPORT_SYMBOL(lprocfs_rd_name);
2593 EXPORT_SYMBOL(lprocfs_rd_fstype);
2594 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2595 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2596 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2597 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2598 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2599 EXPORT_SYMBOL(lprocfs_rd_import);
2600 EXPORT_SYMBOL(lprocfs_rd_state);
2601 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2602 EXPORT_SYMBOL(lprocfs_rd_blksize);
2603 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2604 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2605 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2606 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2607 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2608
2609 EXPORT_SYMBOL(lprocfs_write_helper);
2610 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2611 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2612 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2613 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2614 EXPORT_SYMBOL(lprocfs_stats_collect);
2615 #endif /* LPROCFS*/