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