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