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