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