Whamcloud - gitweb
f4b685ea18f9540c3c51aaba8947f03262b52acc
[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         "change_qunit_size",
606         "alt_checksum_algorithm",
607         NULL
608 };
609
610 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
611                              int count, int *eof, void *data)
612 {
613         struct obd_device *obd = data;
614         __u64 mask = 1, flags;
615         int i, ret = 0;
616
617         LPROCFS_CLIMP_CHECK(obd);
618         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
619         ret = snprintf(page, count, "flags="LPX64"\n", flags);
620         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
621                 if (flags & mask)
622                         ret += snprintf(page + ret, count - ret, "%s\n",
623                                         obd_connect_names[i]);
624         }
625         if (flags & ~(mask - 1))
626                 ret += snprintf(page + ret, count - ret,
627                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
628
629         LPROCFS_CLIMP_EXIT(obd);
630         return ret;
631 }
632 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
633
634 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
635                            int *eof,  void *data)
636 {
637         struct obd_device *obd = (struct obd_device*)data;
638
639         LASSERT(obd != NULL);
640         *eof = 1;
641         return snprintf(page, count, "%u\n", obd->obd_num_exports);
642 }
643
644 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
645                        int *eof, void *data)
646 {
647         struct obd_type *class = (struct obd_type*) data;
648
649         LASSERT(class != NULL);
650         *eof = 1;
651         return snprintf(page, count, "%d\n", class->typ_refcnt);
652 }
653
654 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
655 {
656         int rc = 0;
657
658         LASSERT(obd != NULL);
659         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
660         LASSERT(obd->obd_type->typ_procroot != NULL);
661
662         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
663                                                obd->obd_type->typ_procroot,
664                                                list, obd);
665         if (IS_ERR(obd->obd_proc_entry)) {
666                 rc = PTR_ERR(obd->obd_proc_entry);
667                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
668                 obd->obd_proc_entry = NULL;
669         }
670         return rc;
671 }
672
673 int lprocfs_obd_cleanup(struct obd_device *obd)
674 {
675         if (!obd) 
676                 return -EINVAL;
677         if (obd->obd_proc_exports) {
678                 /* Should be no exports left */
679                 LASSERT(obd->obd_proc_exports->subdir == NULL);
680                 lprocfs_remove(&obd->obd_proc_exports);
681         }
682         lprocfs_remove(&obd->obd_proc_entry);
683         return 0;
684 }
685
686 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
687                                           enum lprocfs_stats_flags flags)
688 {
689         struct lprocfs_stats *stats;
690         struct lprocfs_percpu *percpu;
691         unsigned int percpusize;
692         unsigned int i;
693         unsigned int num_cpu;
694
695         if (num == 0)
696                 return NULL;
697
698         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
699                 num_cpu = 1;
700         else
701                 num_cpu = num_possible_cpus();
702
703         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
704         if (stats == NULL)
705                 return NULL;
706
707         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
708                 stats->ls_flags = flags;
709                 spin_lock_init(&stats->ls_lock);
710                 /* Use this lock only if there are no percpu areas */
711         } else {
712                 stats->ls_flags = 0;
713         }
714
715         percpusize = offsetof(typeof(*percpu), lp_cntr[num]);
716         if (num_cpu > 1)
717                 percpusize = L1_CACHE_ALIGN(percpusize);
718
719         stats->ls_percpu_size = num_cpu * percpusize;
720         OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
721         if (stats->ls_percpu[0] == NULL) {
722                 OBD_FREE(stats, offsetof(typeof(*stats),
723                                          ls_percpu[num_cpu]));
724                 return NULL;
725         }
726
727         stats->ls_num = num;
728         for (i = 1; i < num_cpu; i++)
729                 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
730                         percpusize;
731
732         return stats;
733 }
734
735 void lprocfs_free_stats(struct lprocfs_stats **statsh)
736 {
737         struct lprocfs_stats *stats = *statsh;
738         unsigned int num_cpu;
739
740         if (stats == NULL || stats->ls_num == 0)
741                 return;
742         *statsh = NULL;
743
744         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
745                 num_cpu = 1;
746         else
747                 num_cpu = num_possible_cpus();
748
749         OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
750         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
751 }
752
753 void lprocfs_clear_stats(struct lprocfs_stats *stats)
754 {
755         struct lprocfs_counter *percpu_cntr;
756         int i,j;
757         unsigned int num_cpu;
758
759         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
760
761         for (i = 0; i < num_cpu; i++) {
762                 for (j = 0; j < stats->ls_num; j++) {        
763                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
764                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
765                         percpu_cntr->lc_count = 0;
766                         percpu_cntr->lc_sum = 0;
767                         percpu_cntr->lc_min = ~(__u64)0;
768                         percpu_cntr->lc_max = 0;
769                         percpu_cntr->lc_sumsquare = 0;
770                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
771                 }
772         }
773
774         lprocfs_stats_unlock(stats);
775 }
776
777 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
778                                        size_t len, loff_t *off)
779 {
780         struct seq_file *seq = file->private_data;
781         struct lprocfs_stats *stats = seq->private;
782
783         lprocfs_clear_stats(stats);
784
785         return len;
786 }
787
788 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
789 {
790         struct lprocfs_stats *stats = p->private;
791         /* return 1st cpu location */
792         return (*pos >= stats->ls_num) ? NULL :
793                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
794 }
795
796 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
797 {
798 }
799
800 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
801 {
802         struct lprocfs_stats *stats = p->private;
803         ++*pos;
804         return (*pos >= stats->ls_num) ? NULL :
805                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
806 }
807
808 /* seq file export of one lprocfs counter */
809 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
810 {
811        struct lprocfs_stats *stats = p->private;
812        struct lprocfs_counter  *cntr = v;
813        struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
814        int i, idx, rc;
815        unsigned int num_cpu;
816
817        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
818                struct timeval now;
819                do_gettimeofday(&now);
820                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
821                                "snapshot_time", now.tv_sec, now.tv_usec);
822                if (rc < 0)
823                        return rc;
824        }
825        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
826
827        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
828                num_cpu = 1;
829        else
830                num_cpu = num_possible_cpus();
831
832        for (i = 0; i < num_cpu; i++) {
833                struct lprocfs_counter *percpu_cntr =
834                        &(stats->ls_percpu[i])->lp_cntr[idx];
835                int centry;
836
837                do {
838                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
839                        t.lc_count = percpu_cntr->lc_count;
840                        t.lc_sum = percpu_cntr->lc_sum;
841                        t.lc_min = percpu_cntr->lc_min;
842                        t.lc_max = percpu_cntr->lc_max;
843                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
844                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
845                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
846                ret.lc_count += t.lc_count;
847                ret.lc_sum += t.lc_sum;
848                if (t.lc_min < ret.lc_min)
849                        ret.lc_min = t.lc_min;
850                if (t.lc_max > ret.lc_max)
851                        ret.lc_max = t.lc_max;
852                ret.lc_sumsquare += t.lc_sumsquare;
853        }
854
855        rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
856                        ret.lc_count, cntr->lc_units);
857        if (rc < 0)
858                goto out;
859
860        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
861                rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
862                                ret.lc_min, ret.lc_max, ret.lc_sum);
863                if (rc < 0)
864                        goto out;
865                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
866                        rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
867                if (rc < 0)
868                        goto out;
869        }
870        rc = seq_printf(p, "\n");
871  out:
872        return (rc < 0) ? rc : 0;
873 }
874
875 struct seq_operations lprocfs_stats_seq_sops = {
876         start: lprocfs_stats_seq_start,
877         stop:  lprocfs_stats_seq_stop,
878         next:  lprocfs_stats_seq_next,
879         show:  lprocfs_stats_seq_show,
880 };
881
882 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
883 {
884         struct proc_dir_entry *dp = PDE(inode);
885         struct seq_file *seq;
886         int rc;
887
888         LPROCFS_ENTRY_AND_CHECK(dp);
889         rc = seq_open(file, &lprocfs_stats_seq_sops);
890         if (rc) {
891                 LPROCFS_EXIT();
892                 return rc;
893         }
894         seq = file->private_data;
895         seq->private = dp->data;
896         return 0;
897 }
898
899 struct file_operations lprocfs_stats_seq_fops = {
900         .owner   = THIS_MODULE,
901         .open    = lprocfs_stats_seq_open,
902         .read    = seq_read,
903         .write   = lprocfs_stats_seq_write,
904         .llseek  = seq_lseek,
905         .release = lprocfs_seq_release,
906 };
907
908 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
909                            struct lprocfs_stats *stats)
910 {
911         struct proc_dir_entry *entry;
912         LASSERT(root != NULL);
913
914         entry = create_proc_entry(name, 0644, root);
915         if (entry == NULL)
916                 return -ENOMEM;
917         entry->proc_fops = &lprocfs_stats_seq_fops;
918         entry->data = (void *)stats;
919         return 0;
920 }
921
922 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
923                           unsigned conf, const char *name, const char *units)
924 {
925         struct lprocfs_counter *c;
926         int i;
927         unsigned int num_cpu;
928
929         LASSERT(stats != NULL);
930
931         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
932
933         for (i = 0; i < num_cpu; i++) {
934                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
935                 c->lc_config = conf;
936                 c->lc_count = 0;
937                 c->lc_sum = 0;
938                 c->lc_min = ~(__u64)0;
939                 c->lc_max = 0;
940                 c->lc_name = name;
941                 c->lc_units = units;
942         }
943
944         lprocfs_stats_unlock(stats);
945 }
946 EXPORT_SYMBOL(lprocfs_counter_init);
947
948 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
949 do {                                                                       \
950         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
951         LASSERT(coffset < stats->ls_num);                                  \
952         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
953 } while (0)
954
955 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
956 {
957         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
958         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
959         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
960         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
961         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
962         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
963         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
964         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
965         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
966         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
967         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
968         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
969         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
970         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
971         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
972         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
973         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
974         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
975         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
976         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
977         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
978         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
979         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
980         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
981         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
982         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
983         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
984         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
985         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
986         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
987         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
988         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
989         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
990         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
991         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
992         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
993         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
994         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
995         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
996         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
997         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
998         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
999         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1000         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1001         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1002         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1003         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1004         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1005         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1006         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1007         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1008         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1009         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1010         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1011         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
1012         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1013         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1014         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1015         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1016         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1017         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1018         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1019         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1020         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1021         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1022         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1023         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1024         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1025         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1026 }
1027
1028 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1029 {
1030         struct lprocfs_stats *stats;
1031         unsigned int num_stats;
1032         int rc, i;
1033
1034         LASSERT(obd->obd_stats == NULL);
1035         LASSERT(obd->obd_proc_entry != NULL);
1036         LASSERT(obd->obd_cntr_base == 0);
1037
1038         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1039                 num_private_stats - 1 /* o_owner */;
1040         stats = lprocfs_alloc_stats(num_stats, 0);
1041         if (stats == NULL)
1042                 return -ENOMEM;
1043
1044         lprocfs_init_ops_stats(num_private_stats, stats);
1045
1046         for (i = num_private_stats; i < num_stats; i++) {
1047                 /* If this LBUGs, it is likely that an obd
1048                  * operation was added to struct obd_ops in
1049                  * <obd.h>, and that the corresponding line item
1050                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1051                  * is missing from the list above. */
1052                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1053                          "Missing obd_stat initializer obd_op "
1054                          "operation at offset %d.\n", i - num_private_stats);
1055         }
1056         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1057         if (rc < 0) {
1058                 lprocfs_free_stats(&stats);
1059         } else {
1060                 obd->obd_stats  = stats;
1061                 obd->obd_cntr_base = num_private_stats;
1062         }
1063         return rc;
1064 }
1065
1066 void lprocfs_free_obd_stats(struct obd_device *obd)
1067 {
1068         if (obd->obd_stats) 
1069                 lprocfs_free_stats(&obd->obd_stats);
1070 }
1071
1072 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1073 do {                                                                    \
1074         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1075         LASSERT(coffset < stats->ls_num);                               \
1076         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1077 } while (0)
1078
1079 int lprocfs_alloc_md_stats(struct obd_device *obd,
1080                            unsigned num_private_stats)
1081 {
1082         struct lprocfs_stats *stats;
1083         unsigned int num_stats;
1084         int rc, i;
1085
1086         LASSERT(obd->md_stats == NULL);
1087         LASSERT(obd->obd_proc_entry != NULL);
1088         LASSERT(obd->md_cntr_base == 0);
1089
1090         num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
1091                     num_private_stats;
1092         stats = lprocfs_alloc_stats(num_stats, 0);
1093         if (stats == NULL)
1094                 return -ENOMEM;
1095
1096         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1097         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1098         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1099         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1100         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1101         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1102         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1103         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1104         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1105         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1106         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1107         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1108         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1109         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1110         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1111         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1112         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1113         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1114         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1115         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1116         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1117         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1118         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1119         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1120         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1121         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1122         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1123         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1124
1125         for (i = num_private_stats; i < num_stats; i++) {
1126                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1127                         CERROR("Missing md_stat initializer md_op "
1128                                "operation at offset %d. Aborting.\n",
1129                                i - num_private_stats);
1130                         LBUG();
1131                 }
1132         }
1133         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1134         if (rc < 0) {
1135                 lprocfs_free_stats(&stats);
1136         } else {
1137                 obd->md_stats  = stats;
1138                 obd->md_cntr_base = num_private_stats;
1139         }
1140         return rc;
1141 }
1142
1143 void lprocfs_free_md_stats(struct obd_device *obd)
1144 {
1145         struct lprocfs_stats *stats = obd->md_stats;
1146
1147         if (stats != NULL) {
1148                 obd->md_stats = NULL;
1149                 lprocfs_free_stats(&stats);
1150         }
1151 }
1152
1153 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1154                          int *eof,  void *data)
1155 {
1156         struct obd_export *exp = (struct obd_export*)data;
1157         LASSERT(exp != NULL);
1158         *eof = 1;
1159         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1160 }
1161
1162 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1163                          int *eof,  void *data)
1164 {
1165         struct obd_export *exp = (struct obd_export*)data;
1166         LASSERT(exp != NULL);
1167         *eof = 1;
1168         return snprintf(page, count, "%s\n", 
1169                         obd_uuid2str(&exp->exp_client_uuid));
1170 }
1171         
1172 int lprocfs_exp_setup(struct obd_export *exp)
1173 {
1174         char name[sizeof (exp->exp_client_uuid.uuid) + 3];
1175         int i = 1, rc;
1176         ENTRY;
1177         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
1178                 RETURN(-EINVAL);
1179         mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1180         sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
1181         while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
1182                 /* We might add a new export before deleting the old one during 
1183                    an eviction (recovery-small 19a). Suckage. We
1184                    could block, or come up with a new name, or just give up. */
1185                 if (++i > 9) 
1186                         GOTO(out, rc = -EEXIST);
1187                 sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
1188         }
1189
1190         /* Create a proc entry for this export */
1191         exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
1192         if (!exp->exp_proc) {
1193                 CERROR("Error making export directory for %s\n", name);
1194                 GOTO(out, rc = -ENOMEM);
1195         }
1196
1197         /* Always add nid and uuid */
1198         rc = lprocfs_add_simple(exp->exp_proc, "nid",
1199                                 lprocfs_exp_rd_nid, NULL, exp);
1200         if (rc)
1201                 GOTO(out, rc);
1202         rc = lprocfs_add_simple(exp->exp_proc, "uuid",
1203                                 lprocfs_exp_rd_uuid, NULL, exp);
1204         if (rc)
1205                 GOTO(out, rc);
1206         /* Always add ldlm stats */
1207         exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC 
1208                                                   - LDLM_FIRST_OPC, 0);
1209         if (exp->exp_ldlm_stats == NULL) {
1210                 lprocfs_remove(&exp->exp_proc);
1211                 GOTO(out, rc = -ENOMEM);
1212         }
1213
1214         lprocfs_counter_init(exp->exp_ldlm_stats, 
1215                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1216                              0, "ldlm_enqueue", "reqs");
1217         lprocfs_counter_init(exp->exp_ldlm_stats, 
1218                              LDLM_CONVERT - LDLM_FIRST_OPC,
1219                              0, "ldlm_convert", "reqs");
1220         lprocfs_counter_init(exp->exp_ldlm_stats, 
1221                              LDLM_CANCEL - LDLM_FIRST_OPC,
1222                              0, "ldlm_cancel", "reqs");
1223         lprocfs_counter_init(exp->exp_ldlm_stats, 
1224                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1225                              0, "ldlm_bl_callback", "reqs");
1226         lprocfs_counter_init(exp->exp_ldlm_stats, 
1227                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1228                              0, "ldlm_cp_callback", "reqs");
1229         lprocfs_counter_init(exp->exp_ldlm_stats, 
1230                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1231                              0, "ldlm_gl_callback", "reqs");
1232         lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
1233                                exp->exp_ldlm_stats);
1234 out:
1235         mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1236         RETURN(rc);
1237 }
1238
1239 int lprocfs_exp_cleanup(struct obd_export *exp)
1240 {
1241         mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1242         lprocfs_remove(&exp->exp_proc);
1243         lprocfs_free_stats(&exp->exp_ops_stats);
1244         lprocfs_free_stats(&exp->exp_ldlm_stats);
1245         mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1246         return 0;
1247 }
1248
1249 int lprocfs_write_helper(const char *buffer, unsigned long count,
1250                          int *val)
1251 {
1252         return lprocfs_write_frac_helper(buffer, count, val, 1);
1253 }
1254
1255 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1256                               int *val, int mult)
1257 {
1258         char kernbuf[20], *end, *pbuf;
1259
1260         if (count > (sizeof(kernbuf) - 1))
1261                 return -EINVAL;
1262
1263         if (copy_from_user(kernbuf, buffer, count))
1264                 return -EFAULT;
1265
1266         kernbuf[count] = '\0';
1267         pbuf = kernbuf;
1268         if (*pbuf == '-') {
1269                 mult = -mult;
1270                 pbuf++;
1271         }
1272
1273         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1274         if (pbuf == end)
1275                 return -EINVAL;
1276
1277         if (end != NULL && *end == '.') {
1278                 int temp_val, pow = 1;
1279                 int i;
1280
1281                 pbuf = end + 1;
1282                 if (strlen(pbuf) > 5)
1283                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1284
1285                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1286
1287                 if (pbuf < end) {
1288                         for (i = 0; i < (end - pbuf); i++)
1289                                 pow *= 10;
1290
1291                         *val += temp_val / pow;
1292                 }
1293         }
1294         return 0;
1295 }
1296
1297 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1298 {
1299         long decimal_val, frac_val;
1300         int prtn;
1301
1302         if (count < 10)
1303                 return -EINVAL;
1304
1305         decimal_val = val / mult;
1306         prtn = snprintf(buffer, count, "%ld", decimal_val);
1307         frac_val = val % mult;
1308
1309         if (prtn < (count - 4) && frac_val > 0) {
1310                 long temp_frac;
1311                 int i, temp_mult = 1, frac_bits = 0;
1312
1313                 temp_frac = frac_val * 10;
1314                 buffer[prtn++] = '.';
1315                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1316                         buffer[prtn++] ='0';
1317                         temp_frac *= 10;
1318                         frac_bits++;
1319                 }
1320                 /*
1321                   Need to think these cases :
1322                         1. #echo x.00 > /proc/xxx       output result : x
1323                         2. #echo x.0x > /proc/xxx       output result : x.0x
1324                         3. #echo x.x0 > /proc/xxx       output result : x.x
1325                         4. #echo x.xx > /proc/xxx       output result : x.xx
1326                         Only reserved 2bits fraction.       
1327                  */
1328                 for (i = 0; i < (5 - prtn); i++)
1329                         temp_mult *= 10;
1330
1331                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1332                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1333
1334                 prtn--;
1335                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1336                         prtn--;
1337                         if (buffer[prtn] == '.') {
1338                                 prtn--;
1339                                 break;
1340                         }
1341                 }
1342                 prtn++;
1343         }
1344         buffer[prtn++] ='\n';
1345         return prtn;
1346 }
1347
1348 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1349 {
1350         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1351 }
1352
1353 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1354                               __u64 *val, int mult)
1355 {
1356         char kernbuf[22], *end, *pbuf;
1357         __u64 whole, frac = 0, units;
1358         unsigned frac_d = 1;
1359
1360         if (count > (sizeof(kernbuf) - 1) )
1361                 return -EINVAL;
1362
1363         if (copy_from_user(kernbuf, buffer, count))
1364                 return -EFAULT;
1365
1366         kernbuf[count] = '\0';
1367         pbuf = kernbuf;
1368         if (*pbuf == '-') {
1369                 mult = -mult;
1370                 pbuf++;
1371         }
1372
1373         whole = simple_strtoull(pbuf, &end, 10);
1374         if (pbuf == end)
1375                 return -EINVAL;
1376
1377         if (end != NULL && *end == '.') {
1378                 int i;
1379                 pbuf = end + 1;
1380
1381                 /* need to limit frac_d to a __u32 */
1382                 if (strlen(pbuf) > 10)
1383                         pbuf[10] = '\0';
1384
1385                 frac = simple_strtoull(pbuf, &end, 10);
1386                 /* count decimal places */
1387                 for (i = 0; i < (end - pbuf); i++)
1388                         frac_d *= 10;
1389         }
1390
1391         units = 1;
1392         switch(*end) {
1393         case 'p': case 'P':
1394                 units <<= 10;
1395         case 't': case 'T':
1396                 units <<= 10;
1397         case 'g': case 'G':
1398                 units <<= 10;
1399         case 'm': case 'M':
1400                 units <<= 10;
1401         case 'k': case 'K':
1402                 units <<= 10;
1403         }
1404         /* Specified units override the multiplier */
1405         if (units) 
1406                 mult = mult < 0 ? -units : units;
1407
1408         frac *= mult;
1409         do_div(frac, frac_d);
1410         *val = whole * mult + frac;
1411         return 0;
1412 }
1413
1414 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, 
1415                        char *name, mode_t mode,
1416                        struct file_operations *seq_fops, void *data)
1417 {
1418         struct proc_dir_entry *entry;
1419         ENTRY;
1420
1421         entry = create_proc_entry(name, mode, parent);
1422         if (entry == NULL)
1423                 RETURN(-ENOMEM);
1424         entry->proc_fops = seq_fops;
1425         entry->data = data;
1426
1427         RETURN(0);
1428 }
1429 EXPORT_SYMBOL(lprocfs_seq_create);
1430
1431 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1432                                       mode_t mode,
1433                                       struct file_operations *seq_fops,
1434                                       void *data)
1435 {
1436         return (lprocfs_seq_create(dev->obd_proc_entry, name, 
1437                                    mode, seq_fops, data));
1438 }
1439 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1440
1441 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1442 {
1443         if (value >= OBD_HIST_MAX)
1444                 value = OBD_HIST_MAX - 1;
1445
1446         spin_lock(&oh->oh_lock);
1447         oh->oh_buckets[value]++;
1448         spin_unlock(&oh->oh_lock);
1449 }
1450 EXPORT_SYMBOL(lprocfs_oh_tally);
1451
1452 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1453 {
1454         unsigned int val;
1455
1456         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1457                 ;
1458
1459         lprocfs_oh_tally(oh, val);
1460 }
1461 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1462
1463 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1464 {
1465         unsigned long ret = 0;
1466         int i;
1467
1468         for (i = 0; i < OBD_HIST_MAX; i++)
1469                 ret +=  oh->oh_buckets[i];
1470         return ret;
1471 }
1472 EXPORT_SYMBOL(lprocfs_oh_sum);
1473
1474 void lprocfs_oh_clear(struct obd_histogram *oh)
1475 {
1476         spin_lock(&oh->oh_lock);
1477         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1478         spin_unlock(&oh->oh_lock);
1479 }
1480 EXPORT_SYMBOL(lprocfs_oh_clear);
1481
1482 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1483                                    int count, int *eof, void *data)
1484 {
1485         struct obd_device *obd = data;
1486         int len = 0, size;
1487
1488         LASSERT(obd != NULL);
1489         LASSERT(count >= 0);
1490
1491         /* Set start of user data returned to
1492            page + off since the user may have
1493            requested to read much smaller than
1494            what we need to read */
1495         *start = page + off;
1496
1497         /* We know we are allocated a page here.
1498            Also we know that this function will
1499            not need to write more than a page
1500            so we can truncate at CFS_PAGE_SIZE.  */
1501         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1502
1503         /* Initialize the page */
1504         memset(page, 0, size);
1505
1506         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1507                 goto out;
1508
1509         if (obd->obd_max_recoverable_clients == 0) {
1510                 lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n");
1511                 goto fclose;
1512         }
1513
1514         /* sampled unlocked, but really... */
1515         if (obd->obd_recovering == 0) {
1516                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1517                         goto out;
1518
1519                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1520                     obd->obd_recovery_start) <= 0)
1521                         goto out;
1522
1523                 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1524                     obd->obd_recovery_end) <= 0)
1525                         goto out;
1526
1527                 /* Number of clients have have completed recovery */
1528                 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1529                     obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1530                         goto out;
1531
1532                 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1533                     obd->obd_recoverable_clients) <= 0)
1534                         goto out;
1535
1536                 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1537                     obd->obd_next_recovery_transno - 1) <= 0)
1538                         goto out;
1539
1540                 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1541                 goto fclose;
1542         }
1543
1544         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1545                 goto out;
1546
1547         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1548             obd->obd_recovery_start) <= 0)
1549                 goto out;
1550
1551         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1552                                  CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
1553                                  obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
1554                 goto out;
1555
1556         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1557                                 obd->obd_connected_clients,
1558                                 obd->obd_max_recoverable_clients) <= 0)
1559                 goto out;
1560
1561         /* Number of clients have have completed recovery */
1562         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1563                                  obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1564                                  obd->obd_max_recoverable_clients) <= 0)
1565                 goto out;
1566
1567         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1568                                  obd->obd_replayed_requests) <= 0)
1569                 goto out;
1570
1571         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1572                                  obd->obd_requests_queued_for_recovery) <= 0)
1573                 goto out;
1574
1575         lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", obd->obd_next_recovery_transno);
1576
1577 fclose:
1578         *eof = 1;
1579 out:
1580         return min(count, len - (int)off);
1581 }
1582 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1583
1584 EXPORT_SYMBOL(lprocfs_register);
1585 EXPORT_SYMBOL(lprocfs_srch);
1586 EXPORT_SYMBOL(lprocfs_remove);
1587 EXPORT_SYMBOL(lprocfs_add_vars);
1588 EXPORT_SYMBOL(lprocfs_obd_setup);
1589 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1590 EXPORT_SYMBOL(lprocfs_alloc_stats);
1591 EXPORT_SYMBOL(lprocfs_free_stats);
1592 EXPORT_SYMBOL(lprocfs_clear_stats);
1593 EXPORT_SYMBOL(lprocfs_register_stats);
1594 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1595 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1596 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1597 EXPORT_SYMBOL(lprocfs_exp_setup);
1598 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1599
1600 EXPORT_SYMBOL(lprocfs_rd_u64);
1601 EXPORT_SYMBOL(lprocfs_rd_atomic);
1602 EXPORT_SYMBOL(lprocfs_wr_atomic);
1603 EXPORT_SYMBOL(lprocfs_rd_uint);
1604 EXPORT_SYMBOL(lprocfs_wr_uint);
1605 EXPORT_SYMBOL(lprocfs_rd_uuid);
1606 EXPORT_SYMBOL(lprocfs_rd_name);
1607 EXPORT_SYMBOL(lprocfs_rd_fstype);
1608 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1609 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1610 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1611 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1612
1613 EXPORT_SYMBOL(lprocfs_rd_blksize);
1614 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1615 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1616 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1617 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1618 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1619
1620 EXPORT_SYMBOL(lprocfs_write_helper);
1621 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1622 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1623 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1624 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
1625 #endif /* LPROCFS*/