Whamcloud - gitweb
516d7984e5285a0b47889e563fa0e66146edbbea
[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         "flock_owner",
1014         "lvb_type",
1015         "nanoseconds_times",
1016         "lightweight_conn",
1017         "short_io",
1018         "unknown",
1019         NULL
1020 };
1021
1022 int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep)
1023 {
1024         __u64 mask = 1;
1025         int i, ret = 0;
1026
1027         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
1028                 if (flags & mask)
1029                         ret += snprintf(page + ret, count - ret, "%s%s",
1030                                         ret ? sep : "", obd_connect_names[i]);
1031         }
1032         if (flags & ~(mask - 1))
1033                 ret += snprintf(page + ret, count - ret,
1034                                 "%sunknown flags "LPX64,
1035                                 ret ? sep : "", flags & ~(mask - 1));
1036         return ret;
1037 }
1038 EXPORT_SYMBOL(obd_connect_flags2str);
1039
1040 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
1041                       int *eof, void *data)
1042 {
1043         struct lprocfs_counter ret;
1044         struct obd_device *obd = (struct obd_device *)data;
1045         struct obd_import *imp;
1046         struct obd_import_conn *conn;
1047         int i, j, k, rw = 0;
1048
1049         LASSERT(obd != NULL);
1050         LPROCFS_CLIMP_CHECK(obd);
1051         imp = obd->u.cli.cl_import;
1052         *eof = 1;
1053
1054         i = snprintf(page, count,
1055                      "import:\n"
1056                      "    name: %s\n"
1057                      "    target: %s\n"
1058                      "    state: %s\n"
1059                      "    instance: %u\n"
1060                      "    connect_flags: [",
1061                      obd->obd_name,
1062                      obd2cli_tgt(obd),
1063                      ptlrpc_import_state_name(imp->imp_state),
1064                      imp->imp_connect_data.ocd_instance);
1065         i += obd_connect_flags2str(page + i, count - i,
1066                                    imp->imp_connect_data.ocd_connect_flags,
1067                                    ", ");
1068         i += snprintf(page + i, count - i,
1069                       "]\n"
1070                       "    import_flags: [");
1071         i += obd_import_flags2str(imp, page + i, count - i);
1072
1073         i += snprintf(page + i, count - i,
1074                       "]\n"
1075                       "    connection:\n"
1076                       "       failover_nids: [");
1077         cfs_spin_lock(&imp->imp_lock);
1078         j = 0;
1079         cfs_list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
1080                 i += snprintf(page + i, count - i, "%s%s", j ? ", " : "",
1081                               libcfs_nid2str(conn->oic_conn->c_peer.nid));
1082                 j++;
1083         }
1084         i += snprintf(page + i, count - i,
1085                       "]\n"
1086                       "       current_connection: %s\n"
1087                       "       connection_attempts: %u\n"
1088                       "       generation: %u\n"
1089                       "       in-progress_invalidations: %u\n",
1090                       imp->imp_connection == NULL ? "<none>" :
1091                               libcfs_nid2str(imp->imp_connection->c_peer.nid),
1092                       imp->imp_conn_cnt,
1093                       imp->imp_generation,
1094                       cfs_atomic_read(&imp->imp_inval_count));
1095         cfs_spin_unlock(&imp->imp_lock);
1096
1097         lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret);
1098         if (ret.lc_count != 0) {
1099                 /* first argument to do_div MUST be __u64 */
1100                 __u64 sum = ret.lc_sum;
1101                 do_div(sum, ret.lc_count);
1102                 ret.lc_sum = sum;
1103         } else
1104                 ret.lc_sum = 0;
1105         i += snprintf(page + i, count - i,
1106                       "    rpcs:\n"
1107                       "       inflight: %u\n"
1108                       "       unregistering: %u\n"
1109                       "       timeouts: %u\n"
1110                       "       avg_waittime: "LPU64" %s\n",
1111                       cfs_atomic_read(&imp->imp_inflight),
1112                       cfs_atomic_read(&imp->imp_unregistering),
1113                       cfs_atomic_read(&imp->imp_timeouts),
1114                       ret.lc_sum, ret.lc_units);
1115
1116         k = 0;
1117         for(j = 0; j < IMP_AT_MAX_PORTALS; j++) {
1118                 if (imp->imp_at.iat_portal[j] == 0)
1119                         break;
1120                 k = max_t(unsigned int, k,
1121                           at_get(&imp->imp_at.iat_service_estimate[j]));
1122         }
1123         i += snprintf(page + i, count - i,
1124                       "    service_estimates:\n"
1125                       "       services: %u sec\n"
1126                       "       network: %u sec\n",
1127                       k,
1128                       at_get(&imp->imp_at.iat_net_latency));
1129
1130         i += snprintf(page + i, count - i,
1131                       "    transactions:\n"
1132                       "       last_replay: "LPU64"\n"
1133                       "       peer_committed: "LPU64"\n"
1134                       "       last_checked: "LPU64"\n",
1135                       imp->imp_last_replay_transno,
1136                       imp->imp_peer_committed_transno,
1137                       imp->imp_last_transno_checked);
1138
1139         /* avg data rates */
1140         for (rw = 0; rw <= 1; rw++) {
1141                 lprocfs_stats_collect(obd->obd_svc_stats,
1142                                       PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw,
1143                                       &ret);
1144                 if (ret.lc_sum > 0 && ret.lc_count > 0) {
1145                         /* first argument to do_div MUST be __u64 */
1146                         __u64 sum = ret.lc_sum;
1147                         do_div(sum, ret.lc_count);
1148                         ret.lc_sum = sum;
1149                         i += snprintf(page + i, count - i,
1150                                       "    %s_data_averages:\n"
1151                                       "       bytes_per_rpc: "LPU64"\n",
1152                                       rw ? "write" : "read",
1153                                       ret.lc_sum);
1154                 }
1155                 k = (int)ret.lc_sum;
1156                 j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES;
1157                 lprocfs_stats_collect(obd->obd_svc_stats, j, &ret);
1158                 if (ret.lc_sum > 0 && ret.lc_count != 0) {
1159                         /* first argument to do_div MUST be __u64 */
1160                         __u64 sum = ret.lc_sum;
1161                         do_div(sum, ret.lc_count);
1162                         ret.lc_sum = sum;
1163                         i += snprintf(page + i, count - i,
1164                                       "       %s_per_rpc: "LPU64"\n",
1165                                       ret.lc_units, ret.lc_sum);
1166                         j = (int)ret.lc_sum;
1167                         if (j > 0)
1168                                 i += snprintf(page + i, count - i,
1169                                               "       MB_per_sec: %u.%.02u\n",
1170                                               k / j, (100 * k / j) % 100);
1171                 }
1172         }
1173
1174         LPROCFS_CLIMP_EXIT(obd);
1175         return i;
1176 }
1177 EXPORT_SYMBOL(lprocfs_rd_import);
1178
1179 int lprocfs_rd_state(char *page, char **start, off_t off, int count,
1180                       int *eof, void *data)
1181 {
1182         struct obd_device *obd = (struct obd_device *)data;
1183         struct obd_import *imp;
1184         int i, j, k;
1185
1186         LASSERT(obd != NULL);
1187         LPROCFS_CLIMP_CHECK(obd);
1188         imp = obd->u.cli.cl_import;
1189         *eof = 1;
1190
1191         i = snprintf(page, count, "current_state: %s\n",
1192                      ptlrpc_import_state_name(imp->imp_state));
1193         i += snprintf(page + i, count - i,
1194                       "state_history:\n");
1195         k = imp->imp_state_hist_idx;
1196         for (j = 0; j < IMP_STATE_HIST_LEN; j++) {
1197                 struct import_state_hist *ish =
1198                         &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN];
1199                 if (ish->ish_state == 0)
1200                         continue;
1201                 i += snprintf(page + i, count - i, " - ["CFS_TIME_T", %s]\n",
1202                               ish->ish_time,
1203                               ptlrpc_import_state_name(ish->ish_state));
1204         }
1205
1206         LPROCFS_CLIMP_EXIT(obd);
1207         return i;
1208 }
1209 EXPORT_SYMBOL(lprocfs_rd_state);
1210
1211 int lprocfs_at_hist_helper(char *page, int count, int rc,
1212                            struct adaptive_timeout *at)
1213 {
1214         int i;
1215         for (i = 0; i < AT_BINS; i++)
1216                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
1217         rc += snprintf(page + rc, count - rc, "\n");
1218         return rc;
1219 }
1220 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1221
1222 /* See also ptlrpc_lprocfs_rd_timeouts */
1223 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
1224                         int *eof, void *data)
1225 {
1226         struct obd_device *obd = (struct obd_device *)data;
1227         struct obd_import *imp;
1228         unsigned int cur, worst;
1229         time_t now, worstt;
1230         struct dhms ts;
1231         int i, rc = 0;
1232
1233         LASSERT(obd != NULL);
1234         LPROCFS_CLIMP_CHECK(obd);
1235         imp = obd->u.cli.cl_import;
1236         *eof = 1;
1237
1238         now = cfs_time_current_sec();
1239
1240         /* Some network health info for kicks */
1241         s2dhms(&ts, now - imp->imp_last_reply_time);
1242         rc += snprintf(page + rc, count - rc,
1243                        "%-10s : %ld, "DHMS_FMT" ago\n",
1244                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
1245
1246         cur = at_get(&imp->imp_at.iat_net_latency);
1247         worst = imp->imp_at.iat_net_latency.at_worst_ever;
1248         worstt = imp->imp_at.iat_net_latency.at_worst_time;
1249         s2dhms(&ts, now - worstt);
1250         rc += snprintf(page + rc, count - rc,
1251                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
1252                        "network", cur, worst, worstt, DHMS_VARS(&ts));
1253         rc = lprocfs_at_hist_helper(page, count, rc,
1254                                     &imp->imp_at.iat_net_latency);
1255
1256         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
1257                 if (imp->imp_at.iat_portal[i] == 0)
1258                         break;
1259                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
1260                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
1261                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
1262                 s2dhms(&ts, now - worstt);
1263                 rc += snprintf(page + rc, count - rc,
1264                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
1265                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
1266                                cur, worst, worstt, DHMS_VARS(&ts));
1267                 rc = lprocfs_at_hist_helper(page, count, rc,
1268                                           &imp->imp_at.iat_service_estimate[i]);
1269         }
1270
1271         LPROCFS_CLIMP_EXIT(obd);
1272         return rc;
1273 }
1274 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1275
1276 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
1277                              int count, int *eof, void *data)
1278 {
1279         struct obd_device *obd = data;
1280         __u64 flags;
1281         int ret = 0;
1282
1283         LPROCFS_CLIMP_CHECK(obd);
1284         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
1285         ret = snprintf(page, count, "flags="LPX64"\n", flags);
1286         ret += obd_connect_flags2str(page + ret, count - ret, flags, "\n");
1287         ret += snprintf(page + ret, count - ret, "\n");
1288         LPROCFS_CLIMP_EXIT(obd);
1289         return ret;
1290 }
1291 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
1292
1293 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
1294                            int *eof,  void *data)
1295 {
1296         struct obd_device *obd = data;
1297
1298         LASSERT(obd != NULL);
1299         *eof = 1;
1300         return snprintf(page, count, "%u\n", obd->obd_num_exports);
1301 }
1302 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1303
1304 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
1305                        int *eof, void *data)
1306 {
1307         struct obd_type *class = (struct obd_type*) data;
1308
1309         LASSERT(class != NULL);
1310         *eof = 1;
1311         return snprintf(page, count, "%d\n", class->typ_refcnt);
1312 }
1313 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1314
1315 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
1316 {
1317         int rc = 0;
1318
1319         LASSERT(obd != NULL);
1320         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
1321         LASSERT(obd->obd_type->typ_procroot != NULL);
1322
1323         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
1324                                                obd->obd_type->typ_procroot,
1325                                                list, obd);
1326         if (IS_ERR(obd->obd_proc_entry)) {
1327                 rc = PTR_ERR(obd->obd_proc_entry);
1328                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
1329                 obd->obd_proc_entry = NULL;
1330         }
1331         return rc;
1332 }
1333 EXPORT_SYMBOL(lprocfs_obd_setup);
1334
1335 int lprocfs_obd_cleanup(struct obd_device *obd)
1336 {
1337         if (!obd)
1338                 return -EINVAL;
1339         if (obd->obd_proc_exports_entry) {
1340                 /* Should be no exports left */
1341                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
1342                 lprocfs_remove(&obd->obd_proc_exports_entry);
1343                 obd->obd_proc_exports_entry = NULL;
1344         }
1345         if (obd->obd_proc_entry) {
1346                 lprocfs_remove(&obd->obd_proc_entry);
1347                 obd->obd_proc_entry = NULL;
1348         }
1349         return 0;
1350 }
1351 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1352
1353 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
1354 {
1355         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
1356                client_stat->nid_proc, client_stat->nid_stats,
1357                client_stat->nid_brw_stats);
1358
1359         LASSERTF(cfs_atomic_read(&client_stat->nid_exp_ref_count) == 0,
1360                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
1361                  atomic_read(&client_stat->nid_exp_ref_count));
1362
1363         if (client_stat->nid_proc)
1364                 lprocfs_remove(&client_stat->nid_proc);
1365
1366         if (client_stat->nid_stats)
1367                 lprocfs_free_stats(&client_stat->nid_stats);
1368
1369         if (client_stat->nid_brw_stats)
1370                 OBD_FREE_PTR(client_stat->nid_brw_stats);
1371
1372         if (client_stat->nid_ldlm_stats)
1373                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
1374
1375         OBD_FREE_PTR(client_stat);
1376         return;
1377
1378 }
1379
1380 void lprocfs_free_per_client_stats(struct obd_device *obd)
1381 {
1382         cfs_hash_t *hash = obd->obd_nid_stats_hash;
1383         struct nid_stat *stat;
1384         ENTRY;
1385
1386         /* we need extra list - because hash_exit called to early */
1387         /* not need locking because all clients is died */
1388         while (!cfs_list_empty(&obd->obd_nid_stats)) {
1389                 stat = cfs_list_entry(obd->obd_nid_stats.next,
1390                                       struct nid_stat, nid_list);
1391                 cfs_list_del_init(&stat->nid_list);
1392                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
1393                 lprocfs_free_client_stats(stat);
1394         }
1395         EXIT;
1396 }
1397 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1398
1399 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
1400                                           enum lprocfs_stats_flags flags)
1401 {
1402         struct lprocfs_stats *stats;
1403         unsigned int percpusize;
1404         unsigned int num_entry;
1405
1406         if (num == 0)
1407                 return NULL;
1408
1409         if (lprocfs_no_percpu_stats != 0)
1410                 flags |= LPROCFS_STATS_FLAG_NOPERCPU;
1411
1412         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
1413                 num_entry = 1;
1414         else
1415                 num_entry = cfs_num_possible_cpus() + 1;
1416
1417         /* alloc percpu pointers for all possible cpu slots */
1418         OBD_ALLOC(stats, offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
1419         if (stats == NULL)
1420                 return NULL;
1421
1422         stats->ls_num = num;
1423         stats->ls_biggest_alloc_num = 1;
1424         stats->ls_flags = flags;
1425         cfs_spin_lock_init(&stats->ls_lock);
1426
1427         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
1428         if (num_entry > 1)
1429                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1430
1431         /* for no percpu area, the 0th entry is for real use,
1432          * for percpu area, the 0th entry is for intialized entry template */
1433         OBD_ALLOC(stats->ls_percpu[0], percpusize);
1434         if (stats->ls_percpu[0] == NULL) {
1435                 OBD_FREE(stats,
1436                          offsetof(struct lprocfs_stats, ls_percpu[num_entry]));
1437                 stats = NULL;
1438         }
1439         return stats;
1440 }
1441 EXPORT_SYMBOL(lprocfs_alloc_stats);
1442
1443 void lprocfs_free_stats(struct lprocfs_stats **statsh)
1444 {
1445         struct lprocfs_stats *stats = *statsh;
1446         unsigned int num_entry;
1447         unsigned int percpusize;
1448         unsigned int i;
1449
1450         if (stats == NULL || stats->ls_num == 0)
1451                 return;
1452         *statsh = NULL;
1453
1454         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1455                 num_entry = 1;
1456         else
1457                 num_entry = cfs_num_possible_cpus() + 1;
1458
1459         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1460         if (num_entry > 1)
1461                 percpusize = CFS_L1_CACHE_ALIGN(percpusize);
1462         for (i = 0; i < num_entry; i++)
1463                 if (stats->ls_percpu[i] != NULL)
1464                         OBD_FREE(stats->ls_percpu[i], percpusize);
1465         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_entry]));
1466 }
1467 EXPORT_SYMBOL(lprocfs_free_stats);
1468
1469 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1470 {
1471         struct lprocfs_counter *percpu_cntr;
1472         int                     i;
1473         int                     j;
1474         unsigned int            num_entry;
1475         unsigned long           flags = 0;
1476
1477         num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1478
1479         for (i = 0; i < num_entry; i++) {
1480                 if (stats->ls_percpu[i] == NULL)
1481                         continue;
1482                 for (j = 0; j < stats->ls_num; j++) {
1483                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1484                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1485                         percpu_cntr->lc_count = 0;
1486                         percpu_cntr->lc_sum = 0;
1487                         percpu_cntr->lc_min = LC_MIN_INIT;
1488                         percpu_cntr->lc_max = 0;
1489                         percpu_cntr->lc_sumsquare = 0;
1490                         cfs_atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1491                 }
1492         }
1493
1494         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1495 }
1496 EXPORT_SYMBOL(lprocfs_clear_stats);
1497
1498 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1499                                        size_t len, loff_t *off)
1500 {
1501         struct seq_file *seq = file->private_data;
1502         struct lprocfs_stats *stats = seq->private;
1503
1504         lprocfs_clear_stats(stats);
1505
1506         return len;
1507 }
1508
1509 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1510 {
1511         struct lprocfs_stats *stats = p->private;
1512         /* return 1st cpu location */
1513         return (*pos >= stats->ls_num) ? NULL :
1514                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1515 }
1516
1517 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1518 {
1519 }
1520
1521 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1522 {
1523         struct lprocfs_stats *stats = p->private;
1524         ++*pos;
1525         return (*pos >= stats->ls_num) ? NULL :
1526                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1527 }
1528
1529 /* seq file export of one lprocfs counter */
1530 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1531 {
1532        struct lprocfs_stats *stats = p->private;
1533        struct lprocfs_counter *cntr = v;
1534        struct lprocfs_counter ret;
1535        int idx, rc = 0;
1536
1537        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1538                struct timeval now;
1539                cfs_gettimeofday(&now);
1540                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1541                                "snapshot_time", now.tv_sec, now.tv_usec);
1542                if (rc < 0)
1543                        return rc;
1544        }
1545        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1546
1547        lprocfs_stats_collect(stats, idx, &ret);
1548
1549        if (ret.lc_count == 0)
1550                goto out;
1551
1552        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1553                        ret.lc_count, cntr->lc_units);
1554
1555        if (rc < 0)
1556                goto out;
1557
1558        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1559                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1560                                ret.lc_min, ret.lc_max, ret.lc_sum);
1561                if (rc < 0)
1562                        goto out;
1563                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1564                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1565                if (rc < 0)
1566                        goto out;
1567        }
1568        rc = seq_printf(p, "\n");
1569  out:
1570        return (rc < 0) ? rc : 0;
1571 }
1572
1573 struct seq_operations lprocfs_stats_seq_sops = {
1574         start: lprocfs_stats_seq_start,
1575         stop:  lprocfs_stats_seq_stop,
1576         next:  lprocfs_stats_seq_next,
1577         show:  lprocfs_stats_seq_show,
1578 };
1579
1580 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1581 {
1582         struct proc_dir_entry *dp = PDE(inode);
1583         struct seq_file *seq;
1584         int rc;
1585
1586         if (LPROCFS_ENTRY_AND_CHECK(dp))
1587                 return -ENOENT;
1588
1589         rc = seq_open(file, &lprocfs_stats_seq_sops);
1590         if (rc) {
1591                 LPROCFS_EXIT();
1592                 return rc;
1593         }
1594         seq = file->private_data;
1595         seq->private = dp->data;
1596         return 0;
1597 }
1598
1599 struct file_operations lprocfs_stats_seq_fops = {
1600         .owner   = THIS_MODULE,
1601         .open    = lprocfs_stats_seq_open,
1602         .read    = seq_read,
1603         .write   = lprocfs_stats_seq_write,
1604         .llseek  = seq_lseek,
1605         .release = lprocfs_seq_release,
1606 };
1607
1608 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1609                            struct lprocfs_stats *stats)
1610 {
1611         struct proc_dir_entry *entry;
1612         LASSERT(root != NULL);
1613
1614         LPROCFS_WRITE_ENTRY();
1615         entry = create_proc_entry(name, 0644, root);
1616         if (entry) {
1617                 entry->proc_fops = &lprocfs_stats_seq_fops;
1618                 entry->data = stats;
1619         }
1620
1621         LPROCFS_WRITE_EXIT();
1622
1623         if (entry == NULL)
1624                 return -ENOMEM;
1625
1626         return 0;
1627 }
1628 EXPORT_SYMBOL(lprocfs_register_stats);
1629
1630 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1631                           unsigned conf, const char *name, const char *units)
1632 {
1633         struct lprocfs_counter *c     = &(stats->ls_percpu[0]->lp_cntr[index]);
1634         unsigned long           flags = 0;
1635
1636         LASSERT(stats != NULL);
1637         LASSERT(stats->ls_percpu[0] != NULL);
1638
1639         lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags);
1640         c->lc_config = conf;
1641         c->lc_count = 0;
1642         c->lc_sum = 0;
1643         c->lc_min = LC_MIN_INIT;
1644         c->lc_max = 0;
1645         c->lc_name = name;
1646         c->lc_units = units;
1647         lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags);
1648 }
1649 EXPORT_SYMBOL(lprocfs_counter_init);
1650
1651 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1652 do {                                                                       \
1653         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1654         LASSERT(coffset < stats->ls_num);                                  \
1655         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1656 } while (0)
1657
1658 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1659 {
1660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1671         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1672         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1673         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1674         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1675         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1676         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1677         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1678         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1679         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1680         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1681         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1682         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1683         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1684         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1685         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1686         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create_async);
1687         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1688         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1689         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1690         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1691         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1692         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1693         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1694         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1695         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1696         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1697         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1698         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1699         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1700         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1701         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1702         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1703         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1704         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
1705         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1706         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1707         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1708         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1709         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1710         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1711         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1712         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1713         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1714         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1715         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1716         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1717         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1718         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1719         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1720         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1721         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1722         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1723         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1724         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1725         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1726         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
1727         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
1728 }
1729 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1730
1731 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1732 {
1733         struct lprocfs_stats *stats;
1734         unsigned int num_stats;
1735         int rc, i;
1736
1737         LASSERT(obd->obd_stats == NULL);
1738         LASSERT(obd->obd_proc_entry != NULL);
1739         LASSERT(obd->obd_cntr_base == 0);
1740
1741         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1742                 num_private_stats - 1 /* o_owner */;
1743         stats = lprocfs_alloc_stats(num_stats, 0);
1744         if (stats == NULL)
1745                 return -ENOMEM;
1746
1747         lprocfs_init_ops_stats(num_private_stats, stats);
1748
1749         for (i = num_private_stats; i < num_stats; i++) {
1750                 /* If this LBUGs, it is likely that an obd
1751                  * operation was added to struct obd_ops in
1752                  * <obd.h>, and that the corresponding line item
1753                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1754                  * is missing from the list above. */
1755                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1756                          "Missing obd_stat initializer obd_op "
1757                          "operation at offset %d.\n", i - num_private_stats);
1758         }
1759         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1760         if (rc < 0) {
1761                 lprocfs_free_stats(&stats);
1762         } else {
1763                 obd->obd_stats  = stats;
1764                 obd->obd_cntr_base = num_private_stats;
1765         }
1766         return rc;
1767 }
1768 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1769
1770 void lprocfs_free_obd_stats(struct obd_device *obd)
1771 {
1772         if (obd->obd_stats)
1773                 lprocfs_free_stats(&obd->obd_stats);
1774 }
1775 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1776
1777 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1778 do {                                                                    \
1779         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1780         LASSERT(coffset < stats->ls_num);                               \
1781         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1782 } while (0)
1783
1784 void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats)
1785 {
1786         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1787         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1788         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1789         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1790         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1791         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1792         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1793         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1794         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1795         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1796         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1797         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1798         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1799         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1800         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1801         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1802         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1803         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1804         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1805         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1806         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1807         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1808         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1809         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1810         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1811         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1812         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1813         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1814         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1815         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1816         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1817         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1818 }
1819 EXPORT_SYMBOL(lprocfs_init_mps_stats);
1820
1821 int lprocfs_alloc_md_stats(struct obd_device *obd,
1822                            unsigned num_private_stats)
1823 {
1824         struct lprocfs_stats *stats;
1825         unsigned int num_stats;
1826         int rc, i;
1827
1828         LASSERT(obd->md_stats == NULL);
1829         LASSERT(obd->obd_proc_entry != NULL);
1830         LASSERT(obd->md_cntr_base == 0);
1831
1832         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1833                     num_private_stats;
1834         stats = lprocfs_alloc_stats(num_stats, 0);
1835         if (stats == NULL)
1836                 return -ENOMEM;
1837
1838         lprocfs_init_mps_stats(num_private_stats, stats);
1839
1840         for (i = num_private_stats; i < num_stats; i++) {
1841                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1842                         CERROR("Missing md_stat initializer md_op "
1843                                "operation at offset %d. Aborting.\n",
1844                                i - num_private_stats);
1845                         LBUG();
1846                 }
1847         }
1848         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1849         if (rc < 0) {
1850                 lprocfs_free_stats(&stats);
1851         } else {
1852                 obd->md_stats  = stats;
1853                 obd->md_cntr_base = num_private_stats;
1854         }
1855         return rc;
1856 }
1857 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
1858
1859 void lprocfs_free_md_stats(struct obd_device *obd)
1860 {
1861         struct lprocfs_stats *stats = obd->md_stats;
1862
1863         if (stats != NULL) {
1864                 obd->md_stats = NULL;
1865                 obd->md_cntr_base = 0;
1866                 lprocfs_free_stats(&stats);
1867         }
1868 }
1869 EXPORT_SYMBOL(lprocfs_free_md_stats);
1870
1871 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1872 {
1873         lprocfs_counter_init(ldlm_stats,
1874                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1875                              0, "ldlm_enqueue", "reqs");
1876         lprocfs_counter_init(ldlm_stats,
1877                              LDLM_CONVERT - LDLM_FIRST_OPC,
1878                              0, "ldlm_convert", "reqs");
1879         lprocfs_counter_init(ldlm_stats,
1880                              LDLM_CANCEL - LDLM_FIRST_OPC,
1881                              0, "ldlm_cancel", "reqs");
1882         lprocfs_counter_init(ldlm_stats,
1883                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1884                              0, "ldlm_bl_callback", "reqs");
1885         lprocfs_counter_init(ldlm_stats,
1886                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1887                              0, "ldlm_cp_callback", "reqs");
1888         lprocfs_counter_init(ldlm_stats,
1889                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1890                              0, "ldlm_gl_callback", "reqs");
1891 }
1892 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
1893
1894 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1895                          int *eof,  void *data)
1896 {
1897         struct obd_export *exp = data;
1898         LASSERT(exp != NULL);
1899         *eof = 1;
1900         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1901 }
1902
1903 struct exp_uuid_cb_data {
1904         char                   *page;
1905         int                     count;
1906         int                    *eof;
1907         int                    *len;
1908 };
1909
1910 static void
1911 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1912                             int count, int *eof, int *len)
1913 {
1914         cb_data->page = page;
1915         cb_data->count = count;
1916         cb_data->eof = eof;
1917         cb_data->len = len;
1918 }
1919
1920 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1921                            cfs_hlist_node_t *hnode, void *cb_data)
1922
1923 {
1924         struct obd_export *exp = cfs_hash_object(hs, hnode);
1925         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1926
1927         if (exp->exp_nid_stats)
1928                 *data->len += snprintf((data->page + *data->len),
1929                                        data->count, "%s\n",
1930                                        obd_uuid2str(&exp->exp_client_uuid));
1931         return 0;
1932 }
1933
1934 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1935                         int *eof,  void *data)
1936 {
1937         struct nid_stat *stats = (struct nid_stat *)data;
1938         struct exp_uuid_cb_data cb_data;
1939         struct obd_device *obd = stats->nid_obd;
1940         int len = 0;
1941
1942         *eof = 1;
1943         page[0] = '\0';
1944         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1945         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1946                               lprocfs_exp_print_uuid, &cb_data);
1947         return (*cb_data.len);
1948 }
1949
1950 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1951                            cfs_hlist_node_t *hnode, void *cb_data)
1952
1953 {
1954         struct exp_uuid_cb_data *data = cb_data;
1955         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1956
1957         if (exp->exp_lock_hash != NULL) {
1958                 if (!*data->len) {
1959                         *data->len += cfs_hash_debug_header(data->page,
1960                                                             data->count);
1961                 }
1962                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1963                                                  data->count);
1964         }
1965
1966         return 0;
1967 }
1968
1969 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1970                         int *eof,  void *data)
1971 {
1972         struct nid_stat *stats = (struct nid_stat *)data;
1973         struct exp_uuid_cb_data cb_data;
1974         struct obd_device *obd = stats->nid_obd;
1975         int len = 0;
1976
1977         *eof = 1;
1978         page[0] = '\0';
1979         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1980
1981         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1982                               lprocfs_exp_print_hash, &cb_data);
1983         return (*cb_data.len);
1984 }
1985
1986 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1987                                         int count, int *eof,  void *data)
1988 {
1989         *eof = 1;
1990         return snprintf(page, count, "%s\n",
1991                         "Write into this file to clear all nid stats and "
1992                         "stale nid entries");
1993 }
1994 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1995
1996 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1997 {
1998         struct nid_stat *stat = obj;
1999         int i;
2000         ENTRY;
2001
2002         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
2003         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 1) {
2004                 /* object has only hash references. */
2005                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
2006                 cfs_list_move(&stat->nid_list, data);
2007                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
2008                 RETURN(1);
2009         }
2010         /* we has reference to object - only clear data*/
2011         if (stat->nid_stats)
2012                 lprocfs_clear_stats(stat->nid_stats);
2013
2014         if (stat->nid_brw_stats) {
2015                 for (i = 0; i < BRW_LAST; i++)
2016                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
2017         }
2018         RETURN(0);
2019 }
2020
2021 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
2022                                   unsigned long count, void *data)
2023 {
2024         struct obd_device *obd = (struct obd_device *)data;
2025         struct nid_stat *client_stat;
2026         CFS_LIST_HEAD(free_list);
2027
2028         cfs_hash_cond_del(obd->obd_nid_stats_hash,
2029                           lprocfs_nid_stats_clear_write_cb, &free_list);
2030
2031         while (!cfs_list_empty(&free_list)) {
2032                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
2033                                              nid_list);
2034                 cfs_list_del_init(&client_stat->nid_list);
2035                 lprocfs_free_client_stats(client_stat);
2036         }
2037
2038         return count;
2039 }
2040 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
2041
2042 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
2043 {
2044         struct nid_stat *new_stat, *old_stat;
2045         struct obd_device *obd = NULL;
2046         cfs_proc_dir_entry_t *entry;
2047         char *buffer = NULL;
2048         int rc = 0;
2049         ENTRY;
2050
2051         *newnid = 0;
2052
2053         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
2054             !exp->exp_obd->obd_nid_stats_hash)
2055                 RETURN(-EINVAL);
2056
2057         /* not test against zero because eric say:
2058          * You may only test nid against another nid, or LNET_NID_ANY.
2059          * Anything else is nonsense.*/
2060         if (!nid || *nid == LNET_NID_ANY)
2061                 RETURN(0);
2062
2063         obd = exp->exp_obd;
2064
2065         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
2066
2067         OBD_ALLOC_PTR(new_stat);
2068         if (new_stat == NULL)
2069                 RETURN(-ENOMEM);
2070
2071         new_stat->nid               = *nid;
2072         new_stat->nid_obd           = exp->exp_obd;
2073         /* we need set default refcount to 1 to balance obd_disconnect */
2074         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
2075
2076         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
2077                                            nid, &new_stat->nid_hash);
2078         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
2079                old_stat, libcfs_nid2str(*nid),
2080                cfs_atomic_read(&new_stat->nid_exp_ref_count));
2081
2082         /* We need to release old stats because lprocfs_exp_cleanup() hasn't
2083          * been and will never be called. */
2084         if (exp->exp_nid_stats) {
2085                 nidstat_putref(exp->exp_nid_stats);
2086                 exp->exp_nid_stats = NULL;
2087         }
2088
2089         /* Return -EALREADY here so that we know that the /proc
2090          * entry already has been created */
2091         if (old_stat != new_stat) {
2092                 exp->exp_nid_stats = old_stat;
2093                 GOTO(destroy_new, rc = -EALREADY);
2094         }
2095         /* not found - create */
2096         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
2097         if (buffer == NULL)
2098                 GOTO(destroy_new, rc = -ENOMEM);
2099
2100         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
2101         new_stat->nid_proc = lprocfs_register(buffer,
2102                                               obd->obd_proc_exports_entry,
2103                                               NULL, NULL);
2104         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
2105
2106         if (new_stat->nid_proc == NULL) {
2107                 CERROR("Error making export directory for nid %s\n",
2108                        libcfs_nid2str(*nid));
2109                 GOTO(destroy_new_ns, rc = -ENOMEM);
2110         }
2111
2112         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
2113                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
2114         if (IS_ERR(entry)) {
2115                 CWARN("Error adding the NID stats file\n");
2116                 rc = PTR_ERR(entry);
2117                 GOTO(destroy_new_ns, rc);
2118         }
2119
2120         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
2121                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
2122         if (IS_ERR(entry)) {
2123                 CWARN("Error adding the hash file\n");
2124                 rc = PTR_ERR(entry);
2125                 GOTO(destroy_new_ns, rc);
2126         }
2127
2128         exp->exp_nid_stats = new_stat;
2129         *newnid = 1;
2130         /* protect competitive add to list, not need locking on destroy */
2131         cfs_spin_lock(&obd->obd_nid_lock);
2132         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
2133         cfs_spin_unlock(&obd->obd_nid_lock);
2134
2135         RETURN(rc);
2136
2137 destroy_new_ns:
2138         if (new_stat->nid_proc != NULL)
2139                 lprocfs_remove(&new_stat->nid_proc);
2140         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
2141
2142 destroy_new:
2143         nidstat_putref(new_stat);
2144         OBD_FREE_PTR(new_stat);
2145         RETURN(rc);
2146 }
2147 EXPORT_SYMBOL(lprocfs_exp_setup);
2148
2149 int lprocfs_exp_cleanup(struct obd_export *exp)
2150 {
2151         struct nid_stat *stat = exp->exp_nid_stats;
2152
2153         if(!stat || !exp->exp_obd)
2154                 RETURN(0);
2155
2156         nidstat_putref(exp->exp_nid_stats);
2157         exp->exp_nid_stats = NULL;
2158
2159         return 0;
2160 }
2161 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2162
2163 int lprocfs_write_helper(const char *buffer, unsigned long count,
2164                          int *val)
2165 {
2166         return lprocfs_write_frac_helper(buffer, count, val, 1);
2167 }
2168 EXPORT_SYMBOL(lprocfs_write_helper);
2169
2170 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
2171                               int *val, int mult)
2172 {
2173         char kernbuf[20], *end, *pbuf;
2174
2175         if (count > (sizeof(kernbuf) - 1))
2176                 return -EINVAL;
2177
2178         if (cfs_copy_from_user(kernbuf, buffer, count))
2179                 return -EFAULT;
2180
2181         kernbuf[count] = '\0';
2182         pbuf = kernbuf;
2183         if (*pbuf == '-') {
2184                 mult = -mult;
2185                 pbuf++;
2186         }
2187
2188         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2189         if (pbuf == end)
2190                 return -EINVAL;
2191
2192         if (end != NULL && *end == '.') {
2193                 int temp_val, pow = 1;
2194                 int i;
2195
2196                 pbuf = end + 1;
2197                 if (strlen(pbuf) > 5)
2198                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
2199
2200                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
2201
2202                 if (pbuf < end) {
2203                         for (i = 0; i < (end - pbuf); i++)
2204                                 pow *= 10;
2205
2206                         *val += temp_val / pow;
2207                 }
2208         }
2209         return 0;
2210 }
2211 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2212
2213 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
2214                              int mult)
2215 {
2216         long decimal_val, frac_val;
2217         int prtn;
2218
2219         if (count < 10)
2220                 return -EINVAL;
2221
2222         decimal_val = val / mult;
2223         prtn = snprintf(buffer, count, "%ld", decimal_val);
2224         frac_val = val % mult;
2225
2226         if (prtn < (count - 4) && frac_val > 0) {
2227                 long temp_frac;
2228                 int i, temp_mult = 1, frac_bits = 0;
2229
2230                 temp_frac = frac_val * 10;
2231                 buffer[prtn++] = '.';
2232                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
2233                         /* only reserved 2 bits fraction */
2234                         buffer[prtn++] ='0';
2235                         temp_frac *= 10;
2236                         frac_bits++;
2237                 }
2238                 /*
2239                  * Need to think these cases :
2240                  *      1. #echo x.00 > /proc/xxx       output result : x
2241                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
2242                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
2243                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
2244                  *      Only reserved 2 bits fraction.
2245                  */
2246                 for (i = 0; i < (5 - prtn); i++)
2247                         temp_mult *= 10;
2248
2249                 frac_bits = min((int)count - prtn, 3 - frac_bits);
2250                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
2251                                  frac_val * temp_mult / mult);
2252
2253                 prtn--;
2254                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
2255                         prtn--;
2256                         if (buffer[prtn] == '.') {
2257                                 prtn--;
2258                                 break;
2259                         }
2260                 }
2261                 prtn++;
2262         }
2263         buffer[prtn++] ='\n';
2264         return prtn;
2265 }
2266 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2267
2268 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
2269 {
2270         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2271 }
2272 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2273
2274 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2275                               __u64 *val, int mult)
2276 {
2277         char kernbuf[22], *end, *pbuf;
2278         __u64 whole, frac = 0, units;
2279         unsigned frac_d = 1;
2280
2281         if (count > (sizeof(kernbuf) - 1))
2282                 return -EINVAL;
2283
2284         if (cfs_copy_from_user(kernbuf, buffer, count))
2285                 return -EFAULT;
2286
2287         kernbuf[count] = '\0';
2288         pbuf = kernbuf;
2289         if (*pbuf == '-') {
2290                 mult = -mult;
2291                 pbuf++;
2292         }
2293
2294         whole = simple_strtoull(pbuf, &end, 10);
2295         if (pbuf == end)
2296                 return -EINVAL;
2297
2298         if (end != NULL && *end == '.') {
2299                 int i;
2300                 pbuf = end + 1;
2301
2302                 /* need to limit frac_d to a __u32 */
2303                 if (strlen(pbuf) > 10)
2304                         pbuf[10] = '\0';
2305
2306                 frac = simple_strtoull(pbuf, &end, 10);
2307                 /* count decimal places */
2308                 for (i = 0; i < (end - pbuf); i++)
2309                         frac_d *= 10;
2310         }
2311
2312         units = 1;
2313         switch(*end) {
2314         case 'p': case 'P':
2315                 units <<= 10;
2316         case 't': case 'T':
2317                 units <<= 10;
2318         case 'g': case 'G':
2319                 units <<= 10;
2320         case 'm': case 'M':
2321                 units <<= 10;
2322         case 'k': case 'K':
2323                 units <<= 10;
2324         }
2325         /* Specified units override the multiplier */
2326         if (units)
2327                 mult = mult < 0 ? -units : units;
2328
2329         frac *= mult;
2330         do_div(frac, frac_d);
2331         *val = whole * mult + frac;
2332         return 0;
2333 }
2334 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2335
2336 static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
2337 {
2338         size_t l2;
2339
2340         l2 = strlen(s2);
2341         if (!l2)
2342                 return (char *)s1;
2343         while (len >= l2) {
2344                 len--;
2345                 if (!memcmp(s1, s2, l2))
2346                         return (char *)s1;
2347                 s1++;
2348         }
2349         return NULL;
2350 }
2351
2352 /**
2353  * Find the string \a name in the input \a buffer, and return a pointer to the
2354  * value immediately following \a name, reducing \a count appropriately.
2355  * If \a name is not found the original \a buffer is returned.
2356  */
2357 char *lprocfs_find_named_value(const char *buffer, const char *name,
2358                                 unsigned long *count)
2359 {
2360         char *val;
2361         size_t buflen = *count;
2362
2363         /* there is no strnstr() in rhel5 and ubuntu kernels */
2364         val = lprocfs_strnstr(buffer, name, buflen);
2365         if (val == NULL)
2366                 return (char *)buffer;
2367
2368         val += strlen(name);                             /* skip prefix */
2369         while (val < buffer + buflen && isspace(*val)) /* skip separator */
2370                 val++;
2371
2372         *count = 0;
2373         while (val < buffer + buflen && isalnum(*val)) {
2374                 ++*count;
2375                 ++val;
2376         }
2377
2378         return val - *count;
2379 }
2380 EXPORT_SYMBOL(lprocfs_find_named_value);
2381
2382 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2383                        struct file_operations *seq_fops, void *data)
2384 {
2385         struct proc_dir_entry *entry;
2386         ENTRY;
2387
2388         LPROCFS_WRITE_ENTRY();
2389         entry = create_proc_entry(name, mode, parent);
2390         if (entry) {
2391                 entry->proc_fops = seq_fops;
2392                 entry->data = data;
2393         }
2394         LPROCFS_WRITE_EXIT();
2395
2396         if (entry == NULL)
2397                 RETURN(-ENOMEM);
2398
2399         RETURN(0);
2400 }
2401 EXPORT_SYMBOL(lprocfs_seq_create);
2402
2403 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2404                                       mode_t mode,
2405                                       struct file_operations *seq_fops,
2406                                       void *data)
2407 {
2408         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2409                                    mode, seq_fops, data));
2410 }
2411 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2412
2413 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2414 {
2415         if (value >= OBD_HIST_MAX)
2416                 value = OBD_HIST_MAX - 1;
2417
2418         cfs_spin_lock(&oh->oh_lock);
2419         oh->oh_buckets[value]++;
2420         cfs_spin_unlock(&oh->oh_lock);
2421 }
2422 EXPORT_SYMBOL(lprocfs_oh_tally);
2423
2424 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2425 {
2426         unsigned int val;
2427
2428         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2429                 ;
2430
2431         lprocfs_oh_tally(oh, val);
2432 }
2433 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2434
2435 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2436 {
2437         unsigned long ret = 0;
2438         int i;
2439
2440         for (i = 0; i < OBD_HIST_MAX; i++)
2441                 ret +=  oh->oh_buckets[i];
2442         return ret;
2443 }
2444 EXPORT_SYMBOL(lprocfs_oh_sum);
2445
2446 void lprocfs_oh_clear(struct obd_histogram *oh)
2447 {
2448         cfs_spin_lock(&oh->oh_lock);
2449         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2450         cfs_spin_unlock(&oh->oh_lock);
2451 }
2452 EXPORT_SYMBOL(lprocfs_oh_clear);
2453
2454 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2455                         int count, int *eof, void *data)
2456 {
2457         struct obd_device *obd = data;
2458         int c = 0;
2459
2460         if (obd == NULL)
2461                 return 0;
2462
2463         c += cfs_hash_debug_header(page, count);
2464         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2465         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2466         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2467
2468         return c;
2469 }
2470 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2471
2472 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2473                                    int count, int *eof, void *data)
2474 {
2475         struct obd_device *obd = data;
2476         int len = 0, size;
2477
2478         LASSERT(obd != NULL);
2479         LASSERT(count >= 0);
2480
2481         /* Set start of user data returned to
2482            page + off since the user may have
2483            requested to read much smaller than
2484            what we need to read */
2485         *start = page + off;
2486
2487         /* We know we are allocated a page here.
2488            Also we know that this function will
2489            not need to write more than a page
2490            so we can truncate at CFS_PAGE_SIZE.  */
2491         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2492
2493         /* Initialize the page */
2494         memset(page, 0, size);
2495
2496         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2497                 goto out;
2498         if (obd->obd_max_recoverable_clients == 0) {
2499                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2500                         goto out;
2501
2502                 goto fclose;
2503         }
2504
2505         /* sampled unlocked, but really... */
2506         if (obd->obd_recovering == 0) {
2507                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2508                         goto out;
2509                 if (lprocfs_obd_snprintf(&page, size, &len,
2510                                          "recovery_start: %lu\n",
2511                                          obd->obd_recovery_start) <= 0)
2512                         goto out;
2513                 if (lprocfs_obd_snprintf(&page, size, &len,
2514                                          "recovery_duration: %lu\n",
2515                                          obd->obd_recovery_end -
2516                                          obd->obd_recovery_start) <= 0)
2517                         goto out;
2518                 /* Number of clients that have completed recovery */
2519                 if (lprocfs_obd_snprintf(&page, size, &len,
2520                                          "completed_clients: %d/%d\n",
2521                                          obd->obd_max_recoverable_clients -
2522                                          obd->obd_stale_clients,
2523                                          obd->obd_max_recoverable_clients) <= 0)
2524                         goto out;
2525                 if (lprocfs_obd_snprintf(&page, size, &len,
2526                                          "replayed_requests: %d\n",
2527                                          obd->obd_replayed_requests) <= 0)
2528                         goto out;
2529                 if (lprocfs_obd_snprintf(&page, size, &len,
2530                                          "last_transno: "LPD64"\n",
2531                                          obd->obd_next_recovery_transno - 1)<=0)
2532                         goto out;
2533                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2534                                          obd->obd_version_recov ?
2535                                          "ENABLED" : "DISABLED") <=0)
2536                         goto out;
2537                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
2538                                          obd->obd_no_ir ?
2539                                          "DISABLED" : "ENABLED") <= 0)
2540                         goto out;
2541                 goto fclose;
2542         }
2543
2544         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2545                 goto out;
2546         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2547                                  obd->obd_recovery_start) <= 0)
2548                 goto out;
2549         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2550                                  cfs_time_current_sec() >=
2551                                  obd->obd_recovery_start +
2552                                  obd->obd_recovery_timeout ? 0 :
2553                                  obd->obd_recovery_start +
2554                                  obd->obd_recovery_timeout -
2555                                  cfs_time_current_sec()) <= 0)
2556                 goto out;
2557         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2558                                  cfs_atomic_read(&obd->obd_connected_clients),
2559                                  obd->obd_max_recoverable_clients) <= 0)
2560                 goto out;
2561         /* Number of clients that have completed recovery */
2562         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2563                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2564                 <= 0)
2565                 goto out;
2566         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2567                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2568                 <=0)
2569                 goto out;
2570         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2571                                  cfs_atomic_read(&obd->obd_connected_clients) -
2572                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2573                 <=0)
2574                 goto out;
2575         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2576                                  obd->obd_stale_clients) <= 0)
2577                 goto out;
2578         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2579                                  obd->obd_replayed_requests) <= 0)
2580                 goto out;
2581         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2582                                  obd->obd_requests_queued_for_recovery) <= 0)
2583                 goto out;
2584
2585         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2586                                  obd->obd_next_recovery_transno) <= 0)
2587                 goto out;
2588
2589 fclose:
2590         *eof = 1;
2591 out:
2592         return min(count, len - (int)off);
2593 }
2594 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2595
2596 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
2597                              int count, int *eof, void *data)
2598 {
2599         struct obd_device *obd = (struct obd_device *)data;
2600         LASSERT(obd != NULL);
2601
2602         return snprintf(page, count, "%d\n",
2603                         obd->obd_recovery_ir_factor);
2604 }
2605 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
2606
2607 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
2608                              unsigned long count, void *data)
2609 {
2610         struct obd_device *obd = (struct obd_device *)data;
2611         int val, rc;
2612         LASSERT(obd != NULL);
2613
2614         rc = lprocfs_write_helper(buffer, count, &val);
2615         if (rc)
2616                 return rc;
2617
2618         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
2619                 return -EINVAL;
2620
2621         obd->obd_recovery_ir_factor = val;
2622         return count;
2623 }
2624 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
2625
2626 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2627                                       int count, int *eof, void *data)
2628 {
2629         struct obd_device *obd = (struct obd_device *)data;
2630         LASSERT(obd != NULL);
2631
2632         return snprintf(page, count, "%d\n",
2633                         obd->obd_recovery_timeout);
2634 }
2635 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2636
2637 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2638                                       unsigned long count, void *data)
2639 {
2640         struct obd_device *obd = (struct obd_device *)data;
2641         int val, rc;
2642         LASSERT(obd != NULL);
2643
2644         rc = lprocfs_write_helper(buffer, count, &val);
2645         if (rc)
2646                 return rc;
2647
2648         obd->obd_recovery_timeout = val;
2649         return count;
2650 }
2651 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2652
2653 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2654                                       int count, int *eof, void *data)
2655 {
2656         struct obd_device *obd = data;
2657         LASSERT(obd != NULL);
2658
2659         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
2660 }
2661 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2662
2663 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2664                                       unsigned long count, void *data)
2665 {
2666         struct obd_device *obd = data;
2667         int val, rc;
2668         LASSERT(obd != NULL);
2669
2670         rc = lprocfs_write_helper(buffer, count, &val);
2671         if (rc)
2672                 return rc;
2673
2674         obd->obd_recovery_time_hard = val;
2675         return count;
2676 }
2677 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2678
2679 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2680                           int count, int *eof, void *data)
2681 {
2682         struct obd_device *obd = (struct obd_device *)data;
2683
2684         LASSERT(obd != NULL);
2685         LASSERT(mnt_get_devname(obd->u.obt.obt_vfsmnt));
2686         *eof = 1;
2687         return snprintf(page, count, "%s\n",
2688                         mnt_get_devname(obd->u.obt.obt_vfsmnt));
2689 }
2690 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2691
2692 int lprocfs_obd_rd_max_pages_per_rpc(char *page, char **start, off_t off,
2693                                      int count, int *eof, void *data)
2694 {
2695         struct obd_device *dev = data;
2696         struct client_obd *cli = &dev->u.cli;
2697         int rc;
2698
2699         client_obd_list_lock(&cli->cl_loi_list_lock);
2700         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
2701         client_obd_list_unlock(&cli->cl_loi_list_lock);
2702         return rc;
2703 }
2704 EXPORT_SYMBOL(lprocfs_obd_rd_max_pages_per_rpc);
2705
2706 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
2707                                int count, int *eof, void *data)
2708 {
2709         struct obd_device *obd = (struct obd_device *)data;
2710         struct obd_device_target *target = &obd->u.obt;
2711
2712         LASSERT(obd != NULL);
2713         LASSERT(target->obt_magic == OBT_MAGIC);
2714         *eof = 1;
2715         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
2716 }
2717 EXPORT_SYMBOL(lprocfs_target_rd_instance);
2718 #endif /* LPROCFS*/