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