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