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