Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44 #define DEBUG_SUBSYSTEM S_CLASS
45
46 #ifndef __KERNEL__
47 # include <liblustre.h>
48 #endif
49
50 #include <obd_class.h>
51 #include <lprocfs_status.h>
52 #include <lustre_fsfilt.h>
53
54 #if defined(LPROCFS)
55
56 #define MAX_STRING_SIZE 128
57
58 /* for bug 10866, global variable */
59 DECLARE_RWSEM(_lprocfs_lock);
60 EXPORT_SYMBOL(_lprocfs_lock);
61
62 int lprocfs_seq_release(struct inode *inode, struct file *file)
63 {
64         LPROCFS_EXIT();
65         return seq_release(inode, file);
66 }
67 EXPORT_SYMBOL(lprocfs_seq_release);
68
69 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
70                                     const char *name)
71 {
72         struct proc_dir_entry *temp;
73
74         if (head == NULL)
75                 return NULL;
76         LPROCFS_ENTRY();
77
78         temp = head->subdir;
79         while (temp != NULL) {
80                 if (strcmp(temp->name, name) == 0) {
81                         LPROCFS_EXIT();
82                         return temp;
83                 }
84
85                 temp = temp->next;
86         }
87         LPROCFS_EXIT();
88         return NULL;
89 }
90
91 /* lprocfs API calls */
92
93 /* Function that emulates snprintf but also has the side effect of advancing
94    the page pointer for the next write into the buffer, incrementing the total
95    length written to the buffer, and decrementing the size left in the
96    buffer. */
97 static int lprocfs_obd_snprintf(char **page, int end, int *len,
98                                 const char *format, ...)
99 {
100         va_list list;
101         int n;
102
103         if (*len >= end)
104                 return 0;
105
106         va_start(list, format);
107         n = vsnprintf(*page, end - *len, format, list);
108         va_end(list);
109
110         *page += n; *len += n;
111         return n;
112 }
113
114 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
115                        read_proc_t *read_proc, write_proc_t *write_proc,
116                        void *data)
117 {
118         struct proc_dir_entry *proc;
119         mode_t mode = 0;
120
121         if (root == NULL || name == NULL)
122                 return -EINVAL;
123         if (read_proc)
124                 mode = 0444;
125         if (write_proc)
126                 mode |= 0200;
127         proc = create_proc_entry(name, mode, root);
128         if (!proc) {
129                 CERROR("LprocFS: No memory to create /proc entry %s", name);
130                 return -ENOMEM;
131         }
132         proc->read_proc = read_proc;
133         proc->write_proc = write_proc;
134         proc->data = data;
135         return 0;
136 }
137
138 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
139                         struct proc_dir_entry *parent, const char *dest)
140 {
141         struct proc_dir_entry *entry;
142
143         if (parent == NULL || dest == NULL)
144                 return NULL;
145
146         entry = proc_symlink(name, parent, dest);
147         if (entry == NULL)
148                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
149                         name, dest);
150         return entry;
151 }
152
153 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
154                                  size_t size, loff_t *ppos)
155 {
156         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
157         char *page, *start = NULL;
158         int rc = 0, eof = 1, count;
159
160         if (*ppos >= CFS_PAGE_SIZE)
161                 return 0;
162
163         page = (char *)__get_free_page(GFP_KERNEL);
164         if (page == NULL)
165                 return -ENOMEM;
166
167         LPROCFS_ENTRY();
168         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
169         if (!dp->deleted && dp->read_proc)
170                 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
171                         &eof, dp->data);
172         LPROCFS_EXIT();
173         if (rc <= 0)
174                 goto out;
175
176         /* for lustre proc read, the read count must be less than PAGE_SIZE */
177         LASSERT(eof == 1);
178
179         if (start == NULL) {
180                 rc -= *ppos;
181                 if (rc < 0)
182                         rc = 0;
183                 if (rc == 0)
184                         goto out;
185                 start = page + *ppos;
186         } else if (start < page) {
187                 start = page;
188         }
189
190         count = (rc < size) ? rc : size;
191         if (copy_to_user(buf, start, count)) {
192                 rc = -EFAULT;
193                 goto out;
194         }
195         *ppos += count;
196
197 out:
198         free_page((unsigned long)page);
199         return rc;
200 }
201
202 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
203 {
204         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
205         int rc = -EIO;
206
207         LPROCFS_ENTRY();
208         if (!dp->deleted && dp->write_proc)
209                 rc = dp->write_proc(f, buf, size, dp->data);
210         LPROCFS_EXIT();
211         return rc;
212 }
213
214 static struct file_operations lprocfs_generic_fops = {
215         .owner = THIS_MODULE,
216         .read = lprocfs_fops_read,
217         .write = lprocfs_fops_write,
218 };
219
220 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
221 {
222         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
223         struct obd_device *obd = dp->data;
224
225         atomic_inc(&obd->obd_evict_inprogress);
226
227         return 0;
228 }
229
230 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
231 {
232         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
233         struct obd_device *obd = dp->data;
234
235         atomic_dec(&obd->obd_evict_inprogress);
236         wake_up(&obd->obd_evict_inprogress_waitq);
237
238         return 0;
239 }
240
241 struct file_operations lprocfs_evict_client_fops = {
242         .owner = THIS_MODULE,
243         .read = lprocfs_fops_read,
244         .write = lprocfs_fops_write,
245         .open = lprocfs_evict_client_open,
246         .release = lprocfs_evict_client_release,
247 };
248 EXPORT_SYMBOL(lprocfs_evict_client_fops);
249
250 /**
251  * Add /proc entrys.
252  *
253  * \param root [in]  The parent proc entry on which new entry will be added.
254  * \param list [in]  Array of proc entries to be added.
255  * \param data [in]  The argument to be passed when entries read/write routines
256  *                   are called through /proc file.
257  *
258  * \retval 0   on success
259  *         < 0 on error
260  */
261 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
262                      void *data)
263 {
264         if (root == NULL || list == NULL)
265                 return -EINVAL;
266
267         while (list->name != NULL) {
268                 struct proc_dir_entry *cur_root, *proc;
269                 char *pathcopy, *cur, *next, pathbuf[64];
270                 int pathsize = strlen(list->name) + 1;
271
272                 proc = NULL;
273                 cur_root = root;
274
275                 /* need copy of path for strsep */
276                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
277                         OBD_ALLOC(pathcopy, pathsize);
278                         if (pathcopy == NULL)
279                                 return -ENOMEM;
280                 } else {
281                         pathcopy = pathbuf;
282                 }
283
284                 next = pathcopy;
285                 strcpy(pathcopy, list->name);
286
287                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
288                         if (*cur =='\0') /* skip double/trailing "/" */
289                                 continue;
290
291                         proc = lprocfs_srch(cur_root, cur);
292                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
293                                cur_root->name, cur, next,
294                                (proc ? "exists" : "new"));
295                         if (next != NULL) {
296                                 cur_root = (proc ? proc :
297                                             proc_mkdir(cur, cur_root));
298                         } else if (proc == NULL) {
299                                 mode_t mode = 0;
300                                 if (list->proc_mode != 0000) {
301                                         mode = list->proc_mode;
302                                 } else {
303                                         if (list->read_fptr)
304                                                 mode = 0444;
305                                         if (list->write_fptr)
306                                                 mode |= 0200;
307                                 }
308                                 proc = create_proc_entry(cur, mode, cur_root);
309                         }
310                 }
311
312                 if (pathcopy != pathbuf)
313                         OBD_FREE(pathcopy, pathsize);
314
315                 if (cur_root == NULL || proc == NULL) {
316                         CERROR("LprocFS: No memory to create /proc entry %s",
317                                list->name);
318                         return -ENOMEM;
319                 }
320
321                 if (list->fops)
322                         proc->proc_fops = list->fops;
323                 else
324                         proc->proc_fops = &lprocfs_generic_fops;
325                 proc->read_proc = list->read_fptr;
326                 proc->write_proc = list->write_fptr;
327                 proc->data = (list->data ? list->data : data);
328                 list++;
329         }
330         return 0;
331 }
332
333 void lprocfs_remove(struct proc_dir_entry **rooth)
334 {
335         struct proc_dir_entry *root = *rooth;
336         struct proc_dir_entry *temp = root;
337         struct proc_dir_entry *rm_entry;
338         struct proc_dir_entry *parent;
339
340         if (!root)
341                 return;
342         *rooth = NULL;
343
344         parent = root->parent;
345         LASSERT(parent != NULL);
346         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
347
348         while (1) {
349                 while (temp->subdir != NULL)
350                         temp = temp->subdir;
351
352                 rm_entry = temp;
353                 temp = temp->parent;
354
355                 /* Memory corruption once caused this to fail, and
356                    without this LASSERT we would loop here forever. */
357                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
358                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
359                          rm_entry->name, (int)strlen(rm_entry->name));
360
361                 /* Now, the rm_entry->deleted flags is protected
362                  * by _lprocfs_lock. */
363                 rm_entry->data = NULL;
364                 remove_proc_entry(rm_entry->name, temp);
365                 if (temp == parent)
366                         break;
367         }
368         LPROCFS_WRITE_EXIT();
369 }
370
371 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
372 {
373         LASSERT(parent != NULL);
374         remove_proc_entry(name, parent);
375 }
376
377 struct proc_dir_entry *lprocfs_register(const char *name,
378                                         struct proc_dir_entry *parent,
379                                         struct lprocfs_vars *list, void *data)
380 {
381         struct proc_dir_entry *newchild;
382
383         newchild = lprocfs_srch(parent, name);
384         if (newchild != NULL) {
385                 CERROR(" Lproc: Attempting to register %s more than once \n",
386                        name);
387                 return ERR_PTR(-EALREADY);
388         }
389
390         newchild = proc_mkdir(name, parent);
391         if (newchild != NULL && list != NULL) {
392                 int rc = lprocfs_add_vars(newchild, list, data);
393                 if (rc) {
394                         lprocfs_remove(&newchild);
395                         return ERR_PTR(rc);
396                 }
397         }
398         return newchild;
399 }
400
401 /* Generic callbacks */
402 int lprocfs_rd_uint(char *page, char **start, off_t off,
403                     int count, int *eof, void *data)
404 {
405         unsigned int *temp = (unsigned int *)data;
406         return snprintf(page, count, "%u\n", *temp);
407 }
408
409 int lprocfs_wr_uint(struct file *file, const char *buffer,
410                     unsigned long count, void *data)
411 {
412         unsigned *p = data;
413         char dummy[MAX_STRING_SIZE + 1], *end;
414         unsigned long tmp;
415
416         dummy[MAX_STRING_SIZE] = '\0';
417         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
418                 return -EFAULT;
419
420         tmp = simple_strtoul(dummy, &end, 0);
421         if (dummy == end)
422                 return -EINVAL;
423
424         *p = (unsigned int)tmp;
425         return count;
426 }
427
428 int lprocfs_rd_u64(char *page, char **start, off_t off,
429                    int count, int *eof, void *data)
430 {
431         LASSERT(data != NULL);
432         *eof = 1;
433         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
434 }
435
436 int lprocfs_rd_atomic(char *page, char **start, off_t off,
437                    int count, int *eof, void *data)
438 {
439         atomic_t *atom = (atomic_t *)data;
440         LASSERT(atom != NULL);
441         *eof = 1;
442         return snprintf(page, count, "%d\n", atomic_read(atom));
443 }
444
445 int lprocfs_wr_atomic(struct file *file, const char *buffer,
446                       unsigned long count, void *data)
447 {
448         atomic_t *atm = data;
449         int val = 0;
450         int rc;
451
452         rc = lprocfs_write_helper(buffer, count, &val);
453         if (rc < 0)
454                 return rc;
455
456         if (val <= 0)
457                 return -ERANGE;
458
459         atomic_set(atm, val);
460         return count;
461 }
462
463 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
464                     int *eof, void *data)
465 {
466         struct obd_device *obd = (struct obd_device*)data;
467
468         LASSERT(obd != NULL);
469         *eof = 1;
470         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
471 }
472
473 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
474                     int *eof, void* data)
475 {
476         struct obd_device *dev = (struct obd_device *)data;
477
478         LASSERT(dev != NULL);
479         LASSERT(dev->obd_name != NULL);
480         *eof = 1;
481         return snprintf(page, count, "%s\n", dev->obd_name);
482 }
483
484 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
485                       void *data)
486 {
487         struct obd_device *obd = (struct obd_device *)data;
488
489         LASSERT(obd != NULL);
490         LASSERT(obd->obd_fsops != NULL);
491         LASSERT(obd->obd_fsops->fs_type != NULL);
492         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
493 }
494
495 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
496                        int *eof, void *data)
497 {
498         struct obd_statfs osfs;
499         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
500                             OBD_STATFS_NODELAY);
501         if (!rc) {
502                 *eof = 1;
503                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
504         }
505         return rc;
506 }
507
508 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
509                            int *eof, void *data)
510 {
511         struct obd_statfs osfs;
512         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
513                             OBD_STATFS_NODELAY);
514         if (!rc) {
515                 __u32 blk_size = osfs.os_bsize >> 10;
516                 __u64 result = osfs.os_blocks;
517
518                 while (blk_size >>= 1)
519                         result <<= 1;
520
521                 *eof = 1;
522                 rc = snprintf(page, count, LPU64"\n", result);
523         }
524         return rc;
525 }
526
527 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
528                           int *eof, void *data)
529 {
530         struct obd_statfs osfs;
531         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
532                             OBD_STATFS_NODELAY);
533         if (!rc) {
534                 __u32 blk_size = osfs.os_bsize >> 10;
535                 __u64 result = osfs.os_bfree;
536
537                 while (blk_size >>= 1)
538                         result <<= 1;
539
540                 *eof = 1;
541                 rc = snprintf(page, count, LPU64"\n", result);
542         }
543         return rc;
544 }
545
546 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
547                            int *eof, void *data)
548 {
549         struct obd_statfs osfs;
550         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
551                             OBD_STATFS_NODELAY);
552         if (!rc) {
553                 __u32 blk_size = osfs.os_bsize >> 10;
554                 __u64 result = osfs.os_bavail;
555
556                 while (blk_size >>= 1)
557                         result <<= 1;
558
559                 *eof = 1;
560                 rc = snprintf(page, count, LPU64"\n", result);
561         }
562         return rc;
563 }
564
565 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
566                           int *eof, void *data)
567 {
568         struct obd_statfs osfs;
569         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
570                             OBD_STATFS_NODELAY);
571         if (!rc) {
572                 *eof = 1;
573                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
574         }
575
576         return rc;
577 }
578
579 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
580                          int *eof, void *data)
581 {
582         struct obd_statfs osfs;
583         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
584                             OBD_STATFS_NODELAY);
585         if (!rc) {
586                 *eof = 1;
587                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
588         }
589         return rc;
590 }
591
592 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
593                            int *eof, void *data)
594 {
595         struct obd_device *obd = (struct obd_device *)data;
596         struct obd_import *imp;
597         char *imp_state_name = NULL;
598         int rc = 0;
599
600         LASSERT(obd != NULL);
601         LPROCFS_CLIMP_CHECK(obd);
602         imp = obd->u.cli.cl_import;
603         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
604         *eof = 1;
605         rc = snprintf(page, count, "%s\t%s%s\n",
606                       obd2cli_tgt(obd), imp_state_name,
607                       imp->imp_deactive ? "\tDEACTIVATED" : "");
608
609         LPROCFS_CLIMP_EXIT(obd);
610         return rc;
611 }
612
613 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
614                          int *eof,  void *data)
615 {
616         struct obd_device *obd = (struct obd_device*)data;
617         struct ptlrpc_connection *conn;
618         int rc = 0;
619
620         LASSERT(obd != NULL);
621
622         LPROCFS_CLIMP_CHECK(obd);
623         conn = obd->u.cli.cl_import->imp_connection;
624         LASSERT(conn != NULL);
625         *eof = 1;
626         if (obd->u.cli.cl_import) {
627                 rc = snprintf(page, count, "%s\n",
628                               conn->c_remote_uuid.uuid);
629         } else {
630                 rc = snprintf(page, count, "%s\n", "<none>");
631         }
632
633         LPROCFS_CLIMP_EXIT(obd);
634         return rc;
635 }
636
637 int lprocfs_at_hist_helper(char *page, int count, int rc,
638                            struct adaptive_timeout *at)
639 {
640         int i;
641         for (i = 0; i < AT_BINS; i++)
642                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
643         rc += snprintf(page + rc, count - rc, "\n");
644         return rc;
645 }
646
647 /* See also ptlrpc_lprocfs_rd_timeouts */
648 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
649                         int *eof, void *data)
650 {
651         struct obd_device *obd = (struct obd_device *)data;
652         struct obd_import *imp;
653         unsigned int cur, worst;
654         time_t now, worstt;
655         struct dhms ts;
656         int i, rc = 0;
657
658         LASSERT(obd != NULL);
659         LPROCFS_CLIMP_CHECK(obd);
660         imp = obd->u.cli.cl_import;
661         *eof = 1;
662
663         now = cfs_time_current_sec();
664
665         /* Some network health info for kicks */
666         s2dhms(&ts, now - imp->imp_last_reply_time);
667         rc += snprintf(page + rc, count - rc,
668                        "%-10s : %ld, "DHMS_FMT" ago\n",
669                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
670
671
672         cur = at_get(&imp->imp_at.iat_net_latency);
673         worst = imp->imp_at.iat_net_latency.at_worst_ever;
674         worstt = imp->imp_at.iat_net_latency.at_worst_time;
675         s2dhms(&ts, now - worstt);
676         rc += snprintf(page + rc, count - rc,
677                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
678                        "network", cur, worst, worstt, DHMS_VARS(&ts));
679         rc = lprocfs_at_hist_helper(page, count, rc,
680                                     &imp->imp_at.iat_net_latency);
681
682         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
683                 if (imp->imp_at.iat_portal[i] == 0)
684                         break;
685                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
686                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
687                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
688                 s2dhms(&ts, now - worstt);
689                 rc += snprintf(page + rc, count - rc,
690                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
691                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
692                                cur, worst, worstt, DHMS_VARS(&ts));
693                 rc = lprocfs_at_hist_helper(page, count, rc,
694                                           &imp->imp_at.iat_service_estimate[i]);
695         }
696
697         LPROCFS_CLIMP_EXIT(obd);
698         return rc;
699 }
700
701 static const char *obd_connect_names[] = {
702         "read_only",
703         "lov_index",
704         "unused",
705         "write_grant",
706         "server_lock",
707         "version",
708         "request_portal",
709         "acl",
710         "xattr",
711         "create_on_write",
712         "truncate_lock",
713         "initial_transno",
714         "inode_bit_locks",
715         "join_file",
716         "getattr_by_fid",
717         "no_oh_for_devices",
718         "local_client",
719         "remote_client",
720         "max_byte_per_rpc",
721         "64bit_qdata",
722         "mds_capability",
723         "oss_capability",
724         "early_lock_cancel",
725         "size_on_mds",
726         "adaptive_timeouts",
727         "lru_resize",
728         "mds_mds_connection",
729         "real_conn",
730         "change_qunit_size",
731         "alt_checksum_algorithm",
732         "fid_is_enabled",
733         NULL
734 };
735
736 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
737                              int count, int *eof, void *data)
738 {
739         struct obd_device *obd = data;
740         __u64 mask = 1, flags;
741         int i, ret = 0;
742
743         LPROCFS_CLIMP_CHECK(obd);
744         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
745         ret = snprintf(page, count, "flags="LPX64"\n", flags);
746         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
747                 if (flags & mask)
748                         ret += snprintf(page + ret, count - ret, "%s\n",
749                                         obd_connect_names[i]);
750         }
751         if (flags & ~(mask - 1))
752                 ret += snprintf(page + ret, count - ret,
753                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
754
755         LPROCFS_CLIMP_EXIT(obd);
756         return ret;
757 }
758 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
759
760 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
761                            int *eof,  void *data)
762 {
763         struct obd_device *obd = (struct obd_device*)data;
764
765         LASSERT(obd != NULL);
766         *eof = 1;
767         return snprintf(page, count, "%u\n", obd->obd_num_exports);
768 }
769
770 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
771                        int *eof, void *data)
772 {
773         struct obd_type *class = (struct obd_type*) data;
774
775         LASSERT(class != NULL);
776         *eof = 1;
777         return snprintf(page, count, "%d\n", class->typ_refcnt);
778 }
779
780 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
781 {
782         int rc = 0;
783
784         LASSERT(obd != NULL);
785         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
786         LASSERT(obd->obd_type->typ_procroot != NULL);
787
788         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
789                                                obd->obd_type->typ_procroot,
790                                                list, obd);
791         if (IS_ERR(obd->obd_proc_entry)) {
792                 rc = PTR_ERR(obd->obd_proc_entry);
793                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
794                 obd->obd_proc_entry = NULL;
795         }
796         return rc;
797 }
798
799 int lprocfs_obd_cleanup(struct obd_device *obd)
800 {
801         if (!obd)
802                 return -EINVAL;
803         if (obd->obd_proc_exports_entry) {
804                 /* Should be no exports left */
805                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
806                 lprocfs_remove(&obd->obd_proc_exports_entry);
807         }
808         lprocfs_remove(&obd->obd_proc_entry);
809         return 0;
810 }
811
812 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
813 {
814         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
815                client_stat->nid_proc, client_stat->nid_stats,
816                client_stat->nid_brw_stats);
817
818         LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
819                  client_stat->nid_exp_ref_count);
820
821         hlist_del_init(&client_stat->nid_hash);
822
823         if (client_stat->nid_proc)
824                 lprocfs_remove(&client_stat->nid_proc);
825
826         if (client_stat->nid_stats)
827                 lprocfs_free_stats(&client_stat->nid_stats);
828
829         if (client_stat->nid_brw_stats)
830                 OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
831
832         OBD_FREE(client_stat, sizeof(*client_stat));
833         return;
834
835 }
836
837 void lprocfs_free_per_client_stats(struct obd_device *obd)
838 {
839         struct nid_stat *stat;
840         ENTRY;
841
842         /* we need extra list - because hash_exit called to early */
843         /* not need locking because all clients is died */
844         while(!list_empty(&obd->obd_nid_stats)) {
845                 stat = list_entry(obd->obd_nid_stats.next,
846                                   struct nid_stat, nid_list);
847                 list_del_init(&stat->nid_list);
848                 lprocfs_free_client_stats(stat);
849         }
850
851         EXIT;
852 }
853
854 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
855                                           enum lprocfs_stats_flags flags)
856 {
857         struct lprocfs_stats *stats;
858         unsigned int percpusize;
859         unsigned int i, j;
860         unsigned int num_cpu;
861
862         if (num == 0)
863                 return NULL;
864
865         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
866                 num_cpu = 1;
867         else
868                 num_cpu = num_possible_cpus();
869
870         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
871         if (stats == NULL)
872                 return NULL;
873
874         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
875                 stats->ls_flags = flags;
876                 spin_lock_init(&stats->ls_lock);
877                 /* Use this lock only if there are no percpu areas */
878         } else {
879                 stats->ls_flags = 0;
880         }
881
882         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
883         if (num_cpu > 1)
884                 percpusize = L1_CACHE_ALIGN(percpusize);
885
886         for (i = 0; i < num_cpu; i++) {
887                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
888                 if (stats->ls_percpu[i] == NULL) {
889                         for (j = 0; j < i; j++) {
890                                 OBD_FREE(stats->ls_percpu[j], percpusize);
891                                 stats->ls_percpu[j] = NULL;
892                         }
893                         break;
894                 }
895         }
896         if (stats->ls_percpu[0] == NULL) {
897                 OBD_FREE(stats, offsetof(typeof(*stats),
898                                          ls_percpu[num_cpu]));
899                 return NULL;
900         }
901
902         stats->ls_num = num;
903         return stats;
904 }
905
906 void lprocfs_free_stats(struct lprocfs_stats **statsh)
907 {
908         struct lprocfs_stats *stats = *statsh;
909         unsigned int num_cpu;
910         unsigned int percpusize;
911         unsigned int i;
912
913         if (stats == NULL || stats->ls_num == 0)
914                 return;
915         *statsh = NULL;
916
917         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
918                 num_cpu = 1;
919         else
920                 num_cpu = num_possible_cpus();
921
922         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
923         if (num_cpu > 1)
924                 percpusize = L1_CACHE_ALIGN(percpusize);
925         for (i = 0; i < num_cpu; i++)
926                 OBD_FREE(stats->ls_percpu[i], percpusize);
927         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
928 }
929
930 void lprocfs_clear_stats(struct lprocfs_stats *stats)
931 {
932         struct lprocfs_counter *percpu_cntr;
933         int i,j;
934         unsigned int num_cpu;
935
936         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
937
938         for (i = 0; i < num_cpu; i++) {
939                 for (j = 0; j < stats->ls_num; j++) {
940                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
941                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
942                         percpu_cntr->lc_count = 0;
943                         percpu_cntr->lc_sum = 0;
944                         percpu_cntr->lc_min = LC_MIN_INIT;
945                         percpu_cntr->lc_max = 0;
946                         percpu_cntr->lc_sumsquare = 0;
947                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
948                 }
949         }
950
951         lprocfs_stats_unlock(stats);
952 }
953
954 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
955                                        size_t len, loff_t *off)
956 {
957         struct seq_file *seq = file->private_data;
958         struct lprocfs_stats *stats = seq->private;
959
960         lprocfs_clear_stats(stats);
961
962         return len;
963 }
964
965 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
966 {
967         struct lprocfs_stats *stats = p->private;
968         /* return 1st cpu location */
969         return (*pos >= stats->ls_num) ? NULL :
970                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
971 }
972
973 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
974 {
975 }
976
977 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
978 {
979         struct lprocfs_stats *stats = p->private;
980         ++*pos;
981         return (*pos >= stats->ls_num) ? NULL :
982                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
983 }
984
985 /* seq file export of one lprocfs counter */
986 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
987 {
988        struct lprocfs_stats *stats = p->private;
989        struct lprocfs_counter  *cntr = v;
990        struct lprocfs_counter  t, ret = { .lc_min = LC_MIN_INIT };
991        int i, idx, rc;
992        unsigned int num_cpu;
993
994        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
995                struct timeval now;
996                do_gettimeofday(&now);
997                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
998                                "snapshot_time", now.tv_sec, now.tv_usec);
999                if (rc < 0)
1000                        return rc;
1001        }
1002        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1003
1004        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1005                num_cpu = 1;
1006        else
1007                num_cpu = num_possible_cpus();
1008
1009        for (i = 0; i < num_cpu; i++) {
1010                struct lprocfs_counter *percpu_cntr =
1011                        &(stats->ls_percpu[i])->lp_cntr[idx];
1012                int centry;
1013
1014                do {
1015                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1016                        t.lc_count = percpu_cntr->lc_count;
1017                        t.lc_sum = percpu_cntr->lc_sum;
1018                        t.lc_min = percpu_cntr->lc_min;
1019                        t.lc_max = percpu_cntr->lc_max;
1020                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1021                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1022                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1023                ret.lc_count += t.lc_count;
1024                ret.lc_sum += t.lc_sum;
1025                if (t.lc_min < ret.lc_min)
1026                        ret.lc_min = t.lc_min;
1027                if (t.lc_max > ret.lc_max)
1028                        ret.lc_max = t.lc_max;
1029                ret.lc_sumsquare += t.lc_sumsquare;
1030        }
1031
1032        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1033                        ret.lc_count, cntr->lc_units);
1034        if (rc < 0)
1035                goto out;
1036
1037        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1038                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1039                                ret.lc_min, ret.lc_max, ret.lc_sum);
1040                if (rc < 0)
1041                        goto out;
1042                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1043                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1044                if (rc < 0)
1045                        goto out;
1046        }
1047        rc = seq_printf(p, "\n");
1048  out:
1049        return (rc < 0) ? rc : 0;
1050 }
1051
1052 struct seq_operations lprocfs_stats_seq_sops = {
1053         start: lprocfs_stats_seq_start,
1054         stop:  lprocfs_stats_seq_stop,
1055         next:  lprocfs_stats_seq_next,
1056         show:  lprocfs_stats_seq_show,
1057 };
1058
1059 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1060 {
1061         struct proc_dir_entry *dp = PDE(inode);
1062         struct seq_file *seq;
1063         int rc;
1064
1065         LPROCFS_ENTRY_AND_CHECK(dp);
1066         rc = seq_open(file, &lprocfs_stats_seq_sops);
1067         if (rc) {
1068                 LPROCFS_EXIT();
1069                 return rc;
1070         }
1071         seq = file->private_data;
1072         seq->private = dp->data;
1073         return 0;
1074 }
1075
1076 struct file_operations lprocfs_stats_seq_fops = {
1077         .owner   = THIS_MODULE,
1078         .open    = lprocfs_stats_seq_open,
1079         .read    = seq_read,
1080         .write   = lprocfs_stats_seq_write,
1081         .llseek  = seq_lseek,
1082         .release = lprocfs_seq_release,
1083 };
1084
1085 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1086                            struct lprocfs_stats *stats)
1087 {
1088         struct proc_dir_entry *entry;
1089         LASSERT(root != NULL);
1090
1091         entry = create_proc_entry(name, 0644, root);
1092         if (entry == NULL)
1093                 return -ENOMEM;
1094         entry->proc_fops = &lprocfs_stats_seq_fops;
1095         entry->data = (void *)stats;
1096         return 0;
1097 }
1098
1099 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1100                           unsigned conf, const char *name, const char *units)
1101 {
1102         struct lprocfs_counter *c;
1103         int i;
1104         unsigned int num_cpu;
1105
1106         LASSERT(stats != NULL);
1107
1108         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1109
1110         for (i = 0; i < num_cpu; i++) {
1111                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1112                 c->lc_config = conf;
1113                 c->lc_count = 0;
1114                 c->lc_sum = 0;
1115                 c->lc_min = LC_MIN_INIT;
1116                 c->lc_max = 0;
1117                 c->lc_name = name;
1118                 c->lc_units = units;
1119         }
1120
1121         lprocfs_stats_unlock(stats);
1122 }
1123 EXPORT_SYMBOL(lprocfs_counter_init);
1124
1125 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1126 do {                                                                       \
1127         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1128         LASSERT(coffset < stats->ls_num);                                  \
1129         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1130 } while (0)
1131
1132 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1133 {
1134         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1135         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1136         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1137         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1138         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1139         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1140         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1141         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1142         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1143         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1144         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1145         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1146         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1147         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1148         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1149         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1150         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1151         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1152         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1153         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1154         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1155         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1156         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1157         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1158         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1159         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1160         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1161         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1162         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1163         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1164         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1165         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1166         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1167         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1168         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1169         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1170         LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1171         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1172         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1173         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1174         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1175         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1176         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1177         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1178         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1179         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1180         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1181         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1182         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1183         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1184         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1185         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1186         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1187         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1188         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1189         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1190         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1191         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1192         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1193         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1194         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1195         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1196         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1197         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1198         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1199         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1200         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1201         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1202         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1203         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1204         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1205         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1206         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1207         LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1208         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1209         LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1210 }
1211
1212 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1213 {
1214         struct lprocfs_stats *stats;
1215         unsigned int num_stats;
1216         int rc, i;
1217
1218         LASSERT(obd->obd_stats == NULL);
1219         LASSERT(obd->obd_proc_entry != NULL);
1220         LASSERT(obd->obd_cntr_base == 0);
1221
1222         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1223                 num_private_stats - 1 /* o_owner */;
1224         stats = lprocfs_alloc_stats(num_stats, 0);
1225         if (stats == NULL)
1226                 return -ENOMEM;
1227
1228         lprocfs_init_ops_stats(num_private_stats, stats);
1229
1230         for (i = num_private_stats; i < num_stats; i++) {
1231                 /* If this LBUGs, it is likely that an obd
1232                  * operation was added to struct obd_ops in
1233                  * <obd.h>, and that the corresponding line item
1234                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1235                  * is missing from the list above. */
1236                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1237                          "Missing obd_stat initializer obd_op "
1238                          "operation at offset %d.\n", i - num_private_stats);
1239         }
1240         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1241         if (rc < 0) {
1242                 lprocfs_free_stats(&stats);
1243         } else {
1244                 obd->obd_stats  = stats;
1245                 obd->obd_cntr_base = num_private_stats;
1246         }
1247         return rc;
1248 }
1249
1250 void lprocfs_free_obd_stats(struct obd_device *obd)
1251 {
1252         if (obd->obd_stats)
1253                 lprocfs_free_stats(&obd->obd_stats);
1254 }
1255
1256 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1257 do {                                                                    \
1258         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1259         LASSERT(coffset < stats->ls_num);                               \
1260         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1261 } while (0)
1262
1263 int lprocfs_alloc_md_stats(struct obd_device *obd,
1264                            unsigned num_private_stats)
1265 {
1266         struct lprocfs_stats *stats;
1267         unsigned int num_stats;
1268         int rc, i;
1269
1270         LASSERT(obd->md_stats == NULL);
1271         LASSERT(obd->obd_proc_entry != NULL);
1272         LASSERT(obd->md_cntr_base == 0);
1273
1274         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1275                     num_private_stats;
1276         stats = lprocfs_alloc_stats(num_stats, 0);
1277         if (stats == NULL)
1278                 return -ENOMEM;
1279
1280         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1281         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1282         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1283         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1284         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1285         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1286         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1287         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1288         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1289         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1290         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1291         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1292         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1293         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1294         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1295         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1296         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1297         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1298         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1299         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1300         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1301         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1302         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1303         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1304         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1305         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1306         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1307         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1308         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1309         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1310
1311         for (i = num_private_stats; i < num_stats; i++) {
1312                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1313                         CERROR("Missing md_stat initializer md_op "
1314                                "operation at offset %d. Aborting.\n",
1315                                i - num_private_stats);
1316                         LBUG();
1317                 }
1318         }
1319         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1320         if (rc < 0) {
1321                 lprocfs_free_stats(&stats);
1322         } else {
1323                 obd->md_stats  = stats;
1324                 obd->md_cntr_base = num_private_stats;
1325         }
1326         return rc;
1327 }
1328
1329 void lprocfs_free_md_stats(struct obd_device *obd)
1330 {
1331         struct lprocfs_stats *stats = obd->md_stats;
1332
1333         if (stats != NULL) {
1334                 obd->md_stats = NULL;
1335                 lprocfs_free_stats(&stats);
1336         }
1337 }
1338
1339 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1340                          int *eof,  void *data)
1341 {
1342         struct obd_export *exp = (struct obd_export*)data;
1343         LASSERT(exp != NULL);
1344         *eof = 1;
1345         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1346 }
1347
1348 struct exp_uuid_cb_data {
1349         char                   *page;
1350         int                     count;
1351         int                    *eof;
1352         int                    *len;
1353 };
1354
1355 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1356 {
1357         struct obd_export *exp = (struct obd_export *)obj;
1358         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1359
1360         if (exp->exp_nid_stats)
1361                 *data->len += snprintf((data->page + *data->len),
1362                                        data->count, "%s\n",
1363                                        obd_uuid2str(&exp->exp_client_uuid));
1364 }
1365
1366 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1367                         int *eof,  void *data)
1368 {
1369         struct nid_stat *stats = (struct nid_stat *)data;
1370         struct exp_uuid_cb_data cb_data;
1371         struct obd_device *obd = stats->nid_obd;
1372         int len = 0;
1373
1374         *eof = 1;
1375         page[0] = '\0';
1376         LASSERT(obd != NULL);
1377
1378         cb_data.page = page;
1379         cb_data.count = count;
1380         cb_data.eof = eof;
1381         cb_data.len = &len;
1382         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1383                                  lprocfs_exp_print_uuid, &cb_data);
1384         return (*cb_data.len);
1385 }
1386
1387 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1388                                         int count, int *eof,  void *data)
1389 {
1390         *eof = 1;
1391         return snprintf(page, count, "%s\n",
1392                         "Write into this file to clear all nid stats and "
1393                         "stale nid entries");
1394 }
1395 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1396
1397 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1398 {
1399         struct nid_stat *stat = obj;
1400         int i;
1401
1402         /* object has only hash + iterate_all references.
1403          * add/delete blocked by hash bucket lock */
1404         CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1405         if(stat->nid_exp_ref_count == 2) {
1406                 hlist_del_init(&stat->nid_hash);
1407                 stat->nid_exp_ref_count--;
1408                 spin_lock(&stat->nid_obd->obd_nid_lock);
1409                 list_del_init(&stat->nid_list);
1410                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1411                 list_add(&stat->nid_list, data);
1412                 EXIT;
1413                 return;
1414         }
1415         /* we has reference to object - only clear data*/
1416         if (stat->nid_stats)
1417                 lprocfs_clear_stats(stat->nid_stats);
1418
1419         if (stat->nid_brw_stats) {
1420                 for (i = 0; i < BRW_LAST; i++)
1421                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1422         }
1423         EXIT;
1424         return;
1425 }
1426
1427 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1428                                          unsigned long count, void *data)
1429 {
1430         struct obd_device *obd = (struct obd_device *)data;
1431         struct nid_stat *client_stat;
1432         CFS_LIST_HEAD(free_list);
1433
1434         lustre_hash_for_each(obd->obd_nid_stats_hash,
1435                              lprocfs_nid_stats_clear_write_cb, &free_list);
1436
1437         while (!list_empty(&free_list)) {
1438                 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1439                 list_del_init(&client_stat->nid_list);
1440                 lprocfs_free_client_stats(client_stat);
1441         }
1442
1443         return count;
1444 }
1445 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1446
1447 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1448 {
1449         int rc = 0;
1450         struct nid_stat *tmp = NULL, *tmp1;
1451         struct obd_device *obd = NULL;
1452         ENTRY;
1453
1454         *newnid = 0;
1455
1456         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1457             !exp->exp_obd->obd_nid_stats_hash)
1458                 RETURN(-EINVAL);
1459
1460         /* not test against zero because eric say:
1461          * You may only test nid against another nid, or LNET_NID_ANY.  Anything else is
1462          * nonsense.*/
1463         if (!nid || *nid == LNET_NID_ANY)
1464                 RETURN(0);
1465
1466         obd = exp->exp_obd;
1467
1468         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1469
1470         OBD_ALLOC(tmp, sizeof(struct nid_stat));
1471         if (tmp == NULL)
1472                 RETURN(-ENOMEM);
1473
1474         tmp->nid = *nid;
1475         tmp->nid_obd = exp->exp_obd;
1476         tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
1477
1478        /* protect competitive add to list, not need locking on destroy */
1479         spin_lock(&obd->obd_nid_lock);
1480         list_add(&tmp->nid_list, &obd->obd_nid_stats);
1481         spin_unlock(&obd->obd_nid_lock);
1482
1483         tmp1 = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1484                                           nid, &tmp->nid_hash);
1485         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1486                tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
1487
1488         if (tmp1 != tmp) {
1489                 exp->exp_nid_stats = tmp1;
1490                 GOTO(destroy_new, rc = 0);
1491         }
1492         /* not found - create */
1493         tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1494                                          obd->obd_proc_exports_entry, NULL, NULL);
1495         if (!tmp->nid_proc) {
1496                 CERROR("Error making export directory for"
1497                        " nid %s\n", libcfs_nid2str(*nid));
1498                 lustre_hash_del(obd->obd_nid_stats_hash, nid, &tmp->nid_hash);
1499                 GOTO(destroy_new, rc = -ENOMEM);
1500         }
1501
1502         rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1503                                 lprocfs_exp_rd_uuid, NULL, tmp);
1504         if (rc)
1505                 CWARN("Error adding the uuid file\n");
1506
1507         exp->exp_nid_stats = tmp;
1508         *newnid = 1;
1509         RETURN(rc);
1510
1511 destroy_new:
1512         spin_lock(&obd->obd_nid_lock);
1513         list_del(&tmp->nid_list);
1514         spin_unlock(&obd->obd_nid_lock);
1515         OBD_FREE(tmp, sizeof(struct nid_stat));
1516         RETURN(rc);
1517 }
1518
1519 int lprocfs_exp_cleanup(struct obd_export *exp)
1520 {
1521         struct nid_stat *stat = exp->exp_nid_stats;
1522
1523         if(!stat)
1524                 RETURN(0);
1525
1526         stat->nid_exp_ref_count--;
1527         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1528
1529         exp->exp_nid_stats = NULL;
1530         return 0;
1531 }
1532
1533 int lprocfs_write_helper(const char *buffer, unsigned long count,
1534                          int *val)
1535 {
1536         return lprocfs_write_frac_helper(buffer, count, val, 1);
1537 }
1538
1539 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1540                               int *val, int mult)
1541 {
1542         char kernbuf[20], *end, *pbuf;
1543
1544         if (count > (sizeof(kernbuf) - 1))
1545                 return -EINVAL;
1546
1547         if (copy_from_user(kernbuf, buffer, count))
1548                 return -EFAULT;
1549
1550         kernbuf[count] = '\0';
1551         pbuf = kernbuf;
1552         if (*pbuf == '-') {
1553                 mult = -mult;
1554                 pbuf++;
1555         }
1556
1557         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1558         if (pbuf == end)
1559                 return -EINVAL;
1560
1561         if (end != NULL && *end == '.') {
1562                 int temp_val, pow = 1;
1563                 int i;
1564
1565                 pbuf = end + 1;
1566                 if (strlen(pbuf) > 5)
1567                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1568
1569                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1570
1571                 if (pbuf < end) {
1572                         for (i = 0; i < (end - pbuf); i++)
1573                                 pow *= 10;
1574
1575                         *val += temp_val / pow;
1576                 }
1577         }
1578         return 0;
1579 }
1580
1581 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1582 {
1583         long decimal_val, frac_val;
1584         int prtn;
1585
1586         if (count < 10)
1587                 return -EINVAL;
1588
1589         decimal_val = val / mult;
1590         prtn = snprintf(buffer, count, "%ld", decimal_val);
1591         frac_val = val % mult;
1592
1593         if (prtn < (count - 4) && frac_val > 0) {
1594                 long temp_frac;
1595                 int i, temp_mult = 1, frac_bits = 0;
1596
1597                 temp_frac = frac_val * 10;
1598                 buffer[prtn++] = '.';
1599                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1600                         buffer[prtn++] ='0';
1601                         temp_frac *= 10;
1602                         frac_bits++;
1603                 }
1604                 /*
1605                   Need to think these cases :
1606                         1. #echo x.00 > /proc/xxx       output result : x
1607                         2. #echo x.0x > /proc/xxx       output result : x.0x
1608                         3. #echo x.x0 > /proc/xxx       output result : x.x
1609                         4. #echo x.xx > /proc/xxx       output result : x.xx
1610                         Only reserved 2bits fraction.
1611                  */
1612                 for (i = 0; i < (5 - prtn); i++)
1613                         temp_mult *= 10;
1614
1615                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1616                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1617
1618                 prtn--;
1619                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1620                         prtn--;
1621                         if (buffer[prtn] == '.') {
1622                                 prtn--;
1623                                 break;
1624                         }
1625                 }
1626                 prtn++;
1627         }
1628         buffer[prtn++] ='\n';
1629         return prtn;
1630 }
1631
1632 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1633 {
1634         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1635 }
1636
1637 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1638                               __u64 *val, int mult)
1639 {
1640         char kernbuf[22], *end, *pbuf;
1641         __u64 whole, frac = 0, units;
1642         unsigned frac_d = 1;
1643
1644         if (count > (sizeof(kernbuf) - 1) )
1645                 return -EINVAL;
1646
1647         if (copy_from_user(kernbuf, buffer, count))
1648                 return -EFAULT;
1649
1650         kernbuf[count] = '\0';
1651         pbuf = kernbuf;
1652         if (*pbuf == '-') {
1653                 mult = -mult;
1654                 pbuf++;
1655         }
1656
1657         whole = simple_strtoull(pbuf, &end, 10);
1658         if (pbuf == end)
1659                 return -EINVAL;
1660
1661         if (end != NULL && *end == '.') {
1662                 int i;
1663                 pbuf = end + 1;
1664
1665                 /* need to limit frac_d to a __u32 */
1666                 if (strlen(pbuf) > 10)
1667                         pbuf[10] = '\0';
1668
1669                 frac = simple_strtoull(pbuf, &end, 10);
1670                 /* count decimal places */
1671                 for (i = 0; i < (end - pbuf); i++)
1672                         frac_d *= 10;
1673         }
1674
1675         units = 1;
1676         switch(*end) {
1677         case 'p': case 'P':
1678                 units <<= 10;
1679         case 't': case 'T':
1680                 units <<= 10;
1681         case 'g': case 'G':
1682                 units <<= 10;
1683         case 'm': case 'M':
1684                 units <<= 10;
1685         case 'k': case 'K':
1686                 units <<= 10;
1687         }
1688         /* Specified units override the multiplier */
1689         if (units)
1690                 mult = mult < 0 ? -units : units;
1691
1692         frac *= mult;
1693         do_div(frac, frac_d);
1694         *val = whole * mult + frac;
1695         return 0;
1696 }
1697
1698 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1699                        char *name, mode_t mode,
1700                        struct file_operations *seq_fops, void *data)
1701 {
1702         struct proc_dir_entry *entry;
1703         ENTRY;
1704
1705         entry = create_proc_entry(name, mode, parent);
1706         if (entry == NULL)
1707                 RETURN(-ENOMEM);
1708         entry->proc_fops = seq_fops;
1709         entry->data = data;
1710
1711         RETURN(0);
1712 }
1713 EXPORT_SYMBOL(lprocfs_seq_create);
1714
1715 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1716                                       mode_t mode,
1717                                       struct file_operations *seq_fops,
1718                                       void *data)
1719 {
1720         return (lprocfs_seq_create(dev->obd_proc_entry, name,
1721                                    mode, seq_fops, data));
1722 }
1723 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1724
1725 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1726 {
1727         if (value >= OBD_HIST_MAX)
1728                 value = OBD_HIST_MAX - 1;
1729
1730         spin_lock(&oh->oh_lock);
1731         oh->oh_buckets[value]++;
1732         spin_unlock(&oh->oh_lock);
1733 }
1734 EXPORT_SYMBOL(lprocfs_oh_tally);
1735
1736 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1737 {
1738         unsigned int val;
1739
1740         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1741                 ;
1742
1743         lprocfs_oh_tally(oh, val);
1744 }
1745 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1746
1747 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1748 {
1749         unsigned long ret = 0;
1750         int i;
1751
1752         for (i = 0; i < OBD_HIST_MAX; i++)
1753                 ret +=  oh->oh_buckets[i];
1754         return ret;
1755 }
1756 EXPORT_SYMBOL(lprocfs_oh_sum);
1757
1758 void lprocfs_oh_clear(struct obd_histogram *oh)
1759 {
1760         spin_lock(&oh->oh_lock);
1761         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1762         spin_unlock(&oh->oh_lock);
1763 }
1764 EXPORT_SYMBOL(lprocfs_oh_clear);
1765
1766 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1767                         int count, int *eof, void *data)
1768 {
1769         struct obd_device *obd = data;
1770         int c = 0;
1771
1772         if (obd == NULL)
1773                 return 0;
1774
1775         c += lustre_hash_debug_header(page, count);
1776         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
1777         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
1778         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
1779
1780         return c;
1781 }
1782 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
1783
1784 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1785                                    int count, int *eof, void *data)
1786 {
1787         struct obd_device *obd = data;
1788         int len = 0, size;
1789
1790         LASSERT(obd != NULL);
1791         LASSERT(count >= 0);
1792
1793         /* Set start of user data returned to
1794            page + off since the user may have
1795            requested to read much smaller than
1796            what we need to read */
1797         *start = page + off;
1798
1799         /* We know we are allocated a page here.
1800            Also we know that this function will
1801            not need to write more than a page
1802            so we can truncate at CFS_PAGE_SIZE.  */
1803         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1804
1805         /* Initialize the page */
1806         memset(page, 0, size);
1807
1808         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1809                 goto out;
1810         if (obd->obd_max_recoverable_clients == 0) {
1811                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1812                         goto out;
1813
1814                 goto fclose;
1815         }
1816
1817         /* sampled unlocked, but really... */
1818         if (obd->obd_recovering == 0) {
1819                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1820                         goto out;
1821                 if (lprocfs_obd_snprintf(&page, size, &len,
1822                                          "recovery_start: %lu\n",
1823                                          obd->obd_recovery_start) <= 0)
1824                         goto out;
1825                 if (lprocfs_obd_snprintf(&page, size, &len,
1826                                          "recovery_duration: %lu\n",
1827                                          obd->obd_recovery_end -
1828                                          obd->obd_recovery_start) <= 0)
1829                         goto out;
1830                 /* Number of clients that have completed recovery */
1831                 if (lprocfs_obd_snprintf(&page, size, &len,
1832                                          "completed_clients: %d/%d\n",
1833                                          obd->obd_max_recoverable_clients -
1834                                          obd->obd_recoverable_clients,
1835                                          obd->obd_max_recoverable_clients) <= 0)
1836                         goto out;
1837                 if (lprocfs_obd_snprintf(&page, size, &len,
1838                                          "replayed_requests: %d\n",
1839                                          obd->obd_replayed_requests) <= 0)
1840                         goto out;
1841                 if (lprocfs_obd_snprintf(&page, size, &len,
1842                                          "last_transno: "LPD64"\n",
1843                                          obd->obd_next_recovery_transno - 1)<=0)
1844                         goto out;
1845                 goto fclose;
1846         }
1847
1848         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1849                 goto out;
1850         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1851                                  obd->obd_recovery_start) <= 0)
1852                 goto out;
1853         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1854                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1855                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1856                 goto out;
1857         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1858                                  obd->obd_connected_clients,
1859                                  obd->obd_max_recoverable_clients) <= 0)
1860                 goto out;
1861         /* Number of clients that have completed recovery */
1862         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1863                                  obd->obd_max_recoverable_clients -
1864                                  obd->obd_recoverable_clients,
1865                                  obd->obd_max_recoverable_clients) <= 0)
1866                 goto out;
1867         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1868                                  obd->obd_replayed_requests) <= 0)
1869                 goto out;
1870         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1871                                  obd->obd_requests_queued_for_recovery) <= 0)
1872                 goto out;
1873
1874         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1875                                  obd->obd_next_recovery_transno) <= 0)
1876                 goto out;
1877
1878 fclose:
1879         *eof = 1;
1880 out:
1881         return min(count, len - (int)off);
1882 }
1883 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1884
1885 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1886                                     int count, int *eof, void *data)
1887 {
1888         struct obd_device *obd = (struct obd_device *)data;
1889         LASSERT(obd != NULL);
1890
1891         return snprintf(page, count, "%lu\n",
1892                         obd->obd_recovery_max_time);
1893 }
1894 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1895
1896 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1897                                     unsigned long count, void *data)
1898 {
1899         struct obd_device *obd = (struct obd_device *)data;
1900         int val, rc;
1901         LASSERT(obd != NULL);
1902
1903         rc = lprocfs_write_helper(buffer, count, &val);
1904         if (rc)
1905                 return rc;
1906
1907         obd->obd_recovery_max_time = val;
1908         return count;
1909 }
1910 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1911
1912 EXPORT_SYMBOL(lprocfs_register);
1913 EXPORT_SYMBOL(lprocfs_srch);
1914 EXPORT_SYMBOL(lprocfs_remove);
1915 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1916 EXPORT_SYMBOL(lprocfs_add_vars);
1917 EXPORT_SYMBOL(lprocfs_obd_setup);
1918 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1919 EXPORT_SYMBOL(lprocfs_add_simple);
1920 EXPORT_SYMBOL(lprocfs_add_symlink);
1921 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1922 EXPORT_SYMBOL(lprocfs_alloc_stats);
1923 EXPORT_SYMBOL(lprocfs_free_stats);
1924 EXPORT_SYMBOL(lprocfs_clear_stats);
1925 EXPORT_SYMBOL(lprocfs_register_stats);
1926 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1927 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1928 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1929 EXPORT_SYMBOL(lprocfs_exp_setup);
1930 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1931
1932 EXPORT_SYMBOL(lprocfs_rd_u64);
1933 EXPORT_SYMBOL(lprocfs_rd_atomic);
1934 EXPORT_SYMBOL(lprocfs_wr_atomic);
1935 EXPORT_SYMBOL(lprocfs_rd_uint);
1936 EXPORT_SYMBOL(lprocfs_wr_uint);
1937 EXPORT_SYMBOL(lprocfs_rd_uuid);
1938 EXPORT_SYMBOL(lprocfs_rd_name);
1939 EXPORT_SYMBOL(lprocfs_rd_fstype);
1940 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1941 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1942 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1943 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1944 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1945 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1946 EXPORT_SYMBOL(lprocfs_rd_blksize);
1947 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1948 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1949 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1950 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1951 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1952
1953 EXPORT_SYMBOL(lprocfs_write_helper);
1954 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1955 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1956 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1957 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1958 #endif /* LPROCFS*/