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