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