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