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