Whamcloud - gitweb
b=16098
[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, quotacheck);
1188         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1189         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1190         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1191         LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1192         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1193         LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1194 }
1195
1196 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1197 {
1198         struct lprocfs_stats *stats;
1199         unsigned int num_stats;
1200         int rc, i;
1201
1202         LASSERT(obd->obd_stats == NULL);
1203         LASSERT(obd->obd_proc_entry != NULL);
1204         LASSERT(obd->obd_cntr_base == 0);
1205
1206         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1207                 num_private_stats - 1 /* o_owner */;
1208         stats = lprocfs_alloc_stats(num_stats, 0);
1209         if (stats == NULL)
1210                 return -ENOMEM;
1211
1212         lprocfs_init_ops_stats(num_private_stats, stats);
1213
1214         for (i = num_private_stats; i < num_stats; i++) {
1215                 /* If this LBUGs, it is likely that an obd
1216                  * operation was added to struct obd_ops in
1217                  * <obd.h>, and that the corresponding line item
1218                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1219                  * is missing from the list above. */
1220                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1221                          "Missing obd_stat initializer obd_op "
1222                          "operation at offset %d.\n", i - num_private_stats);
1223         }
1224         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1225         if (rc < 0) {
1226                 lprocfs_free_stats(&stats);
1227         } else {
1228                 obd->obd_stats  = stats;
1229                 obd->obd_cntr_base = num_private_stats;
1230         }
1231         return rc;
1232 }
1233
1234 void lprocfs_free_obd_stats(struct obd_device *obd)
1235 {
1236         if (obd->obd_stats) 
1237                 lprocfs_free_stats(&obd->obd_stats);
1238 }
1239
1240 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1241 do {                                                                    \
1242         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1243         LASSERT(coffset < stats->ls_num);                               \
1244         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1245 } while (0)
1246
1247 int lprocfs_alloc_md_stats(struct obd_device *obd,
1248                            unsigned num_private_stats)
1249 {
1250         struct lprocfs_stats *stats;
1251         unsigned int num_stats;
1252         int rc, i;
1253
1254         LASSERT(obd->md_stats == NULL);
1255         LASSERT(obd->obd_proc_entry != NULL);
1256         LASSERT(obd->md_cntr_base == 0);
1257
1258         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1259                     num_private_stats;
1260         stats = lprocfs_alloc_stats(num_stats, 0);
1261         if (stats == NULL)
1262                 return -ENOMEM;
1263
1264         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1265         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1266         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1267         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1268         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1269         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1270         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1271         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1272         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1273         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1274         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1275         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1276         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1277         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1278         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1279         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1280         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1281         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1282         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1283         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1284         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1285         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1286         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1287         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1288         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1289         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1290         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1291         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1292         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1293         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1294
1295         for (i = num_private_stats; i < num_stats; i++) {
1296                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1297                         CERROR("Missing md_stat initializer md_op "
1298                                "operation at offset %d. Aborting.\n",
1299                                i - num_private_stats);
1300                         LBUG();
1301                 }
1302         }
1303         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1304         if (rc < 0) {
1305                 lprocfs_free_stats(&stats);
1306         } else {
1307                 obd->md_stats  = stats;
1308                 obd->md_cntr_base = num_private_stats;
1309         }
1310         return rc;
1311 }
1312
1313 void lprocfs_free_md_stats(struct obd_device *obd)
1314 {
1315         struct lprocfs_stats *stats = obd->md_stats;
1316
1317         if (stats != NULL) {
1318                 obd->md_stats = NULL;
1319                 lprocfs_free_stats(&stats);
1320         }
1321 }
1322
1323 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1324                          int *eof,  void *data)
1325 {
1326         struct obd_export *exp = (struct obd_export*)data;
1327         LASSERT(exp != NULL);
1328         *eof = 1;
1329         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1330 }
1331
1332 struct exp_uuid_cb_data {
1333         char                   *page;
1334         int                     count;
1335         int                    *eof;
1336         int                    *len;
1337 };
1338
1339 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1340 {
1341         struct obd_export *exp = (struct obd_export *)obj;
1342         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1343
1344         if (exp->exp_nid_stats)
1345                 *data->len += snprintf((data->page + *data->len),
1346                                        data->count, "%s\n",
1347                                        obd_uuid2str(&exp->exp_client_uuid));
1348 }
1349
1350 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1351                         int *eof,  void *data)
1352 {
1353         struct nid_stat *stats = (struct nid_stat *)data;
1354         struct exp_uuid_cb_data cb_data;
1355         struct obd_device *obd = stats->nid_obd;
1356         int len = 0;
1357
1358         *eof = 1;
1359         page[0] = '\0';
1360         LASSERT(obd != NULL);
1361
1362         cb_data.page = page;
1363         cb_data.count = count;
1364         cb_data.eof = eof;
1365         cb_data.len = &len;
1366         lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
1367                                    &stats->nid, lprocfs_exp_print_uuid,
1368                                    &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_iterate_all(obd->obd_nid_stats_hash_body,
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_body)
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_body);
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_body, nid,
1469                                          &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_delitem(obd->obd_nid_stats_hash_body, nid,
1484                                     &tmp->nid_hash);
1485                 GOTO(destroy_new, rc = -ENOMEM);
1486         }
1487
1488         rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
1489                                 lprocfs_exp_rd_uuid, NULL, tmp);
1490         if (rc)
1491                 CWARN("Error adding the uuid file\n");
1492
1493         exp->exp_nid_stats = tmp;
1494         *newnid = 1;
1495         RETURN(rc);
1496
1497 destroy_new:
1498         spin_lock(&obd->obd_nid_lock);
1499         list_del(&tmp->nid_list);
1500         spin_unlock(&obd->obd_nid_lock);
1501         OBD_FREE(tmp, sizeof(struct nid_stat));
1502         RETURN(rc);
1503 }
1504
1505 int lprocfs_exp_cleanup(struct obd_export *exp)
1506 {
1507         struct nid_stat *stat = exp->exp_nid_stats;
1508
1509         if(!stat)
1510                 RETURN(0);
1511
1512         stat->nid_exp_ref_count--;
1513         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1514
1515         exp->exp_nid_stats = NULL;
1516         return 0;
1517 }
1518
1519 int lprocfs_write_helper(const char *buffer, unsigned long count,
1520                          int *val)
1521 {
1522         return lprocfs_write_frac_helper(buffer, count, val, 1);
1523 }
1524
1525 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1526                               int *val, int mult)
1527 {
1528         char kernbuf[20], *end, *pbuf;
1529
1530         if (count > (sizeof(kernbuf) - 1))
1531                 return -EINVAL;
1532
1533         if (copy_from_user(kernbuf, buffer, count))
1534                 return -EFAULT;
1535
1536         kernbuf[count] = '\0';
1537         pbuf = kernbuf;
1538         if (*pbuf == '-') {
1539                 mult = -mult;
1540                 pbuf++;
1541         }
1542
1543         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1544         if (pbuf == end)
1545                 return -EINVAL;
1546
1547         if (end != NULL && *end == '.') {
1548                 int temp_val, pow = 1;
1549                 int i;
1550
1551                 pbuf = end + 1;
1552                 if (strlen(pbuf) > 5)
1553                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1554
1555                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1556
1557                 if (pbuf < end) {
1558                         for (i = 0; i < (end - pbuf); i++)
1559                                 pow *= 10;
1560
1561                         *val += temp_val / pow;
1562                 }
1563         }
1564         return 0;
1565 }
1566
1567 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1568 {
1569         long decimal_val, frac_val;
1570         int prtn;
1571
1572         if (count < 10)
1573                 return -EINVAL;
1574
1575         decimal_val = val / mult;
1576         prtn = snprintf(buffer, count, "%ld", decimal_val);
1577         frac_val = val % mult;
1578
1579         if (prtn < (count - 4) && frac_val > 0) {
1580                 long temp_frac;
1581                 int i, temp_mult = 1, frac_bits = 0;
1582
1583                 temp_frac = frac_val * 10;
1584                 buffer[prtn++] = '.';
1585                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1586                         buffer[prtn++] ='0';
1587                         temp_frac *= 10;
1588                         frac_bits++;
1589                 }
1590                 /*
1591                   Need to think these cases :
1592                         1. #echo x.00 > /proc/xxx       output result : x
1593                         2. #echo x.0x > /proc/xxx       output result : x.0x
1594                         3. #echo x.x0 > /proc/xxx       output result : x.x
1595                         4. #echo x.xx > /proc/xxx       output result : x.xx
1596                         Only reserved 2bits fraction.       
1597                  */
1598                 for (i = 0; i < (5 - prtn); i++)
1599                         temp_mult *= 10;
1600
1601                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1602                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1603
1604                 prtn--;
1605                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1606                         prtn--;
1607                         if (buffer[prtn] == '.') {
1608                                 prtn--;
1609                                 break;
1610                         }
1611                 }
1612                 prtn++;
1613         }
1614         buffer[prtn++] ='\n';
1615         return prtn;
1616 }
1617
1618 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1619 {
1620         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1621 }
1622
1623 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1624                               __u64 *val, int mult)
1625 {
1626         char kernbuf[22], *end, *pbuf;
1627         __u64 whole, frac = 0, units;
1628         unsigned frac_d = 1;
1629
1630         if (count > (sizeof(kernbuf) - 1) )
1631                 return -EINVAL;
1632
1633         if (copy_from_user(kernbuf, buffer, count))
1634                 return -EFAULT;
1635
1636         kernbuf[count] = '\0';
1637         pbuf = kernbuf;
1638         if (*pbuf == '-') {
1639                 mult = -mult;
1640                 pbuf++;
1641         }
1642
1643         whole = simple_strtoull(pbuf, &end, 10);
1644         if (pbuf == end)
1645                 return -EINVAL;
1646
1647         if (end != NULL && *end == '.') {
1648                 int i;
1649                 pbuf = end + 1;
1650
1651                 /* need to limit frac_d to a __u32 */
1652                 if (strlen(pbuf) > 10)
1653                         pbuf[10] = '\0';
1654
1655                 frac = simple_strtoull(pbuf, &end, 10);
1656                 /* count decimal places */
1657                 for (i = 0; i < (end - pbuf); i++)
1658                         frac_d *= 10;
1659         }
1660
1661         units = 1;
1662         switch(*end) {
1663         case 'p': case 'P':
1664                 units <<= 10;
1665         case 't': case 'T':
1666                 units <<= 10;
1667         case 'g': case 'G':
1668                 units <<= 10;
1669         case 'm': case 'M':
1670                 units <<= 10;
1671         case 'k': case 'K':
1672                 units <<= 10;
1673         }
1674         /* Specified units override the multiplier */
1675         if (units) 
1676                 mult = mult < 0 ? -units : units;
1677
1678         frac *= mult;
1679         do_div(frac, frac_d);
1680         *val = whole * mult + frac;
1681         return 0;
1682 }
1683
1684 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1685                        char *name, mode_t mode,
1686                        struct file_operations *seq_fops, void *data)
1687 {
1688         struct proc_dir_entry *entry;
1689         ENTRY;
1690
1691         entry = create_proc_entry(name, mode, parent);
1692         if (entry == NULL)
1693                 RETURN(-ENOMEM);
1694         entry->proc_fops = seq_fops;
1695         entry->data = data;
1696
1697         RETURN(0);
1698 }
1699 EXPORT_SYMBOL(lprocfs_seq_create);
1700
1701 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1702                                       mode_t mode,
1703                                       struct file_operations *seq_fops,
1704                                       void *data)
1705 {
1706         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1707                                    mode, seq_fops, data));
1708 }
1709 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1710
1711 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1712 {
1713         if (value >= OBD_HIST_MAX)
1714                 value = OBD_HIST_MAX - 1;
1715
1716         spin_lock(&oh->oh_lock);
1717         oh->oh_buckets[value]++;
1718         spin_unlock(&oh->oh_lock);
1719 }
1720 EXPORT_SYMBOL(lprocfs_oh_tally);
1721
1722 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1723 {
1724         unsigned int val;
1725
1726         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1727                 ;
1728
1729         lprocfs_oh_tally(oh, val);
1730 }
1731 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1732
1733 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1734 {
1735         unsigned long ret = 0;
1736         int i;
1737
1738         for (i = 0; i < OBD_HIST_MAX; i++)
1739                 ret +=  oh->oh_buckets[i];
1740         return ret;
1741 }
1742 EXPORT_SYMBOL(lprocfs_oh_sum);
1743
1744 void lprocfs_oh_clear(struct obd_histogram *oh)
1745 {
1746         spin_lock(&oh->oh_lock);
1747         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1748         spin_unlock(&oh->oh_lock);
1749 }
1750 EXPORT_SYMBOL(lprocfs_oh_clear);
1751
1752 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1753                                    int count, int *eof, void *data)
1754 {
1755         struct obd_device *obd = data;
1756         int len = 0, size;
1757
1758         LASSERT(obd != NULL);
1759         LASSERT(count >= 0);
1760
1761         /* Set start of user data returned to
1762            page + off since the user may have
1763            requested to read much smaller than
1764            what we need to read */
1765         *start = page + off;
1766
1767         /* We know we are allocated a page here.
1768            Also we know that this function will
1769            not need to write more than a page
1770            so we can truncate at CFS_PAGE_SIZE.  */
1771         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1772
1773         /* Initialize the page */
1774         memset(page, 0, size);
1775
1776         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1777                 goto out;
1778         if (obd->obd_max_recoverable_clients == 0) {
1779                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1780                         goto out;
1781
1782                 goto fclose;
1783         }
1784
1785         /* sampled unlocked, but really... */
1786         if (obd->obd_recovering == 0) {
1787                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1788                         goto out;
1789                 if (lprocfs_obd_snprintf(&page, size, &len,
1790                                          "recovery_start: %lu\n",
1791                                          obd->obd_recovery_start) <= 0)
1792                         goto out;
1793                 if (lprocfs_obd_snprintf(&page, size, &len,
1794                                          "recovery_duration: %lu\n",
1795                                          obd->obd_recovery_end -
1796                                          obd->obd_recovery_start) <= 0)
1797                         goto out;
1798                 /* Number of clients that have completed recovery */
1799                 if (lprocfs_obd_snprintf(&page, size, &len,
1800                                          "completed_clients: %d/%d\n",
1801                                          obd->obd_max_recoverable_clients -
1802                                          obd->obd_recoverable_clients,
1803                                          obd->obd_max_recoverable_clients) <= 0)
1804                         goto out;
1805                 if (lprocfs_obd_snprintf(&page, size, &len,
1806                                          "replayed_requests: %d\n",
1807                                          obd->obd_replayed_requests) <= 0)
1808                         goto out;
1809                 if (lprocfs_obd_snprintf(&page, size, &len,
1810                                          "last_transno: "LPD64"\n",
1811                                          obd->obd_next_recovery_transno - 1)<=0)
1812                         goto out;
1813                 goto fclose;
1814         }
1815
1816         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1817                 goto out;
1818         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1819                                  obd->obd_recovery_start) <= 0)
1820                 goto out;
1821         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1822                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
1823                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
1824                 goto out;
1825         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
1826                                  obd->obd_connected_clients,
1827                                  obd->obd_max_recoverable_clients) <= 0)
1828                 goto out;
1829         /* Number of clients that have completed recovery */
1830         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
1831                                  obd->obd_max_recoverable_clients -
1832                                  obd->obd_recoverable_clients,
1833                                  obd->obd_max_recoverable_clients) <= 0)
1834                 goto out;
1835         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
1836                                  obd->obd_replayed_requests) <= 0)
1837                 goto out;
1838         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1839                                  obd->obd_requests_queued_for_recovery) <= 0)
1840                 goto out;
1841
1842         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", 
1843                                  obd->obd_next_recovery_transno) <= 0)
1844                 goto out;
1845
1846 fclose:
1847         *eof = 1;
1848 out:
1849         return min(count, len - (int)off);
1850 }
1851 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1852
1853 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
1854                                     int count, int *eof, void *data)
1855 {
1856         struct obd_device *obd = (struct obd_device *)data;
1857         LASSERT(obd != NULL);
1858
1859         return snprintf(page, count, "%lu\n", 
1860                         obd->obd_recovery_max_time);
1861 }
1862 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
1863
1864 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
1865                                     unsigned long count, void *data)
1866 {
1867         struct obd_device *obd = (struct obd_device *)data;
1868         int val, rc;
1869         LASSERT(obd != NULL);
1870
1871         rc = lprocfs_write_helper(buffer, count, &val);
1872         if (rc)
1873                 return rc;
1874
1875         obd->obd_recovery_max_time = val;
1876         return count;
1877 }
1878 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
1879
1880 EXPORT_SYMBOL(lprocfs_register);
1881 EXPORT_SYMBOL(lprocfs_srch);
1882 EXPORT_SYMBOL(lprocfs_remove);
1883 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
1884 EXPORT_SYMBOL(lprocfs_add_vars);
1885 EXPORT_SYMBOL(lprocfs_obd_setup);
1886 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1887 EXPORT_SYMBOL(lprocfs_add_simple);
1888 EXPORT_SYMBOL(lprocfs_add_symlink);
1889 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
1890 EXPORT_SYMBOL(lprocfs_alloc_stats);
1891 EXPORT_SYMBOL(lprocfs_free_stats);
1892 EXPORT_SYMBOL(lprocfs_clear_stats);
1893 EXPORT_SYMBOL(lprocfs_register_stats);
1894 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1895 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1896 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1897 EXPORT_SYMBOL(lprocfs_exp_setup);
1898 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1899
1900 EXPORT_SYMBOL(lprocfs_rd_u64);
1901 EXPORT_SYMBOL(lprocfs_rd_atomic);
1902 EXPORT_SYMBOL(lprocfs_wr_atomic);
1903 EXPORT_SYMBOL(lprocfs_rd_uint);
1904 EXPORT_SYMBOL(lprocfs_wr_uint);
1905 EXPORT_SYMBOL(lprocfs_rd_uuid);
1906 EXPORT_SYMBOL(lprocfs_rd_name);
1907 EXPORT_SYMBOL(lprocfs_rd_fstype);
1908 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1909 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1910 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1911 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1912 EXPORT_SYMBOL(lprocfs_at_hist_helper);
1913 EXPORT_SYMBOL(lprocfs_rd_timeouts);
1914 EXPORT_SYMBOL(lprocfs_rd_blksize);
1915 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1916 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1917 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1918 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1919 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1920
1921 EXPORT_SYMBOL(lprocfs_write_helper);
1922 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1923 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1924 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1925 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1926 #endif /* LPROCFS*/