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