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