Whamcloud - gitweb
land b1_5 onto 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 /* for bug 10866, global variable */
42 DECLARE_RWSEM(_lprocfs_lock);
43 EXPORT_SYMBOL(_lprocfs_lock);
44
45 int lprocfs_seq_release(struct inode *inode, struct file *file)
46 {
47         LPROCFS_EXIT();
48         return seq_release(inode, file);
49 }
50 EXPORT_SYMBOL(lprocfs_seq_release);
51
52 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
53                                     const char *name)
54 {
55         struct proc_dir_entry *temp;
56
57         if (head == NULL)
58                 return NULL;
59
60         temp = head->subdir;
61         while (temp != NULL) {
62                 if (strcmp(temp->name, name) == 0)
63                         return temp;
64
65                 temp = temp->next;
66         }
67         return NULL;
68 }
69
70 /* lprocfs API calls */
71
72 /* Function that emulates snprintf but also has the side effect of advancing
73    the page pointer for the next write into the buffer, incrementing the total
74    length written to the buffer, and decrementing the size left in the
75    buffer. */
76 static int lprocfs_obd_snprintf(char **page, int end, int *len,
77                                 const char *format, ...)
78 {
79         va_list list;
80         int n;
81
82         if (*len >= end)
83                 return 0;
84
85         va_start(list, format);
86         n = vsnprintf(*page, end - *len, format, list);
87         va_end(list);
88
89         *page += n; *len += n;
90         return n;
91 }
92
93 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
94                        read_proc_t *read_proc, write_proc_t *write_proc,
95                        void *data)
96 {
97         struct proc_dir_entry *proc;
98         mode_t mode = 0;
99         
100         if (root == NULL || name == NULL)
101                 return -EINVAL;
102         if (read_proc)
103                 mode = 0444;
104         if (write_proc)
105                 mode |= 0200;
106         proc = create_proc_entry(name, mode, root);
107         if (!proc) {
108                 CERROR("LprocFS: No memory to create /proc entry %s", name);
109                 return -ENOMEM;
110         }
111         proc->read_proc = read_proc;
112         proc->write_proc = write_proc;
113         proc->data = data;
114         return 0;
115 }
116
117
118 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf, size_t size, loff_t *ppos)
119 {
120         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
121         char *page, *start = NULL;
122         int rc = 0, eof = 1, count;
123
124         if (*ppos >= PAGE_SIZE)
125                 return 0;
126
127         page = (char *)__get_free_page(GFP_KERNEL);
128         if (page == NULL)
129                 return -ENOMEM;
130
131         LPROCFS_ENTRY();
132         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
133         if (!dp->deleted && dp->read_proc)
134                 rc = dp->read_proc(page, &start, *ppos, PAGE_SIZE, 
135                         &eof, dp->data);
136         LPROCFS_EXIT();
137         if (rc <= 0)
138                 goto out;
139
140         /* for lustre proc read, the read count must be less than PAGE_SIZE */
141         LASSERT(eof == 1);
142
143         if (start == NULL) {
144                 rc -= *ppos;
145                 if (rc < 0)
146                         rc = 0;
147                 if (rc == 0)
148                         goto out;
149                 start = page + *ppos;
150         } else if (start < page) {
151                 start = page;
152         }
153
154         count = (rc < size) ? rc : size;
155         if (copy_to_user(buf, start, count)) {
156                 rc = -EFAULT;
157                 goto out;
158         }
159         *ppos += count;
160
161 out:
162         free_page((unsigned long)page);
163         return rc;
164 }
165
166 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
167 {
168         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
169         int rc = 0;
170
171         LPROCFS_ENTRY();
172         if (!dp->deleted && dp->write_proc)
173                 rc = dp->write_proc(f, buf, size, dp->data);
174         LPROCFS_EXIT();
175         return rc;
176 }
177
178 static struct file_operations lprocfs_generic_fops = {
179         .owner = THIS_MODULE,
180         .read = lprocfs_fops_read,
181         .write = lprocfs_fops_write,
182 };
183
184
185 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
186                      void *data)
187 {
188         if (root == NULL || list == NULL)
189                 return -EINVAL;
190
191         while (list->name != NULL) {
192                 struct proc_dir_entry *cur_root, *proc;
193                 char *pathcopy, *cur, *next, pathbuf[64];
194                 int pathsize = strlen(list->name) + 1;
195
196                 proc = NULL;
197                 cur_root = root;
198
199                 /* need copy of path for strsep */
200                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
201                         OBD_ALLOC(pathcopy, pathsize);
202                         if (pathcopy == NULL)
203                                 return -ENOMEM;
204                 } else {
205                         pathcopy = pathbuf;
206                 }
207
208                 next = pathcopy;
209                 strcpy(pathcopy, list->name);
210
211                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
212                         if (*cur =='\0') /* skip double/trailing "/" */
213                                 continue;
214
215                         proc = lprocfs_srch(cur_root, cur);
216                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
217                                cur_root->name, cur, next,
218                                (proc ? "exists" : "new"));
219                         if (next != NULL) {
220                                 cur_root = (proc ? proc :
221                                             proc_mkdir(cur, cur_root));
222                         } else if (proc == NULL) {
223                                 mode_t mode = 0;
224                                 if (list->read_fptr)
225                                         mode = 0444;
226                                 if (list->write_fptr)
227                                         mode |= 0200;
228                                 proc = create_proc_entry(cur, mode, cur_root);
229                         }
230                 }
231
232                 if (pathcopy != pathbuf)
233                         OBD_FREE(pathcopy, pathsize);
234
235                 if (cur_root == NULL || proc == NULL) {
236                         CERROR("LprocFS: No memory to create /proc entry %s",
237                                list->name);
238                         return -ENOMEM;
239                 }
240
241                 proc->proc_fops = &lprocfs_generic_fops;
242                 proc->read_proc = list->read_fptr;
243                 proc->write_proc = list->write_fptr;
244                 proc->data = (list->data ? list->data : data);
245                 list++;
246         }
247         return 0;
248 }
249
250 void lprocfs_remove(struct proc_dir_entry **rooth)
251 {
252         struct proc_dir_entry *root = *rooth;
253         struct proc_dir_entry *temp = root;
254         struct proc_dir_entry *rm_entry;
255         struct proc_dir_entry *parent;
256
257         if (!root) 
258                 return;
259         *rooth = NULL;
260
261         parent = root->parent;
262         LASSERT(parent != NULL);
263  
264         while (1) {
265                 while (temp->subdir != NULL)
266                         temp = temp->subdir;
267
268                 rm_entry = temp;
269                 temp = temp->parent;
270
271                 /* Memory corruption once caused this to fail, and
272                    without this LASSERT we would loop here forever. */
273                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
274                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
275                          rm_entry->name, (int)strlen(rm_entry->name));
276
277                 /* Now, the rm_entry->deleted flags is protected 
278                  * by _lprocfs_lock. */
279                 down_write(&_lprocfs_lock);
280                 rm_entry->data = NULL;
281                 remove_proc_entry(rm_entry->name, rm_entry->parent);
282                 up_write(&_lprocfs_lock);
283                 if (temp == parent)
284                         break;
285         }
286 }
287
288 struct proc_dir_entry *lprocfs_register(const char *name,
289                                         struct proc_dir_entry *parent,
290                                         struct lprocfs_vars *list, void *data)
291 {
292         struct proc_dir_entry *newchild;
293
294         newchild = lprocfs_srch(parent, name);
295         if (newchild != NULL) {
296                 CERROR(" Lproc: Attempting to register %s more than once \n",
297                        name);
298                 return ERR_PTR(-EALREADY);
299         }
300
301         newchild = proc_mkdir(name, parent);
302         if (newchild != NULL && list != NULL) {
303                 int rc = lprocfs_add_vars(newchild, list, data);
304                 if (rc) {
305                         lprocfs_remove(&newchild);
306                         return ERR_PTR(rc);
307                 }
308         }
309         return newchild;
310 }
311
312 /* Generic callbacks */
313
314 int lprocfs_rd_u64(char *page, char **start, off_t off,
315                    int count, int *eof, void *data)
316 {
317         LASSERT(data != NULL);
318         *eof = 1;
319         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
320 }
321
322 int lprocfs_rd_atomic(char *page, char **start, off_t off,
323                    int count, int *eof, void *data)
324 {
325         atomic_t *atom = (atomic_t *)data;
326         LASSERT(atom != NULL);
327         *eof = 1;
328         return snprintf(page, count, "%d\n", atomic_read(atom));
329 }
330
331 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
332                     int *eof, void *data)
333 {
334         struct obd_device *obd = (struct obd_device*)data;
335
336         LASSERT(obd != NULL);
337         *eof = 1;
338         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
339 }
340
341 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
342                     int *eof, void* data)
343 {
344         struct obd_device *dev = (struct obd_device *)data;
345
346         LASSERT(dev != NULL);
347         LASSERT(dev->obd_name != NULL);
348         *eof = 1;
349         return snprintf(page, count, "%s\n", dev->obd_name);
350 }
351
352 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
353                       void *data)
354 {
355         struct obd_device *obd = (struct obd_device *)data;
356
357         LASSERT(obd != NULL);
358         LASSERT(obd->obd_fsops != NULL);
359         LASSERT(obd->obd_fsops->fs_type != NULL);
360         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
361 }
362
363 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
364                        int *eof, void *data)
365 {
366         struct obd_statfs osfs;
367         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
368         if (!rc) {
369                 *eof = 1;
370                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
371         }
372         return rc;
373 }
374
375 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
376                            int *eof, void *data)
377 {
378         struct obd_statfs osfs;
379         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
380         if (!rc) {
381                 __u32 blk_size = osfs.os_bsize >> 10;
382                 __u64 result = osfs.os_blocks;
383
384                 while (blk_size >>= 1)
385                         result <<= 1;
386
387                 *eof = 1;
388                 rc = snprintf(page, count, LPU64"\n", result);
389         }
390         return rc;
391 }
392
393 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
394                           int *eof, void *data)
395 {
396         struct obd_statfs osfs;
397         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
398         if (!rc) {
399                 __u32 blk_size = osfs.os_bsize >> 10;
400                 __u64 result = osfs.os_bfree;
401
402                 while (blk_size >>= 1)
403                         result <<= 1;
404
405                 *eof = 1;
406                 rc = snprintf(page, count, LPU64"\n", result);
407         }
408         return rc;
409 }
410
411 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
412                            int *eof, void *data)
413 {
414         struct obd_statfs osfs;
415         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
416         if (!rc) {
417                 __u32 blk_size = osfs.os_bsize >> 10;
418                 __u64 result = osfs.os_bavail;
419
420                 while (blk_size >>= 1)
421                         result <<= 1;
422
423                 *eof = 1;
424                 rc = snprintf(page, count, LPU64"\n", result);
425         }
426         return rc;
427 }
428
429 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
430                           int *eof, void *data)
431 {
432         struct obd_statfs osfs;
433         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
434         if (!rc) {
435                 *eof = 1;
436                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
437         }
438
439         return rc;
440 }
441
442 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
443                          int *eof, void *data)
444 {
445         struct obd_statfs osfs;
446         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
447         if (!rc) {
448                 *eof = 1;
449                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
450         }
451         return rc;
452 }
453
454 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
455                            int *eof, void *data)
456 {
457         struct obd_device *obd = (struct obd_device *)data;
458         struct obd_import *imp;
459         char *imp_state_name = NULL;
460         int rc = 0;
461
462         LASSERT(obd != NULL);
463         LPROCFS_CLIMP_CHECK(obd);
464         imp = obd->u.cli.cl_import;
465         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
466         *eof = 1;
467         rc = snprintf(page, count, "%s\t%s%s\n",
468                         obd2cli_tgt(obd), imp_state_name,
469                         imp->imp_deactive ? "\tDEACTIVATED" : "");
470
471         LPROCFS_CLIMP_EXIT(obd);
472         return rc;
473 }
474
475 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
476                          int *eof,  void *data)
477 {
478         struct obd_device *obd = (struct obd_device*)data;
479         struct ptlrpc_connection *conn;
480         int rc = 0;
481
482         LASSERT(obd != NULL); 
483         LPROCFS_CLIMP_CHECK(obd);
484         conn = obd->u.cli.cl_import->imp_connection;
485         LASSERT(conn != NULL);
486         *eof = 1;
487         rc = snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
488
489         LPROCFS_CLIMP_EXIT(obd);
490         return rc;
491 }
492
493 static const char *obd_connect_names[] = {
494         "read_only",
495         "lov_index",
496         "unused",
497         "write_grant",
498         "server_lock",
499         "version",
500         "request_portal",
501         "acl",
502         "xattr",
503         "create_on_write",
504         "truncate_lock",
505         "initial_transno",
506         "inode_bit_locks",
507         "join_file",
508         "getattr_by_fid",
509         "no_oh_for_devices",
510         "local_1.8_client",
511         "remote_1.8_client",
512         "max_byte_per_rpc",
513         "64bit_qdata",
514         "fid_capability",
515         "oss_capability",
516         NULL
517 };
518
519 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
520                              int count, int *eof, void *data)
521 {
522         struct obd_device *obd = data;
523         __u64 mask = 1, flags;
524         int i, ret = 0;
525
526         LPROCFS_CLIMP_CHECK(obd);
527         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
528         ret = snprintf(page, count, "flags="LPX64"\n", flags);
529         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
530                 if (flags & mask)
531                         ret += snprintf(page + ret, count - ret, "%s\n",
532                                         obd_connect_names[i]);
533         }
534         if (flags & ~(mask - 1))
535                 ret += snprintf(page + ret, count - ret,
536                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
537
538         LPROCFS_CLIMP_EXIT(obd);
539         return ret;
540 }
541 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
542
543 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
544                            int *eof,  void *data)
545 {
546         struct obd_device *obd = (struct obd_device*)data;
547
548         LASSERT(obd != NULL);
549         *eof = 1;
550         return snprintf(page, count, "%u\n", obd->obd_num_exports);
551 }
552
553 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
554                        int *eof, void *data)
555 {
556         struct obd_type *class = (struct obd_type*) data;
557
558         LASSERT(class != NULL);
559         *eof = 1;
560         return snprintf(page, count, "%d\n", class->typ_refcnt);
561 }
562
563 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
564 {
565         int rc = 0;
566
567         LASSERT(obd != NULL);
568         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
569         LASSERT(obd->obd_type->typ_procroot != NULL);
570
571         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
572                                                obd->obd_type->typ_procroot,
573                                                list, obd);
574         if (IS_ERR(obd->obd_proc_entry)) {
575                 rc = PTR_ERR(obd->obd_proc_entry);
576                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
577                 obd->obd_proc_entry = NULL;
578         }
579         return rc;
580 }
581
582 int lprocfs_obd_cleanup(struct obd_device *obd)
583 {
584         if (!obd) 
585                 return -EINVAL;
586         if (obd->obd_proc_exports) {
587                 /* Should be no exports left */
588                 LASSERT(obd->obd_proc_exports->subdir == NULL);
589                 lprocfs_remove(&obd->obd_proc_exports);
590         }
591         lprocfs_remove(&obd->obd_proc_entry);
592         return 0;
593 }
594
595 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
596 {
597         struct lprocfs_stats *stats;
598         struct lprocfs_percpu *percpu;
599         unsigned int percpusize;
600         unsigned int i;
601
602         if (num == 0)
603                 return NULL;
604
605         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
606         if (stats == NULL)
607                 return NULL;
608
609         percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
610         stats->ls_percpu_size = num_online_cpus() * percpusize;
611         OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
612         if (stats->ls_percpu[0] == NULL) {
613                 OBD_FREE(stats, offsetof(typeof(*stats),
614                                          ls_percpu[num_online_cpus()]));
615                 return NULL;
616         }
617
618         stats->ls_num = num;
619         for (i = 1; i < num_online_cpus(); i++)
620                 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
621                         percpusize;
622
623         return stats;
624 }
625
626 void lprocfs_free_stats(struct lprocfs_stats **statsh)
627 {
628         struct lprocfs_stats *stats = *statsh;
629         
630         if (!stats || (stats->ls_num == 0))
631                 return;
632         *statsh = NULL;
633
634         OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
635         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
636 }
637
638 void lprocfs_clear_stats(struct lprocfs_stats *stats)
639 {
640         struct lprocfs_counter *percpu_cntr;
641         int i,j;
642
643         for (i = 0; i < num_online_cpus(); i++) {
644                 for (j = 0; j < stats->ls_num; j++) {        
645                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
646                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
647                         percpu_cntr->lc_count = 0;
648                         percpu_cntr->lc_sum = 0;
649                         percpu_cntr->lc_min = ~(__u64)0;
650                         percpu_cntr->lc_max = 0;
651                         percpu_cntr->lc_sumsquare = 0;
652                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
653                 }
654         }
655 }
656
657 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
658                                        size_t len, loff_t *off)
659 {
660         struct seq_file *seq = file->private_data;
661         struct lprocfs_stats *stats = seq->private;
662
663         lprocfs_clear_stats(stats);
664
665         return len;
666 }
667
668 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
669 {
670         struct lprocfs_stats *stats = p->private;
671         /* return 1st cpu location */
672         return (*pos >= stats->ls_num) ? NULL :
673                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
674 }
675
676 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
677 {
678 }
679
680 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
681 {
682         struct lprocfs_stats *stats = p->private;
683         ++*pos;
684         return (*pos >= stats->ls_num) ? NULL :
685                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
686 }
687
688 /* seq file export of one lprocfs counter */
689 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
690 {
691        struct lprocfs_stats *stats = p->private;
692        struct lprocfs_counter  *cntr = v;
693        struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
694        int i, idx, rc;
695
696        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
697                struct timeval now;
698                do_gettimeofday(&now);
699                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
700                                "snapshot_time", now.tv_sec, now.tv_usec);
701                if (rc < 0)
702                        return rc;
703        }
704        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
705
706        for (i = 0; i < num_online_cpus(); i++) {
707                struct lprocfs_counter *percpu_cntr =
708                        &(stats->ls_percpu[i])->lp_cntr[idx];
709                int centry;
710
711                do {
712                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
713                        t.lc_count = percpu_cntr->lc_count;
714                        t.lc_sum = percpu_cntr->lc_sum;
715                        t.lc_min = percpu_cntr->lc_min;
716                        t.lc_max = percpu_cntr->lc_max;
717                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
718                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
719                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
720                ret.lc_count += t.lc_count;
721                ret.lc_sum += t.lc_sum;
722                if (t.lc_min < ret.lc_min)
723                        ret.lc_min = t.lc_min;
724                if (t.lc_max > ret.lc_max)
725                        ret.lc_max = t.lc_max;
726                ret.lc_sumsquare += t.lc_sumsquare;
727        }
728
729        rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
730                        ret.lc_count, cntr->lc_units);
731        if (rc < 0)
732                goto out;
733
734        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
735                rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
736                                ret.lc_min, ret.lc_max, ret.lc_sum);
737                if (rc < 0)
738                        goto out;
739                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
740                        rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
741                if (rc < 0)
742                        goto out;
743        }
744        rc = seq_printf(p, "\n");
745  out:
746        return (rc < 0) ? rc : 0;
747 }
748
749 struct seq_operations lprocfs_stats_seq_sops = {
750         start: lprocfs_stats_seq_start,
751         stop:  lprocfs_stats_seq_stop,
752         next:  lprocfs_stats_seq_next,
753         show:  lprocfs_stats_seq_show,
754 };
755
756 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
757 {
758         struct proc_dir_entry *dp = PDE(inode);
759         struct seq_file *seq;
760         int rc;
761
762         LPROCFS_ENTRY_AND_CHECK(dp);
763         rc = seq_open(file, &lprocfs_stats_seq_sops);
764         if (rc) {
765                 LPROCFS_EXIT();
766                 return rc;
767         }
768
769         seq = file->private_data;
770         seq->private = dp->data;
771         return 0;
772 }
773
774 struct file_operations lprocfs_stats_seq_fops = {
775         .owner   = THIS_MODULE,
776         .open    = lprocfs_stats_seq_open,
777         .read    = seq_read,
778         .write   = lprocfs_stats_seq_write,
779         .llseek  = seq_lseek,
780         .release = lprocfs_seq_release,
781 };
782
783 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
784                            struct lprocfs_stats *stats)
785 {
786         struct proc_dir_entry *entry;
787         LASSERT(root != NULL);
788
789         entry = create_proc_entry(name, 0644, root);
790         if (entry == NULL)
791                 return -ENOMEM;
792         entry->proc_fops = &lprocfs_stats_seq_fops;
793         entry->data = (void *)stats;
794         return 0;
795 }
796
797 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
798                           unsigned conf, const char *name, const char *units)
799 {
800         struct lprocfs_counter *c;
801         int i;
802
803         LASSERT(stats != NULL);
804         for (i = 0; i < num_online_cpus(); i++) {
805                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
806                 c->lc_config = conf;
807                 c->lc_count = 0;
808                 c->lc_sum = 0;
809                 c->lc_min = ~(__u64)0;
810                 c->lc_max = 0;
811                 c->lc_name = name;
812                 c->lc_units = units;
813         }
814 }
815 EXPORT_SYMBOL(lprocfs_counter_init);
816
817 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
818 do {                                                                       \
819         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
820         LASSERT(coffset < stats->ls_num);                                  \
821         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
822 } while (0)
823
824 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
825 {
826         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
827         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
828         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
829         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
830         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
831         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
832         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
833         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
834         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
835         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
836         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
837         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
838         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
839         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
840         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
841         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
842         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
843         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
844         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
845         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
846         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
847         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
848         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
849         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
850         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
851         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
852         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
853         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
854         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
855         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
856         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
857         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
858         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
859         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
860         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
861         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
862         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
863         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
864         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
865         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
866         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
867         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
868         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
869         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
870         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
871         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
872         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
873         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
874         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
875         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
876         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
877         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
878         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
879         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
880         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
881         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
882         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
883         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
884         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
885         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
886         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
887         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
888         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
889 }
890
891 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
892 {
893         struct lprocfs_stats *stats;
894         unsigned int num_stats;
895         int rc, i;
896
897         LASSERT(obd->obd_stats == NULL);
898         LASSERT(obd->obd_proc_entry != NULL);
899         LASSERT(obd->obd_cntr_base == 0);
900
901         num_stats = ((int)sizeof(*obd->obd_type->typ_ops) / sizeof(void *)) +
902                 num_private_stats - 1 /* o_owner */;
903         stats = lprocfs_alloc_stats(num_stats);
904         if (stats == NULL)
905                 return -ENOMEM;
906
907         lprocfs_init_ops_stats(num_private_stats, stats);
908
909         for (i = num_private_stats; i < num_stats; i++) {
910                 /* If this LBUGs, it is likely that an obd
911                  * operation was added to struct obd_ops in
912                  * <obd.h>, and that the corresponding line item
913                  * LPROCFS_OBD_OP_INIT(.., .., opname)
914                  * is missing from the list above. */
915                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
916                          "Missing obd_stat initializer obd_op "
917                          "operation at offset %d.\n", i - num_private_stats);
918         }
919         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
920         if (rc < 0) {
921                 lprocfs_free_stats(&stats);
922         } else {
923                 obd->obd_stats  = stats;
924                 obd->obd_cntr_base = num_private_stats;
925         }
926         return rc;
927 }
928
929 void lprocfs_free_obd_stats(struct obd_device *obd)
930 {
931         if (obd->obd_stats) 
932                 lprocfs_free_stats(&obd->obd_stats);
933 }
934
935 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
936                          int *eof,  void *data)
937 {
938         struct obd_export *exp = (struct obd_export*)data;
939         LASSERT(exp != NULL);
940         *eof = 1;
941         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
942 }
943
944 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
945                          int *eof,  void *data)
946 {
947         struct obd_export *exp = (struct obd_export*)data;
948         LASSERT(exp != NULL);
949         *eof = 1;
950         return snprintf(page, count, "%s\n", 
951                         obd_uuid2str(&exp->exp_client_uuid));
952 }
953
954 int lprocfs_exp_setup(struct obd_export *exp)
955 {
956         char name[sizeof (exp->exp_client_uuid.uuid) + 3];
957         int i = 1, rc;
958         ENTRY;
959
960         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
961                 RETURN(-EINVAL);
962
963         mutex_down(&exp->exp_obd->obd_proc_exp_sem);
964         sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
965         while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
966                 /* We might add a new export before deleting the old one during 
967                    an eviction (recovery-small 19a). Suckage. We
968                    could block, or come up with a new name, or just give up. */
969                 if (++i > 9) 
970                         GOTO(out, rc = -EEXIST);
971                 sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
972         }
973
974         /* Create a proc entry for this export */
975         exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
976         if (!exp->exp_proc) {
977                 CERROR("Error making export directory for %s\n", name);
978                 GOTO(out, rc = -ENOMEM);
979         }
980
981         /* Always add nid and uuid */
982         rc = lprocfs_add_simple(exp->exp_proc, "nid",
983                                 lprocfs_exp_rd_nid, NULL, exp);
984         if (rc)
985                 GOTO(out, rc);
986         rc = lprocfs_add_simple(exp->exp_proc, "uuid",
987                                 lprocfs_exp_rd_uuid, NULL, exp);
988         if (rc)
989                 GOTO(out, rc);
990
991         /* Always add ldlm stats */
992         exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC 
993                                                   - LDLM_FIRST_OPC);
994         if (exp->exp_ldlm_stats == NULL) {
995                 lprocfs_remove(&exp->exp_proc);
996                 GOTO(out, rc = -ENOMEM);
997         }
998
999         lprocfs_counter_init(exp->exp_ldlm_stats, 
1000                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1001                              0, "ldlm_enqueue", "reqs");
1002         lprocfs_counter_init(exp->exp_ldlm_stats, 
1003                              LDLM_CONVERT - LDLM_FIRST_OPC,
1004                              0, "ldlm_convert", "reqs");
1005         lprocfs_counter_init(exp->exp_ldlm_stats, 
1006                              LDLM_CANCEL - LDLM_FIRST_OPC,
1007                              0, "ldlm_cancel", "reqs");
1008         lprocfs_counter_init(exp->exp_ldlm_stats, 
1009                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1010                              0, "ldlm_bl_callback", "reqs");
1011         lprocfs_counter_init(exp->exp_ldlm_stats, 
1012                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1013                              0, "ldlm_cp_callback", "reqs");
1014         lprocfs_counter_init(exp->exp_ldlm_stats, 
1015                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1016                              0, "ldlm_gl_callback", "reqs");
1017         lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
1018                                exp->exp_ldlm_stats);
1019 out:
1020         mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1021         RETURN(rc);
1022 }
1023
1024 int lprocfs_exp_cleanup(struct obd_export *exp)
1025 {
1026         mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1027         lprocfs_remove(&exp->exp_proc);
1028         lprocfs_free_stats(&exp->exp_ops_stats);
1029         lprocfs_free_stats(&exp->exp_ldlm_stats);
1030         mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1031         return 0;
1032 }
1033
1034 int lprocfs_write_helper(const char *buffer, unsigned long count,
1035                          int *val)
1036 {
1037         return lprocfs_write_frac_helper(buffer, count, val, 1);
1038 }
1039
1040 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1041                               int *val, int mult)
1042 {
1043         char kernbuf[20], *end, *pbuf;
1044
1045         if (count > (sizeof(kernbuf) - 1))
1046                 return -EINVAL;
1047
1048         if (copy_from_user(kernbuf, buffer, count))
1049                 return -EFAULT;
1050
1051         kernbuf[count] = '\0';
1052         pbuf = kernbuf;
1053         if (*pbuf == '-') {
1054                 mult = -mult;
1055                 pbuf++;
1056         }
1057
1058         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1059         if (pbuf == end)
1060                 return -EINVAL;
1061
1062         if (end != NULL && *end == '.') {
1063                 int temp_val, pow = 1;
1064                 int i;
1065
1066                 pbuf = end + 1;
1067                 if (strlen(pbuf) > 5)
1068                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1069
1070                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1071
1072                 if (pbuf < end) {
1073                         for (i = 0; i < (end - pbuf); i++)
1074                                 pow *= 10;
1075
1076                         *val += temp_val / pow;
1077                 }
1078         }
1079         return 0;
1080 }
1081
1082 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1083 {
1084         long decimal_val, frac_val;
1085         int prtn;
1086
1087         if (count < 10)
1088                 return -EINVAL;
1089
1090         decimal_val = val / mult;
1091         prtn = snprintf(buffer, count, "%ld", decimal_val);
1092         frac_val = val % mult;
1093
1094         if (prtn < (count - 4) && frac_val > 0) {
1095                 long temp_frac;
1096                 int i, temp_mult = 1, frac_bits = 0;
1097
1098                 temp_frac = frac_val * 10;
1099                 buffer[prtn++] = '.';
1100                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1101                         buffer[prtn++] ='0';
1102                         temp_frac *= 10;
1103                         frac_bits++;
1104                 }
1105                 /*
1106                   Need to think these cases :
1107                         1. #echo x.00 > /proc/xxx       output result : x
1108                         2. #echo x.0x > /proc/xxx       output result : x.0x
1109                         3. #echo x.x0 > /proc/xxx       output result : x.x
1110                         4. #echo x.xx > /proc/xxx       output result : x.xx
1111                         Only reserved 2bits fraction.       
1112                  */
1113                 for (i = 0; i < (5 - prtn); i++)
1114                         temp_mult *= 10;
1115
1116                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1117                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1118
1119                 prtn--;
1120                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1121                         prtn--;
1122                         if (buffer[prtn] == '.') {
1123                                 prtn--;
1124                                 break;
1125                         }
1126                 }
1127                 prtn++;
1128         }
1129         buffer[prtn++] ='\n';
1130         return prtn;
1131 }
1132
1133 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1134 {
1135         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1136 }
1137
1138 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1139                               __u64 *val, int mult)
1140 {
1141         char kernbuf[22], *end, *pbuf;
1142         __u64 whole, frac = 0, units;
1143         unsigned frac_d = 1;
1144
1145         if (count > (sizeof(kernbuf) - 1) )
1146                 return -EINVAL;
1147
1148         if (copy_from_user(kernbuf, buffer, count))
1149                 return -EFAULT;
1150
1151         kernbuf[count] = '\0';
1152         pbuf = kernbuf;
1153         if (*pbuf == '-') {
1154                 mult = -mult;
1155                 pbuf++;
1156         }
1157
1158         whole = simple_strtoull(pbuf, &end, 10);
1159         if (pbuf == end)
1160                 return -EINVAL;
1161
1162         if (end != NULL && *end == '.') {
1163                 int i;
1164                 pbuf = end + 1;
1165
1166                 /* need to limit frac_d to a __u32 */
1167                 if (strlen(pbuf) > 10)
1168                         pbuf[10] = '\0';
1169
1170                 frac = simple_strtoull(pbuf, &end, 10);
1171                 /* count decimal places */
1172                 for (i = 0; i < (end - pbuf); i++)
1173                         frac_d *= 10;
1174         }
1175
1176         units = 1;
1177         switch(*end) {
1178         case 'p': case 'P':
1179                 units <<= 10;
1180         case 't': case 'T':
1181                 units <<= 10;
1182         case 'g': case 'G':
1183                 units <<= 10;
1184         case 'm': case 'M':
1185                 units <<= 10;
1186         case 'k': case 'K':
1187                 units <<= 10;
1188         }
1189         /* Specified units override the multiplier */
1190         if (units)
1191                 mult = mult < 0 ? -units : units;
1192
1193         frac *= mult;
1194         do_div(frac, frac_d);
1195         *val = whole * mult + frac;
1196         return 0;
1197 }
1198
1199 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1200                        char *name, mode_t mode,
1201                        struct file_operations *seq_fops, void *data)
1202 {
1203         struct proc_dir_entry *entry;
1204         ENTRY;
1205
1206         entry = create_proc_entry(name, mode, parent);
1207         if (entry == NULL)
1208                 RETURN(-ENOMEM);
1209         entry->proc_fops = seq_fops;
1210         entry->data = data;
1211
1212         RETURN(0);
1213 }
1214 EXPORT_SYMBOL(lprocfs_seq_create);
1215
1216 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1217                                       mode_t mode,
1218                                       struct file_operations *seq_fops,
1219                                       void *data)
1220 {
1221         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1222                                    mode, seq_fops, data));
1223 }
1224 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1225
1226 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1227 {
1228         if (value >= OBD_HIST_MAX)
1229                 value = OBD_HIST_MAX - 1;
1230
1231         spin_lock(&oh->oh_lock);
1232         oh->oh_buckets[value]++;
1233         spin_unlock(&oh->oh_lock);
1234 }
1235 EXPORT_SYMBOL(lprocfs_oh_tally);
1236
1237 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1238 {
1239         unsigned int val;
1240
1241         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1242                 ;
1243
1244         lprocfs_oh_tally(oh, val);
1245 }
1246 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1247
1248 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1249 {
1250         unsigned long ret = 0;
1251         int i;
1252
1253         for (i = 0; i < OBD_HIST_MAX; i++)
1254                 ret +=  oh->oh_buckets[i];
1255         return ret;
1256 }
1257 EXPORT_SYMBOL(lprocfs_oh_sum);
1258
1259 void lprocfs_oh_clear(struct obd_histogram *oh)
1260 {
1261         spin_lock(&oh->oh_lock);
1262         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1263         spin_unlock(&oh->oh_lock);
1264 }
1265 EXPORT_SYMBOL(lprocfs_oh_clear);
1266
1267 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1268                                    int count, int *eof, void *data)
1269 {
1270         struct obd_device *obd = data;
1271         int len = 0, size;
1272
1273         LASSERT(obd != NULL);
1274         LASSERT(count >= 0);
1275
1276         /* Set start of user data returned to
1277            page + off since the user may have
1278            requested to read much smaller than
1279            what we need to read */
1280         *start = page + off;
1281
1282         /* We know we are allocated a page here.
1283            Also we know that this function will
1284            not need to write more than a page
1285            so we can truncate at CFS_PAGE_SIZE.  */
1286         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1287
1288         /* Initialize the page */
1289         memset(page, 0, size);
1290
1291         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1292                 goto out;
1293
1294         if (obd->obd_max_recoverable_clients == 0) {
1295                 lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n");
1296                 goto fclose;
1297         }
1298
1299         /* sampled unlocked, but really... */
1300         if (obd->obd_recovering == 0) {
1301                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1302                         goto out;
1303
1304                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1305                     obd->obd_recovery_start) <= 0)
1306                         goto out;
1307
1308                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1309                     obd->obd_recovery_end) <= 0)
1310                         goto out;
1311
1312                 /* Number of clients have have completed recovery */
1313                 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1314                     obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1315                         goto out;
1316
1317                 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1318                     obd->obd_recoverable_clients) <= 0)
1319                         goto out;
1320
1321                 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1322                     obd->obd_next_recovery_transno - 1) <= 0)
1323                         goto out;
1324
1325                 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1326                 goto fclose;
1327         }
1328
1329         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1330                 goto out;
1331
1332         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1333             obd->obd_recovery_start) <= 0)
1334                 goto out;
1335
1336         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1337                                  CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
1338                                  obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
1339                 goto out;
1340
1341         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1342                                 obd->obd_connected_clients,
1343                                 obd->obd_max_recoverable_clients) <= 0)
1344                 goto out;
1345
1346         /* Number of clients have have completed recovery */
1347         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1348                                  obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1349                                  obd->obd_max_recoverable_clients) <= 0)
1350                 goto out;
1351
1352         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1353                                  obd->obd_replayed_requests) <= 0)
1354                 goto out;
1355
1356         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1357                                  obd->obd_requests_queued_for_recovery) <= 0)
1358                 goto out;
1359
1360         lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", obd->obd_next_recovery_transno);
1361
1362 fclose:
1363         *eof = 1;
1364 out:
1365         return min(count, len - (int)off);
1366 }
1367 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1368
1369 EXPORT_SYMBOL(lprocfs_register);
1370 EXPORT_SYMBOL(lprocfs_srch);
1371 EXPORT_SYMBOL(lprocfs_remove);
1372 EXPORT_SYMBOL(lprocfs_add_vars);
1373 EXPORT_SYMBOL(lprocfs_obd_setup);
1374 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1375 EXPORT_SYMBOL(lprocfs_alloc_stats);
1376 EXPORT_SYMBOL(lprocfs_free_stats);
1377 EXPORT_SYMBOL(lprocfs_clear_stats);
1378 EXPORT_SYMBOL(lprocfs_register_stats);
1379 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1380 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1381 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1382 EXPORT_SYMBOL(lprocfs_exp_setup);
1383 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1384
1385 EXPORT_SYMBOL(lprocfs_rd_u64);
1386 EXPORT_SYMBOL(lprocfs_rd_atomic);
1387 EXPORT_SYMBOL(lprocfs_rd_uuid);
1388 EXPORT_SYMBOL(lprocfs_rd_name);
1389 EXPORT_SYMBOL(lprocfs_rd_fstype);
1390 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1391 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1392 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1393 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1394
1395 EXPORT_SYMBOL(lprocfs_rd_blksize);
1396 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1397 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1398 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1399 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1400 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1401
1402 EXPORT_SYMBOL(lprocfs_write_helper);
1403 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1404 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1405 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1406 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1407 #endif /* LPROCFS*/