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