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