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