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