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