Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lprocfs_status.c
37  *
38  * Author: Hariharan Thantry <thantry@users.sourceforge.net>
39  */
40
41 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44 #define DEBUG_SUBSYSTEM S_CLASS
45
46 #ifndef __KERNEL__
47 # include <liblustre.h>
48 #endif
49
50 #include <obd_class.h>
51 #include <lprocfs_status.h>
52 #include <lustre_fsfilt.h>
53
54 #if defined(LPROCFS)
55
56 #define MAX_STRING_SIZE 128
57
58 /* for bug 10866, global variable */
59 DECLARE_RWSEM(_lprocfs_lock);
60 EXPORT_SYMBOL(_lprocfs_lock);
61
62 int lprocfs_seq_release(struct inode *inode, struct file *file)
63 {
64         LPROCFS_EXIT();
65         return seq_release(inode, file);
66 }
67 EXPORT_SYMBOL(lprocfs_seq_release);
68
69 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
70                                     const char *name)
71 {
72         struct proc_dir_entry *temp;
73
74         if (head == NULL)
75                 return NULL;
76         LPROCFS_ENTRY();
77
78         temp = head->subdir;
79         while (temp != NULL) {
80                 if (strcmp(temp->name, name) == 0) {
81                         LPROCFS_EXIT();
82                         return temp;
83                 }
84
85                 temp = temp->next;
86         }
87         LPROCFS_EXIT();
88         return NULL;
89 }
90
91 /* lprocfs API calls */
92
93 /* Function that emulates snprintf but also has the side effect of advancing
94    the page pointer for the next write into the buffer, incrementing the total
95    length written to the buffer, and decrementing the size left in the
96    buffer. */
97 static int lprocfs_obd_snprintf(char **page, int end, int *len,
98                                 const char *format, ...)
99 {
100         va_list list;
101         int n;
102
103         if (*len >= end)
104                 return 0;
105
106         va_start(list, format);
107         n = vsnprintf(*page, end - *len, format, list);
108         va_end(list);
109
110         *page += n; *len += n;
111         return n;
112 }
113
114 cfs_proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
115                                          char *name,
116                                          read_proc_t *read_proc,
117                                          write_proc_t *write_proc,
118                                          void *data,
119                                          struct file_operations *fops)
120 {
121         cfs_proc_dir_entry_t *proc;
122         mode_t mode = 0;
123
124         if (root == NULL || name == NULL)
125                 return ERR_PTR(-EINVAL);
126         if (read_proc)
127                 mode = 0444;
128         if (write_proc)
129                 mode |= 0200;
130         if (fops)
131                 mode = 0644;
132         proc = create_proc_entry(name, mode, root);
133         if (!proc) {
134                 CERROR("LprocFS: No memory to create /proc entry %s", name);
135                 return ERR_PTR(-ENOMEM);
136         }
137         proc->read_proc = read_proc;
138         proc->write_proc = write_proc;
139         proc->data = data;
140         if (fops)
141                 proc->proc_fops = fops;
142         return proc;
143 }
144
145 struct proc_dir_entry *lprocfs_add_symlink(const char *name,
146                         struct proc_dir_entry *parent, const char *dest)
147 {
148         struct proc_dir_entry *entry;
149
150         if (parent == NULL || dest == NULL)
151                 return NULL;
152
153         entry = proc_symlink(name, parent, dest);
154         if (entry == NULL)
155                 CERROR("LprocFS: Could not create symbolic link from %s to %s",
156                         name, dest);
157         return entry;
158 }
159
160 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
161                                  size_t size, loff_t *ppos)
162 {
163         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
164         char *page, *start = NULL;
165         int rc = 0, eof = 1, count;
166
167         if (*ppos >= CFS_PAGE_SIZE)
168                 return 0;
169
170         page = (char *)__get_free_page(GFP_KERNEL);
171         if (page == NULL)
172                 return -ENOMEM;
173
174         LPROCFS_ENTRY();
175         OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
176         if (!dp->deleted && dp->read_proc)
177                 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
178                                    &eof, dp->data);
179         LPROCFS_EXIT();
180         if (rc <= 0)
181                 goto out;
182
183         /* for lustre proc read, the read count must be less than PAGE_SIZE */
184         LASSERT(eof == 1);
185
186         if (start == NULL) {
187                 rc -= *ppos;
188                 if (rc < 0)
189                         rc = 0;
190                 if (rc == 0)
191                         goto out;
192                 start = page + *ppos;
193         } else if (start < page) {
194                 start = page;
195         }
196
197         count = (rc < size) ? rc : size;
198         if (copy_to_user(buf, start, count)) {
199                 rc = -EFAULT;
200                 goto out;
201         }
202         *ppos += count;
203
204 out:
205         free_page((unsigned long)page);
206         return rc;
207 }
208
209 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
210 {
211         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
212         int rc = -EIO;
213
214         LPROCFS_ENTRY();
215         if (!dp->deleted && dp->write_proc)
216                 rc = dp->write_proc(f, buf, size, dp->data);
217         LPROCFS_EXIT();
218         return rc;
219 }
220
221 static struct file_operations lprocfs_generic_fops = {
222         .owner = THIS_MODULE,
223         .read = lprocfs_fops_read,
224         .write = lprocfs_fops_write,
225 };
226
227 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
228 {
229         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
230         struct obd_device *obd = dp->data;
231
232         atomic_inc(&obd->obd_evict_inprogress);
233
234         return 0;
235 }
236
237 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
238 {
239         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
240         struct obd_device *obd = dp->data;
241
242         atomic_dec(&obd->obd_evict_inprogress);
243         wake_up(&obd->obd_evict_inprogress_waitq);
244
245         return 0;
246 }
247
248 struct file_operations lprocfs_evict_client_fops = {
249         .owner = THIS_MODULE,
250         .read = lprocfs_fops_read,
251         .write = lprocfs_fops_write,
252         .open = lprocfs_evict_client_open,
253         .release = lprocfs_evict_client_release,
254 };
255 EXPORT_SYMBOL(lprocfs_evict_client_fops);
256
257 /**
258  * Add /proc entries.
259  *
260  * \param root [in]  The parent proc entry on which new entry will be added.
261  * \param list [in]  Array of proc entries to be added.
262  * \param data [in]  The argument to be passed when entries read/write routines
263  *                   are called through /proc file.
264  *
265  * \retval 0   on success
266  *         < 0 on error
267  */
268 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
269                      void *data)
270 {
271         if (root == NULL || list == NULL)
272                 return -EINVAL;
273
274         while (list->name != NULL) {
275                 struct proc_dir_entry *cur_root, *proc;
276                 char *pathcopy, *cur, *next, pathbuf[64];
277                 int pathsize = strlen(list->name) + 1;
278
279                 proc = NULL;
280                 cur_root = root;
281
282                 /* need copy of path for strsep */
283                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
284                         OBD_ALLOC(pathcopy, pathsize);
285                         if (pathcopy == NULL)
286                                 return -ENOMEM;
287                 } else {
288                         pathcopy = pathbuf;
289                 }
290
291                 next = pathcopy;
292                 strcpy(pathcopy, list->name);
293
294                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
295                         if (*cur =='\0') /* skip double/trailing "/" */
296                                 continue;
297
298                         proc = lprocfs_srch(cur_root, cur);
299                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
300                                cur_root->name, cur, next,
301                                (proc ? "exists" : "new"));
302                         if (next != NULL) {
303                                 cur_root = (proc ? proc :
304                                             proc_mkdir(cur, cur_root));
305                         } else if (proc == NULL) {
306                                 mode_t mode = 0;
307                                 if (list->proc_mode != 0000) {
308                                         mode = list->proc_mode;
309                                 } else {
310                                         if (list->read_fptr)
311                                                 mode = 0444;
312                                         if (list->write_fptr)
313                                                 mode |= 0200;
314                                 }
315                                 proc = create_proc_entry(cur, mode, cur_root);
316                         }
317                 }
318
319                 if (pathcopy != pathbuf)
320                         OBD_FREE(pathcopy, pathsize);
321
322                 if (cur_root == NULL || proc == NULL) {
323                         CERROR("LprocFS: No memory to create /proc entry %s",
324                                list->name);
325                         return -ENOMEM;
326                 }
327
328                 if (list->fops)
329                         proc->proc_fops = list->fops;
330                 else
331                         proc->proc_fops = &lprocfs_generic_fops;
332                 proc->read_proc = list->read_fptr;
333                 proc->write_proc = list->write_fptr;
334                 proc->data = (list->data ? list->data : data);
335                 list++;
336         }
337         return 0;
338 }
339
340 void lprocfs_remove(struct proc_dir_entry **rooth)
341 {
342         struct proc_dir_entry *root = *rooth;
343         struct proc_dir_entry *temp = root;
344         struct proc_dir_entry *rm_entry;
345         struct proc_dir_entry *parent;
346
347         if (!root)
348                 return;
349         *rooth = NULL;
350
351         parent = root->parent;
352         LASSERT(parent != NULL);
353         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
354
355         while (1) {
356                 while (temp->subdir != NULL)
357                         temp = temp->subdir;
358
359                 rm_entry = temp;
360                 temp = temp->parent;
361
362                 /* Memory corruption once caused this to fail, and
363                    without this LASSERT we would loop here forever. */
364                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
365                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
366                          rm_entry->name, (int)strlen(rm_entry->name));
367
368                 /* Now, the rm_entry->deleted flags is protected
369                  * by _lprocfs_lock. */
370                 rm_entry->data = NULL;
371                 remove_proc_entry(rm_entry->name, temp);
372                 if (temp == parent)
373                         break;
374         }
375         LPROCFS_WRITE_EXIT();
376 }
377
378 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
379 {
380         LASSERT(parent != NULL);
381         remove_proc_entry(name, parent);
382 }
383
384 struct proc_dir_entry *lprocfs_register(const char *name,
385                                         struct proc_dir_entry *parent,
386                                         struct lprocfs_vars *list, void *data)
387 {
388         struct proc_dir_entry *newchild;
389
390         newchild = lprocfs_srch(parent, name);
391         if (newchild != NULL) {
392                 CERROR(" Lproc: Attempting to register %s more than once \n",
393                        name);
394                 return ERR_PTR(-EALREADY);
395         }
396
397         newchild = proc_mkdir(name, parent);
398         if (newchild != NULL && list != NULL) {
399                 int rc = lprocfs_add_vars(newchild, list, data);
400                 if (rc) {
401                         lprocfs_remove(&newchild);
402                         return ERR_PTR(rc);
403                 }
404         }
405         return newchild;
406 }
407
408 /* Generic callbacks */
409 int lprocfs_rd_uint(char *page, char **start, off_t off,
410                     int count, int *eof, void *data)
411 {
412         unsigned int *temp = data;
413         return snprintf(page, count, "%u\n", *temp);
414 }
415
416 int lprocfs_wr_uint(struct file *file, const char *buffer,
417                     unsigned long count, void *data)
418 {
419         unsigned *p = data;
420         char dummy[MAX_STRING_SIZE + 1], *end;
421         unsigned long tmp;
422
423         dummy[MAX_STRING_SIZE] = '\0';
424         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
425                 return -EFAULT;
426
427         tmp = simple_strtoul(dummy, &end, 0);
428         if (dummy == end)
429                 return -EINVAL;
430
431         *p = (unsigned int)tmp;
432         return count;
433 }
434
435 int lprocfs_rd_u64(char *page, char **start, off_t off,
436                    int count, int *eof, void *data)
437 {
438         LASSERT(data != NULL);
439         *eof = 1;
440         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
441 }
442
443 int lprocfs_rd_atomic(char *page, char **start, off_t off,
444                    int count, int *eof, void *data)
445 {
446         atomic_t *atom = data;
447         LASSERT(atom != NULL);
448         *eof = 1;
449         return snprintf(page, count, "%d\n", atomic_read(atom));
450 }
451
452 int lprocfs_wr_atomic(struct file *file, const char *buffer,
453                       unsigned long count, void *data)
454 {
455         atomic_t *atm = data;
456         int val = 0;
457         int rc;
458
459         rc = lprocfs_write_helper(buffer, count, &val);
460         if (rc < 0)
461                 return rc;
462
463         if (val <= 0)
464                 return -ERANGE;
465
466         atomic_set(atm, val);
467         return count;
468 }
469
470 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
471                     int *eof, void *data)
472 {
473         struct obd_device *obd = data;
474
475         LASSERT(obd != NULL);
476         *eof = 1;
477         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
478 }
479
480 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
481                     int *eof, void *data)
482 {
483         struct obd_device *dev = data;
484
485         LASSERT(dev != NULL);
486         LASSERT(dev->obd_name != NULL);
487         *eof = 1;
488         return snprintf(page, count, "%s\n", dev->obd_name);
489 }
490
491 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
492                       void *data)
493 {
494         struct obd_device *obd = data;
495
496         LASSERT(obd != NULL);
497         LASSERT(obd->obd_fsops != NULL);
498         LASSERT(obd->obd_fsops->fs_type != NULL);
499         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
500 }
501
502 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
503                        int *eof, void *data)
504 {
505         struct obd_statfs osfs;
506         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
507                             OBD_STATFS_NODELAY);
508         if (!rc) {
509                 *eof = 1;
510                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
511         }
512         return rc;
513 }
514
515 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
516                            int *eof, void *data)
517 {
518         struct obd_statfs osfs;
519         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
520                             OBD_STATFS_NODELAY);
521         if (!rc) {
522                 __u32 blk_size = osfs.os_bsize >> 10;
523                 __u64 result = osfs.os_blocks;
524
525                 while (blk_size >>= 1)
526                         result <<= 1;
527
528                 *eof = 1;
529                 rc = snprintf(page, count, LPU64"\n", result);
530         }
531         return rc;
532 }
533
534 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
535                           int *eof, void *data)
536 {
537         struct obd_statfs osfs;
538         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
539                             OBD_STATFS_NODELAY);
540         if (!rc) {
541                 __u32 blk_size = osfs.os_bsize >> 10;
542                 __u64 result = osfs.os_bfree;
543
544                 while (blk_size >>= 1)
545                         result <<= 1;
546
547                 *eof = 1;
548                 rc = snprintf(page, count, LPU64"\n", result);
549         }
550         return rc;
551 }
552
553 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
554                            int *eof, void *data)
555 {
556         struct obd_statfs osfs;
557         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
558                             OBD_STATFS_NODELAY);
559         if (!rc) {
560                 __u32 blk_size = osfs.os_bsize >> 10;
561                 __u64 result = osfs.os_bavail;
562
563                 while (blk_size >>= 1)
564                         result <<= 1;
565
566                 *eof = 1;
567                 rc = snprintf(page, count, LPU64"\n", result);
568         }
569         return rc;
570 }
571
572 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
573                           int *eof, void *data)
574 {
575         struct obd_statfs osfs;
576         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
577                             OBD_STATFS_NODELAY);
578         if (!rc) {
579                 *eof = 1;
580                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
581         }
582
583         return rc;
584 }
585
586 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
587                          int *eof, void *data)
588 {
589         struct obd_statfs osfs;
590         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
591                             OBD_STATFS_NODELAY);
592         if (!rc) {
593                 *eof = 1;
594                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
595         }
596         return rc;
597 }
598
599 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
600                            int *eof, void *data)
601 {
602         struct obd_device *obd = data;
603         struct obd_import *imp;
604         char *imp_state_name = NULL;
605         int rc = 0;
606
607         LASSERT(obd != NULL);
608         LPROCFS_CLIMP_CHECK(obd);
609         imp = obd->u.cli.cl_import;
610         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
611         *eof = 1;
612         rc = snprintf(page, count, "%s\t%s%s\n",
613                       obd2cli_tgt(obd), imp_state_name,
614                       imp->imp_deactive ? "\tDEACTIVATED" : "");
615
616         LPROCFS_CLIMP_EXIT(obd);
617         return rc;
618 }
619
620 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
621                          int *eof,  void *data)
622 {
623         struct obd_device *obd = data;
624         struct ptlrpc_connection *conn;
625         int rc = 0;
626
627         LASSERT(obd != NULL);
628
629         LPROCFS_CLIMP_CHECK(obd);
630         conn = obd->u.cli.cl_import->imp_connection;
631         LASSERT(conn != NULL);
632         *eof = 1;
633         if (obd->u.cli.cl_import) {
634                 rc = snprintf(page, count, "%s\n",
635                               conn->c_remote_uuid.uuid);
636         } else {
637                 rc = snprintf(page, count, "%s\n", "<none>");
638         }
639
640         LPROCFS_CLIMP_EXIT(obd);
641         return rc;
642 }
643
644 #define flag2str(flag) \
645         if (imp->imp_##flag && max - len > 0) \
646                 len += snprintf(str + len, max - len, " " #flag);
647         
648 /**
649  * Append a space separated list of current set flags to str.
650  */
651 static int obd_import_flags2str(struct obd_import *imp, char *str, 
652                                           int max)
653 {
654         int len = 0;
655         
656         if (imp->imp_obd->obd_no_recov)
657                 len += snprintf(str, max - len, " no_recov");
658
659         flag2str(invalid);
660         flag2str(deactive);
661         flag2str(replayable);
662         flag2str(pingable);
663         flag2str(recon_bk);
664         flag2str(last_recon);
665         return len;
666 }
667 #undef flags2str
668
669 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
670                       int *eof, void *data)
671 {
672         struct obd_device *obd = (struct obd_device *)data;
673         struct obd_import *imp;
674         char *imp_state_name = NULL;
675         int rc = 0;
676
677         LASSERT(obd != NULL);
678         LPROCFS_CLIMP_CHECK(obd);
679         imp = obd->u.cli.cl_import;
680         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
681         *eof = 1;
682
683         rc = snprintf(page, count, 
684                       "import: %s\n"
685                       "    target: %s@%s\n"
686                       "    state: %s\n"
687                       "    inflight: %u\n"
688                       "    conn_cnt: %u\n"
689                       "    generation: %u\n"
690                       "    inval_cnt: %u\n"
691                       "    last_replay_transno: "LPU64"\n"
692                       "    peer_committed_transno: "LPU64"\n"
693                       "    last_trasno_checked: "LPU64"\n"
694                       "    flags:",
695                       obd->obd_name,
696                       obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
697                       imp_state_name,
698                       atomic_read(&imp->imp_inflight),
699                       imp->imp_conn_cnt,
700                       imp->imp_generation,
701                       atomic_read(&imp->imp_inval_count),
702                       imp->imp_last_replay_transno,
703                       imp->imp_peer_committed_transno,
704                       imp->imp_last_transno_checked);
705         rc += obd_import_flags2str(imp, page + rc, count - rc);
706         rc += snprintf(page+rc, count - rc, "\n");
707         LPROCFS_CLIMP_EXIT(obd);
708         return rc;
709 }
710
711 int lprocfs_at_hist_helper(char *page, int count, int rc,
712                            struct adaptive_timeout *at)
713 {
714         int i;
715         for (i = 0; i < AT_BINS; i++)
716                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
717         rc += snprintf(page + rc, count - rc, "\n");
718         return rc;
719 }
720
721 /* See also ptlrpc_lprocfs_rd_timeouts */
722 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
723                         int *eof, void *data)
724 {
725         struct obd_device *obd = (struct obd_device *)data;
726         struct obd_import *imp;
727         unsigned int cur, worst;
728         time_t now, worstt;
729         struct dhms ts;
730         int i, rc = 0;
731
732         LASSERT(obd != NULL);
733         LPROCFS_CLIMP_CHECK(obd);
734         imp = obd->u.cli.cl_import;
735         *eof = 1;
736
737         now = cfs_time_current_sec();
738
739         /* Some network health info for kicks */
740         s2dhms(&ts, now - imp->imp_last_reply_time);
741         rc += snprintf(page + rc, count - rc,
742                        "%-10s : %ld, "DHMS_FMT" ago\n",
743                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
744
745
746         cur = at_get(&imp->imp_at.iat_net_latency);
747         worst = imp->imp_at.iat_net_latency.at_worst_ever;
748         worstt = imp->imp_at.iat_net_latency.at_worst_time;
749         s2dhms(&ts, now - worstt);
750         rc += snprintf(page + rc, count - rc,
751                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
752                        "network", cur, worst, worstt, DHMS_VARS(&ts));
753         rc = lprocfs_at_hist_helper(page, count, rc,
754                                     &imp->imp_at.iat_net_latency);
755
756         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
757                 if (imp->imp_at.iat_portal[i] == 0)
758                         break;
759                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
760                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
761                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
762                 s2dhms(&ts, now - worstt);
763                 rc += snprintf(page + rc, count - rc,
764                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
765                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
766                                cur, worst, worstt, DHMS_VARS(&ts));
767                 rc = lprocfs_at_hist_helper(page, count, rc,
768                                           &imp->imp_at.iat_service_estimate[i]);
769         }
770
771         LPROCFS_CLIMP_EXIT(obd);
772         return rc;
773 }
774
775 static const char *obd_connect_names[] = {
776         "read_only",
777         "lov_index",
778         "unused",
779         "write_grant",
780         "server_lock",
781         "version",
782         "request_portal",
783         "acl",
784         "xattr",
785         "create_on_write",
786         "truncate_lock",
787         "initial_transno",
788         "inode_bit_locks",
789         "join_file",
790         "getattr_by_fid",
791         "no_oh_for_devices",
792         "local_client",
793         "remote_client",
794         "max_byte_per_rpc",
795         "64bit_qdata",
796         "mds_capability",
797         "oss_capability",
798         "early_lock_cancel",
799         "size_on_mds",
800         "adaptive_timeouts",
801         "lru_resize",
802         "mds_mds_connection",
803         "real_conn",
804         "change_qunit_size",
805         "alt_checksum_algorithm",
806         "fid_is_enabled",
807         "version_recovery",
808         "pools",
809         NULL
810 };
811
812 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
813                              int count, int *eof, void *data)
814 {
815         struct obd_device *obd = data;
816         __u64 mask = 1, flags;
817         int i, ret = 0;
818
819         LPROCFS_CLIMP_CHECK(obd);
820         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
821         ret = snprintf(page, count, "flags="LPX64"\n", flags);
822         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
823                 if (flags & mask)
824                         ret += snprintf(page + ret, count - ret, "%s\n",
825                                         obd_connect_names[i]);
826         }
827         if (flags & ~(mask - 1))
828                 ret += snprintf(page + ret, count - ret,
829                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
830
831         LPROCFS_CLIMP_EXIT(obd);
832         return ret;
833 }
834 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
835
836 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
837                            int *eof,  void *data)
838 {
839         struct obd_device *obd = data;
840
841         LASSERT(obd != NULL);
842         *eof = 1;
843         return snprintf(page, count, "%u\n", obd->obd_num_exports);
844 }
845
846 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
847                        int *eof, void *data)
848 {
849         struct obd_type *class = (struct obd_type*) data;
850
851         LASSERT(class != NULL);
852         *eof = 1;
853         return snprintf(page, count, "%d\n", class->typ_refcnt);
854 }
855
856 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
857 {
858         int rc = 0;
859
860         LASSERT(obd != NULL);
861         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
862         LASSERT(obd->obd_type->typ_procroot != NULL);
863
864         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
865                                                obd->obd_type->typ_procroot,
866                                                list, obd);
867         if (IS_ERR(obd->obd_proc_entry)) {
868                 rc = PTR_ERR(obd->obd_proc_entry);
869                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
870                 obd->obd_proc_entry = NULL;
871         }
872         return rc;
873 }
874
875 int lprocfs_obd_cleanup(struct obd_device *obd)
876 {
877         if (!obd)
878                 return -EINVAL;
879         if (obd->obd_proc_exports_entry) {
880                 /* Should be no exports left */
881                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
882                 lprocfs_remove(&obd->obd_proc_exports_entry);
883         }
884         lprocfs_remove(&obd->obd_proc_entry);
885         return 0;
886 }
887
888 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
889 {
890         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
891                client_stat->nid_proc, client_stat->nid_stats,
892                client_stat->nid_brw_stats);
893
894         LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
895                  client_stat->nid_exp_ref_count);
896
897         hlist_del_init(&client_stat->nid_hash);
898
899         if (client_stat->nid_proc)
900                 lprocfs_remove(&client_stat->nid_proc);
901
902         if (client_stat->nid_stats)
903                 lprocfs_free_stats(&client_stat->nid_stats);
904
905         if (client_stat->nid_brw_stats)
906                 OBD_FREE_PTR(client_stat->nid_brw_stats);
907
908         if (client_stat->nid_ldlm_stats)
909                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
910
911         OBD_FREE_PTR(client_stat);
912         return;
913
914 }
915
916 void lprocfs_free_per_client_stats(struct obd_device *obd)
917 {
918         struct nid_stat *stat;
919         ENTRY;
920
921         /* we need extra list - because hash_exit called to early */
922         /* not need locking because all clients is died */
923         while(!list_empty(&obd->obd_nid_stats)) {
924                 stat = list_entry(obd->obd_nid_stats.next,
925                                   struct nid_stat, nid_list);
926                 list_del_init(&stat->nid_list);
927                 lprocfs_free_client_stats(stat);
928         }
929
930         EXIT;
931 }
932
933 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
934                                           enum lprocfs_stats_flags flags)
935 {
936         struct lprocfs_stats *stats;
937         unsigned int percpusize;
938         unsigned int i, j;
939         unsigned int num_cpu;
940
941         if (num == 0)
942                 return NULL;
943
944         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
945                 num_cpu = 1;
946         else
947                 num_cpu = num_possible_cpus();
948
949         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
950         if (stats == NULL)
951                 return NULL;
952
953         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
954                 stats->ls_flags = flags;
955                 spin_lock_init(&stats->ls_lock);
956                 /* Use this lock only if there are no percpu areas */
957         } else {
958                 stats->ls_flags = 0;
959         }
960
961         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
962         if (num_cpu > 1)
963                 percpusize = L1_CACHE_ALIGN(percpusize);
964
965         for (i = 0; i < num_cpu; i++) {
966                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
967                 if (stats->ls_percpu[i] == NULL) {
968                         for (j = 0; j < i; j++) {
969                                 OBD_FREE(stats->ls_percpu[j], percpusize);
970                                 stats->ls_percpu[j] = NULL;
971                         }
972                         break;
973                 }
974         }
975         if (stats->ls_percpu[0] == NULL) {
976                 OBD_FREE(stats, offsetof(typeof(*stats),
977                                          ls_percpu[num_cpu]));
978                 return NULL;
979         }
980
981         stats->ls_num = num;
982         return stats;
983 }
984
985 void lprocfs_free_stats(struct lprocfs_stats **statsh)
986 {
987         struct lprocfs_stats *stats = *statsh;
988         unsigned int num_cpu;
989         unsigned int percpusize;
990         unsigned int i;
991
992         if (stats == NULL || stats->ls_num == 0)
993                 return;
994         *statsh = NULL;
995
996         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
997                 num_cpu = 1;
998         else
999                 num_cpu = num_possible_cpus();
1000
1001         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1002         if (num_cpu > 1)
1003                 percpusize = L1_CACHE_ALIGN(percpusize);
1004         for (i = 0; i < num_cpu; i++)
1005                 OBD_FREE(stats->ls_percpu[i], percpusize);
1006         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1007 }
1008
1009 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1010 {
1011         struct lprocfs_counter *percpu_cntr;
1012         int i,j;
1013         unsigned int num_cpu;
1014
1015         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1016
1017         for (i = 0; i < num_cpu; i++) {
1018                 for (j = 0; j < stats->ls_num; j++) {
1019                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1020                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1021                         percpu_cntr->lc_count = 0;
1022                         percpu_cntr->lc_sum = 0;
1023                         percpu_cntr->lc_min = LC_MIN_INIT;
1024                         percpu_cntr->lc_max = 0;
1025                         percpu_cntr->lc_sumsquare = 0;
1026                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1027                 }
1028         }
1029
1030         lprocfs_stats_unlock(stats);
1031 }
1032
1033 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1034                                        size_t len, loff_t *off)
1035 {
1036         struct seq_file *seq = file->private_data;
1037         struct lprocfs_stats *stats = seq->private;
1038
1039         lprocfs_clear_stats(stats);
1040
1041         return len;
1042 }
1043
1044 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1045 {
1046         struct lprocfs_stats *stats = p->private;
1047         /* return 1st cpu location */
1048         return (*pos >= stats->ls_num) ? NULL :
1049                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1050 }
1051
1052 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1053 {
1054 }
1055
1056 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1057 {
1058         struct lprocfs_stats *stats = p->private;
1059         ++*pos;
1060         return (*pos >= stats->ls_num) ? NULL :
1061                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1062 }
1063
1064 /* seq file export of one lprocfs counter */
1065 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1066 {
1067        struct lprocfs_stats *stats = p->private;
1068        struct lprocfs_counter  *cntr = v;
1069        struct lprocfs_counter  t, ret = { .lc_min = LC_MIN_INIT };
1070        int i, idx, rc = 0;
1071        unsigned int num_cpu;
1072
1073        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1074                struct timeval now;
1075                do_gettimeofday(&now);
1076                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1077                                "snapshot_time", now.tv_sec, now.tv_usec);
1078                if (rc < 0)
1079                        return rc;
1080        }
1081        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1082
1083        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1084                num_cpu = 1;
1085        else
1086                num_cpu = num_possible_cpus();
1087
1088        for (i = 0; i < num_cpu; i++) {
1089                struct lprocfs_counter *percpu_cntr =
1090                        &(stats->ls_percpu[i])->lp_cntr[idx];
1091                int centry;
1092
1093                do {
1094                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1095                        t.lc_count = percpu_cntr->lc_count;
1096                        t.lc_sum = percpu_cntr->lc_sum;
1097                        t.lc_min = percpu_cntr->lc_min;
1098                        t.lc_max = percpu_cntr->lc_max;
1099                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1100                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1101                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1102                ret.lc_count += t.lc_count;
1103                ret.lc_sum += t.lc_sum;
1104                if (t.lc_min < ret.lc_min)
1105                        ret.lc_min = t.lc_min;
1106                if (t.lc_max > ret.lc_max)
1107                        ret.lc_max = t.lc_max;
1108                ret.lc_sumsquare += t.lc_sumsquare;
1109        }
1110
1111        if (ret.lc_count == 0)
1112                goto out;
1113
1114        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1115                        ret.lc_count, cntr->lc_units);
1116        if (rc < 0)
1117                goto out;
1118
1119        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1120                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1121                                ret.lc_min, ret.lc_max, ret.lc_sum);
1122                if (rc < 0)
1123                        goto out;
1124                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1125                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1126                if (rc < 0)
1127                        goto out;
1128        }
1129        rc = seq_printf(p, "\n");
1130  out:
1131        return (rc < 0) ? rc : 0;
1132 }
1133
1134 struct seq_operations lprocfs_stats_seq_sops = {
1135         start: lprocfs_stats_seq_start,
1136         stop:  lprocfs_stats_seq_stop,
1137         next:  lprocfs_stats_seq_next,
1138         show:  lprocfs_stats_seq_show,
1139 };
1140
1141 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1142 {
1143         struct proc_dir_entry *dp = PDE(inode);
1144         struct seq_file *seq;
1145         int rc;
1146
1147         LPROCFS_ENTRY_AND_CHECK(dp);
1148         rc = seq_open(file, &lprocfs_stats_seq_sops);
1149         if (rc) {
1150                 LPROCFS_EXIT();
1151                 return rc;
1152         }
1153         seq = file->private_data;
1154         seq->private = dp->data;
1155         return 0;
1156 }
1157
1158 struct file_operations lprocfs_stats_seq_fops = {
1159         .owner   = THIS_MODULE,
1160         .open    = lprocfs_stats_seq_open,
1161         .read    = seq_read,
1162         .write   = lprocfs_stats_seq_write,
1163         .llseek  = seq_lseek,
1164         .release = lprocfs_seq_release,
1165 };
1166
1167 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1168                            struct lprocfs_stats *stats)
1169 {
1170         struct proc_dir_entry *entry;
1171         LASSERT(root != NULL);
1172
1173         entry = create_proc_entry(name, 0644, root);
1174         if (entry == NULL)
1175                 return -ENOMEM;
1176         entry->proc_fops = &lprocfs_stats_seq_fops;
1177         entry->data = stats;
1178         return 0;
1179 }
1180
1181 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1182                           unsigned conf, const char *name, const char *units)
1183 {
1184         struct lprocfs_counter *c;
1185         int i;
1186         unsigned int num_cpu;
1187
1188         LASSERT(stats != NULL);
1189
1190         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1191
1192         for (i = 0; i < num_cpu; i++) {
1193                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1194                 c->lc_config = conf;
1195                 c->lc_count = 0;
1196                 c->lc_sum = 0;
1197                 c->lc_min = LC_MIN_INIT;
1198                 c->lc_max = 0;
1199                 c->lc_name = name;
1200                 c->lc_units = units;
1201         }
1202
1203         lprocfs_stats_unlock(stats);
1204 }
1205 EXPORT_SYMBOL(lprocfs_counter_init);
1206
1207 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1208 do {                                                                       \
1209         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1210         LASSERT(coffset < stats->ls_num);                                  \
1211         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1212 } while (0)
1213
1214 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1215 {
1216         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1217         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1218         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1219         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1220         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1221         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1222         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1223         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1224         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1225         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1226         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1227         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1228         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1229         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1230         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1231         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1232         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1233         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1234         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1235         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1236         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1237         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1238         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1239         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1240         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1241         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1242         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1243         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1244         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1245         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1246         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1247         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1248         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1249         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1250         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1251         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1252         LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1253         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1254         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1255         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1256         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1257         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1258         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1259         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1260         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1261         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1262         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1263         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1264         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1265         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1266         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1267         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1268         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1269         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1270         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1271         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1272         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1273         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1274         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1275         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1276         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1277         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1278         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1279         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1280         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1281         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1282         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1283         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1284         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1285         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1286         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1287         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1288         LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1289         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1290         LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1291         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1292         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1293         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1294         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1295 }
1296
1297 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1298 {
1299         struct lprocfs_stats *stats;
1300         unsigned int num_stats;
1301         int rc, i;
1302
1303         LASSERT(obd->obd_stats == NULL);
1304         LASSERT(obd->obd_proc_entry != NULL);
1305         LASSERT(obd->obd_cntr_base == 0);
1306
1307         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1308                 num_private_stats - 1 /* o_owner */;
1309         stats = lprocfs_alloc_stats(num_stats, 0);
1310         if (stats == NULL)
1311                 return -ENOMEM;
1312
1313         lprocfs_init_ops_stats(num_private_stats, stats);
1314
1315         for (i = num_private_stats; i < num_stats; i++) {
1316                 /* If this LBUGs, it is likely that an obd
1317                  * operation was added to struct obd_ops in
1318                  * <obd.h>, and that the corresponding line item
1319                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1320                  * is missing from the list above. */
1321                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1322                          "Missing obd_stat initializer obd_op "
1323                          "operation at offset %d.\n", i - num_private_stats);
1324         }
1325         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1326         if (rc < 0) {
1327                 lprocfs_free_stats(&stats);
1328         } else {
1329                 obd->obd_stats  = stats;
1330                 obd->obd_cntr_base = num_private_stats;
1331         }
1332         return rc;
1333 }
1334
1335 void lprocfs_free_obd_stats(struct obd_device *obd)
1336 {
1337         if (obd->obd_stats)
1338                 lprocfs_free_stats(&obd->obd_stats);
1339 }
1340
1341 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1342 do {                                                                    \
1343         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1344         LASSERT(coffset < stats->ls_num);                               \
1345         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1346 } while (0)
1347
1348 int lprocfs_alloc_md_stats(struct obd_device *obd,
1349                            unsigned num_private_stats)
1350 {
1351         struct lprocfs_stats *stats;
1352         unsigned int num_stats;
1353         int rc, i;
1354
1355         LASSERT(obd->md_stats == NULL);
1356         LASSERT(obd->obd_proc_entry != NULL);
1357         LASSERT(obd->md_cntr_base == 0);
1358
1359         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1360                     num_private_stats;
1361         stats = lprocfs_alloc_stats(num_stats, 0);
1362         if (stats == NULL)
1363                 return -ENOMEM;
1364
1365         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1366         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1367         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1368         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1369         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1370         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1371         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1372         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1373         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1374         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1375         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1376         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1377         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1378         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1379         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1380         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1381         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1382         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1383         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1384         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1385         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1386         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1387         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1388         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1389         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1390         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1391         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1392         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1393         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1394         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1395
1396         for (i = num_private_stats; i < num_stats; i++) {
1397                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1398                         CERROR("Missing md_stat initializer md_op "
1399                                "operation at offset %d. Aborting.\n",
1400                                i - num_private_stats);
1401                         LBUG();
1402                 }
1403         }
1404         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1405         if (rc < 0) {
1406                 lprocfs_free_stats(&stats);
1407         } else {
1408                 obd->md_stats  = stats;
1409                 obd->md_cntr_base = num_private_stats;
1410         }
1411         return rc;
1412 }
1413
1414 void lprocfs_free_md_stats(struct obd_device *obd)
1415 {
1416         struct lprocfs_stats *stats = obd->md_stats;
1417
1418         if (stats != NULL) {
1419                 obd->md_stats = NULL;
1420                 obd->md_cntr_base = 0;
1421                 lprocfs_free_stats(&stats);
1422         }
1423 }
1424
1425 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1426 {
1427         lprocfs_counter_init(ldlm_stats,
1428                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1429                              0, "ldlm_enqueue", "reqs");
1430         lprocfs_counter_init(ldlm_stats,
1431                              LDLM_CONVERT - LDLM_FIRST_OPC,
1432                              0, "ldlm_convert", "reqs");
1433         lprocfs_counter_init(ldlm_stats,
1434                              LDLM_CANCEL - LDLM_FIRST_OPC,
1435                              0, "ldlm_cancel", "reqs");
1436         lprocfs_counter_init(ldlm_stats,
1437                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1438                              0, "ldlm_bl_callback", "reqs");
1439         lprocfs_counter_init(ldlm_stats,
1440                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1441                              0, "ldlm_cp_callback", "reqs");
1442         lprocfs_counter_init(ldlm_stats,
1443                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1444                              0, "ldlm_gl_callback", "reqs");
1445 }
1446
1447 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1448                          int *eof,  void *data)
1449 {
1450         struct obd_export *exp = data;
1451         LASSERT(exp != NULL);
1452         *eof = 1;
1453         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1454 }
1455
1456 struct exp_uuid_cb_data {
1457         char                   *page;
1458         int                     count;
1459         int                    *eof;
1460         int                    *len;
1461 };
1462
1463 static void
1464 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1465                             int count, int *eof, int *len)
1466 {
1467         cb_data->page = page;
1468         cb_data->count = count;
1469         cb_data->eof = eof;
1470         cb_data->len = len;
1471 }
1472
1473 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1474 {
1475         struct obd_export *exp = (struct obd_export *)obj;
1476         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1477
1478         if (exp->exp_nid_stats)
1479                 *data->len += snprintf((data->page + *data->len),
1480                                        data->count, "%s\n",
1481                                        obd_uuid2str(&exp->exp_client_uuid));
1482 }
1483
1484 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1485                         int *eof,  void *data)
1486 {
1487         struct nid_stat *stats = (struct nid_stat *)data;
1488         struct exp_uuid_cb_data cb_data;
1489         struct obd_device *obd = stats->nid_obd;
1490         int len = 0;
1491
1492         *eof = 1;
1493         page[0] = '\0';
1494         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1495         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1496                                  lprocfs_exp_print_uuid, &cb_data);
1497         return (*cb_data.len);
1498 }
1499
1500 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1501 {
1502         struct exp_uuid_cb_data *data = cb_data;
1503         struct obd_export       *exp = obj;
1504         lustre_hash_t           *lh;
1505
1506         lh = exp->exp_lock_hash;
1507         if (lh) {
1508                 if (!*data->len)
1509                         *data->len += lustre_hash_debug_header(data->page,
1510                                                                data->count);
1511
1512                 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1513                                                     data->count);
1514         }
1515 }
1516
1517 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1518                         int *eof,  void *data)
1519 {
1520         struct nid_stat *stats = (struct nid_stat *)data;
1521         struct exp_uuid_cb_data cb_data;
1522         struct obd_device *obd = stats->nid_obd;
1523         int len = 0;
1524
1525         *eof = 1;
1526         page[0] = '\0';
1527         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1528
1529         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1530                                  lprocfs_exp_print_hash, &cb_data);
1531         return (*cb_data.len);
1532 }
1533
1534 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1535                                         int count, int *eof,  void *data)
1536 {
1537         *eof = 1;
1538         return snprintf(page, count, "%s\n",
1539                         "Write into this file to clear all nid stats and "
1540                         "stale nid entries");
1541 }
1542 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1543
1544 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1545 {
1546         struct nid_stat *stat = obj;
1547         int i;
1548         ENTRY;
1549         /* object has only hash + iterate_all references.
1550          * add/delete blocked by hash bucket lock */
1551         CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1552         if (stat->nid_exp_ref_count == 2) {
1553                 hlist_del_init(&stat->nid_hash);
1554                 stat->nid_exp_ref_count--;
1555                 spin_lock(&stat->nid_obd->obd_nid_lock);
1556                 list_move(&stat->nid_list, data);
1557                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1558                 EXIT;
1559                 return;
1560         }
1561         /* we has reference to object - only clear data*/
1562         if (stat->nid_stats)
1563                 lprocfs_clear_stats(stat->nid_stats);
1564
1565         if (stat->nid_brw_stats) {
1566                 for (i = 0; i < BRW_LAST; i++)
1567                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1568         }
1569         EXIT;
1570         return;
1571 }
1572
1573 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1574                                          unsigned long count, void *data)
1575 {
1576         struct obd_device *obd = (struct obd_device *)data;
1577         struct nid_stat *client_stat;
1578         CFS_LIST_HEAD(free_list);
1579
1580         lustre_hash_for_each(obd->obd_nid_stats_hash,
1581                              lprocfs_nid_stats_clear_write_cb, &free_list);
1582
1583         while (!list_empty(&free_list)) {
1584                 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1585                 list_del_init(&client_stat->nid_list);
1586                 lprocfs_free_client_stats(client_stat);
1587         }
1588
1589         return count;
1590 }
1591 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1592
1593 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1594 {
1595         struct nid_stat *new_stat, *old_stat;
1596         struct nid_stat_uuid *new_ns_uuid;
1597         struct obd_device *obd = NULL;
1598         cfs_proc_dir_entry_t *entry;
1599         int rc = 0;
1600         ENTRY;
1601
1602         *newnid = 0;
1603
1604         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1605             !exp->exp_obd->obd_nid_stats_hash)
1606                 RETURN(-EINVAL);
1607
1608         /* not test against zero because eric say:
1609          * You may only test nid against another nid, or LNET_NID_ANY.
1610          * Anything else is nonsense.*/
1611         if (!nid || *nid == LNET_NID_ANY)
1612                 RETURN(0);
1613
1614         obd = exp->exp_obd;
1615
1616         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1617
1618         OBD_ALLOC_PTR(new_stat);
1619         if (new_stat == NULL)
1620                 RETURN(-ENOMEM);
1621
1622         OBD_ALLOC_PTR(new_ns_uuid);
1623         if (new_ns_uuid == NULL) {
1624                 OBD_FREE_PTR(new_stat);
1625                 RETURN(-ENOMEM);
1626         }
1627         CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1628         strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1629                 sizeof(struct obd_uuid));
1630
1631         CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1632         new_stat->nid               = *nid;
1633         new_stat->nid_obd           = exp->exp_obd;
1634         new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1635
1636        /* protect competitive add to list, not need locking on destroy */
1637         spin_lock(&obd->obd_nid_lock);
1638         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1639         spin_unlock(&obd->obd_nid_lock);
1640
1641         old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1642                                               nid, &new_stat->nid_hash);
1643         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1644                old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1645
1646         /* Return -EALREADY here so that we know that the /proc
1647          * entry already has been created */
1648         if (old_stat != new_stat) {
1649                 struct nid_stat_uuid *tmp_uuid;
1650                 int found = 0;
1651
1652                 exp->exp_nid_stats = old_stat;
1653                 /* We need to decrement the refcount if the uuid was
1654                  * already in our list */
1655                 spin_lock(&obd->obd_nid_lock);
1656                 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1657                                     ns_uuid_list) {
1658                         if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1659                                                         &exp->exp_client_uuid)){
1660                                 found = 1;
1661                                 --old_stat->nid_exp_ref_count;
1662                                 break;
1663                         }
1664                 }
1665
1666                 if (!found)
1667                         list_add(&new_ns_uuid->ns_uuid_list,
1668                                  &old_stat->nid_uuid_list);
1669                 else
1670                         OBD_FREE_PTR(new_ns_uuid);
1671
1672                 spin_unlock(&obd->obd_nid_lock);
1673
1674                 GOTO(destroy_new, rc = -EALREADY);
1675         }
1676         /* not found - create */
1677         new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1678                                               obd->obd_proc_exports_entry,
1679                                               NULL, NULL);
1680         if (new_stat->nid_proc == NULL) {
1681                 CERROR("Error making export directory for nid %s\n",
1682                        libcfs_nid2str(*nid));
1683                 GOTO(destroy_new_ns, rc = -ENOMEM);
1684         }
1685
1686         /* Add in uuid to our nid_stats list */
1687         spin_lock(&obd->obd_nid_lock);
1688         list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1689         spin_unlock(&obd->obd_nid_lock);
1690
1691         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1692                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1693         if (IS_ERR(entry)) {
1694                 CWARN("Error adding the NID stats file\n");
1695                 rc = PTR_ERR(entry);
1696                 GOTO(destroy_new_ns, rc);
1697         }
1698
1699         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1700                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1701         if (IS_ERR(entry)) {
1702                 CWARN("Error adding the hash file\n");
1703                 lprocfs_remove(&new_stat->nid_proc);
1704                 rc = PTR_ERR(entry);
1705                 GOTO(destroy_new_ns, rc);
1706         }
1707
1708         exp->exp_nid_stats = new_stat;
1709         *newnid = 1;
1710         RETURN(rc);
1711
1712 destroy_new_ns:
1713         lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1714         OBD_FREE_PTR(new_ns_uuid);
1715
1716 destroy_new:
1717         spin_lock(&obd->obd_nid_lock);
1718         list_del(&new_stat->nid_list);
1719         spin_unlock(&obd->obd_nid_lock);
1720         OBD_FREE_PTR(new_stat);
1721         RETURN(rc);
1722 }
1723
1724 int lprocfs_exp_cleanup(struct obd_export *exp)
1725 {
1726         struct nid_stat *stat = exp->exp_nid_stats;
1727         struct nid_stat_uuid *cursor, *tmp;
1728         int found = 0;
1729
1730         if(!stat || !exp->exp_obd)
1731                 RETURN(0);
1732
1733         spin_lock(&exp->exp_obd->obd_nid_lock);
1734         list_for_each_entry_safe(cursor, tmp,
1735                                  &stat->nid_uuid_list,
1736                                  ns_uuid_list) {
1737                 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1738                                               &exp->exp_client_uuid)) {
1739                         found = 1;
1740                         list_del(&cursor->ns_uuid_list);
1741                         OBD_FREE_PTR(cursor);
1742                         break;
1743                 }
1744         }
1745         spin_unlock(&exp->exp_obd->obd_nid_lock);
1746         if (!found)
1747                 CERROR("obd_export's client uuid %s are not found in its "
1748                        "nid_stats list\n", exp->exp_client_uuid.uuid);
1749
1750         stat->nid_exp_ref_count--;
1751         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1752
1753         exp->exp_nid_stats = NULL;
1754         lprocfs_free_md_stats(exp->exp_obd);
1755
1756         return 0;
1757 }
1758
1759 int lprocfs_write_helper(const char *buffer, unsigned long count,
1760                          int *val)
1761 {
1762         return lprocfs_write_frac_helper(buffer, count, val, 1);
1763 }
1764
1765 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1766                               int *val, int mult)
1767 {
1768         char kernbuf[20], *end, *pbuf;
1769
1770         if (count > (sizeof(kernbuf) - 1))
1771                 return -EINVAL;
1772
1773         if (copy_from_user(kernbuf, buffer, count))
1774                 return -EFAULT;
1775
1776         kernbuf[count] = '\0';
1777         pbuf = kernbuf;
1778         if (*pbuf == '-') {
1779                 mult = -mult;
1780                 pbuf++;
1781         }
1782
1783         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1784         if (pbuf == end)
1785                 return -EINVAL;
1786
1787         if (end != NULL && *end == '.') {
1788                 int temp_val, pow = 1;
1789                 int i;
1790
1791                 pbuf = end + 1;
1792                 if (strlen(pbuf) > 5)
1793                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1794
1795                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1796
1797                 if (pbuf < end) {
1798                         for (i = 0; i < (end - pbuf); i++)
1799                                 pow *= 10;
1800
1801                         *val += temp_val / pow;
1802                 }
1803         }
1804         return 0;
1805 }
1806
1807 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1808 {
1809         long decimal_val, frac_val;
1810         int prtn;
1811
1812         if (count < 10)
1813                 return -EINVAL;
1814
1815         decimal_val = val / mult;
1816         prtn = snprintf(buffer, count, "%ld", decimal_val);
1817         frac_val = val % mult;
1818
1819         if (prtn < (count - 4) && frac_val > 0) {
1820                 long temp_frac;
1821                 int i, temp_mult = 1, frac_bits = 0;
1822
1823                 temp_frac = frac_val * 10;
1824                 buffer[prtn++] = '.';
1825                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1826                         /* only reserved 2 bits fraction */
1827                         buffer[prtn++] ='0';
1828                         temp_frac *= 10;
1829                         frac_bits++;
1830                 }
1831                 /*
1832                  * Need to think these cases :
1833                  *      1. #echo x.00 > /proc/xxx       output result : x
1834                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1835                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1836                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1837                  *      Only reserved 2 bits fraction.
1838                  */
1839                 for (i = 0; i < (5 - prtn); i++)
1840                         temp_mult *= 10;
1841
1842                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1843                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1844                                  frac_val * temp_mult / mult);
1845
1846                 prtn--;
1847                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1848                         prtn--;
1849                         if (buffer[prtn] == '.') {
1850                                 prtn--;
1851                                 break;
1852                         }
1853                 }
1854                 prtn++;
1855         }
1856         buffer[prtn++] ='\n';
1857         return prtn;
1858 }
1859
1860 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1861 {
1862         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1863 }
1864
1865 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1866                               __u64 *val, int mult)
1867 {
1868         char kernbuf[22], *end, *pbuf;
1869         __u64 whole, frac = 0, units;
1870         unsigned frac_d = 1;
1871
1872         if (count > (sizeof(kernbuf) - 1) )
1873                 return -EINVAL;
1874
1875         if (copy_from_user(kernbuf, buffer, count))
1876                 return -EFAULT;
1877
1878         kernbuf[count] = '\0';
1879         pbuf = kernbuf;
1880         if (*pbuf == '-') {
1881                 mult = -mult;
1882                 pbuf++;
1883         }
1884
1885         whole = simple_strtoull(pbuf, &end, 10);
1886         if (pbuf == end)
1887                 return -EINVAL;
1888
1889         if (end != NULL && *end == '.') {
1890                 int i;
1891                 pbuf = end + 1;
1892
1893                 /* need to limit frac_d to a __u32 */
1894                 if (strlen(pbuf) > 10)
1895                         pbuf[10] = '\0';
1896
1897                 frac = simple_strtoull(pbuf, &end, 10);
1898                 /* count decimal places */
1899                 for (i = 0; i < (end - pbuf); i++)
1900                         frac_d *= 10;
1901         }
1902
1903         units = 1;
1904         switch(*end) {
1905         case 'p': case 'P':
1906                 units <<= 10;
1907         case 't': case 'T':
1908                 units <<= 10;
1909         case 'g': case 'G':
1910                 units <<= 10;
1911         case 'm': case 'M':
1912                 units <<= 10;
1913         case 'k': case 'K':
1914                 units <<= 10;
1915         }
1916         /* Specified units override the multiplier */
1917         if (units)
1918                 mult = mult < 0 ? -units : units;
1919
1920         frac *= mult;
1921         do_div(frac, frac_d);
1922         *val = whole * mult + frac;
1923         return 0;
1924 }
1925
1926 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1927                        struct file_operations *seq_fops, void *data)
1928 {
1929         struct proc_dir_entry *entry;
1930         ENTRY;
1931
1932         entry = create_proc_entry(name, mode, parent);
1933         if (entry == NULL)
1934                 RETURN(-ENOMEM);
1935         entry->proc_fops = seq_fops;
1936         entry->data = data;
1937
1938         RETURN(0);
1939 }
1940 EXPORT_SYMBOL(lprocfs_seq_create);
1941
1942 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1943                                       mode_t mode,
1944                                       struct file_operations *seq_fops,
1945                                       void *data)
1946 {
1947         return (lprocfs_seq_create(dev->obd_proc_entry, name,
1948                                    mode, seq_fops, data));
1949 }
1950 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1951
1952 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1953 {
1954         if (value >= OBD_HIST_MAX)
1955                 value = OBD_HIST_MAX - 1;
1956
1957         spin_lock(&oh->oh_lock);
1958         oh->oh_buckets[value]++;
1959         spin_unlock(&oh->oh_lock);
1960 }
1961 EXPORT_SYMBOL(lprocfs_oh_tally);
1962
1963 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1964 {
1965         unsigned int val;
1966
1967         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1968                 ;
1969
1970         lprocfs_oh_tally(oh, val);
1971 }
1972 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1973
1974 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1975 {
1976         unsigned long ret = 0;
1977         int i;
1978
1979         for (i = 0; i < OBD_HIST_MAX; i++)
1980                 ret +=  oh->oh_buckets[i];
1981         return ret;
1982 }
1983 EXPORT_SYMBOL(lprocfs_oh_sum);
1984
1985 void lprocfs_oh_clear(struct obd_histogram *oh)
1986 {
1987         spin_lock(&oh->oh_lock);
1988         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1989         spin_unlock(&oh->oh_lock);
1990 }
1991 EXPORT_SYMBOL(lprocfs_oh_clear);
1992
1993 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1994                         int count, int *eof, void *data)
1995 {
1996         struct obd_device *obd = data;
1997         int c = 0;
1998
1999         if (obd == NULL)
2000                 return 0;
2001
2002         c += lustre_hash_debug_header(page, count);
2003         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2004         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2005         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2006
2007         return c;
2008 }
2009 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2010
2011 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2012                                    int count, int *eof, void *data)
2013 {
2014         struct obd_device *obd = data;
2015         int len = 0, size;
2016
2017         LASSERT(obd != NULL);
2018         LASSERT(count >= 0);
2019
2020         /* Set start of user data returned to
2021            page + off since the user may have
2022            requested to read much smaller than
2023            what we need to read */
2024         *start = page + off;
2025
2026         /* We know we are allocated a page here.
2027            Also we know that this function will
2028            not need to write more than a page
2029            so we can truncate at CFS_PAGE_SIZE.  */
2030         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2031
2032         /* Initialize the page */
2033         memset(page, 0, size);
2034
2035         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2036                 goto out;
2037         if (obd->obd_max_recoverable_clients == 0) {
2038                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2039                         goto out;
2040
2041                 goto fclose;
2042         }
2043
2044         /* sampled unlocked, but really... */
2045         if (obd->obd_recovering == 0) {
2046                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2047                         goto out;
2048                 if (lprocfs_obd_snprintf(&page, size, &len,
2049                                          "recovery_start: %lu\n",
2050                                          obd->obd_recovery_start) <= 0)
2051                         goto out;
2052                 if (lprocfs_obd_snprintf(&page, size, &len,
2053                                          "recovery_duration: %lu\n",
2054                                          obd->obd_recovery_end -
2055                                          obd->obd_recovery_start) <= 0)
2056                         goto out;
2057                 /* Number of clients that have completed recovery */
2058                 if (lprocfs_obd_snprintf(&page, size, &len,
2059                                          "completed_clients: %d/%d\n",
2060                                          obd->obd_max_recoverable_clients -
2061                                          obd->obd_recoverable_clients,
2062                                          obd->obd_max_recoverable_clients) <= 0)
2063                         goto out;
2064                 if (lprocfs_obd_snprintf(&page, size, &len,
2065                                          "replayed_requests: %d\n",
2066                                          obd->obd_replayed_requests) <= 0)
2067                         goto out;
2068                 if (lprocfs_obd_snprintf(&page, size, &len,
2069                                          "last_transno: "LPD64"\n",
2070                                          obd->obd_next_recovery_transno - 1)<=0)
2071                         goto out;
2072                 goto fclose;
2073         }
2074
2075         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2076                 goto out;
2077         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2078                                  obd->obd_recovery_start) <= 0)
2079                 goto out;
2080         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2081                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2082                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2083                 goto out;
2084         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2085                                  obd->obd_connected_clients,
2086                                  obd->obd_max_recoverable_clients) <= 0)
2087                 goto out;
2088         /* Number of clients that have completed recovery */
2089         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2090                                  obd->obd_max_recoverable_clients -
2091                                  obd->obd_recoverable_clients,
2092                                  obd->obd_max_recoverable_clients) <= 0)
2093                 goto out;
2094         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2095                                  obd->obd_replayed_requests) <= 0)
2096                 goto out;
2097         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2098                                  obd->obd_requests_queued_for_recovery) <= 0)
2099                 goto out;
2100
2101         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2102                                  obd->obd_next_recovery_transno) <= 0)
2103                 goto out;
2104
2105 fclose:
2106         *eof = 1;
2107 out:
2108         return min(count, len - (int)off);
2109 }
2110 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2111
2112 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2113                                     int count, int *eof, void *data)
2114 {
2115         struct obd_device *obd = data;
2116         LASSERT(obd != NULL);
2117
2118         return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2119 }
2120 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2121
2122 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2123                                     unsigned long count, void *data)
2124 {
2125         struct obd_device *obd = data;
2126         int val, rc;
2127         LASSERT(obd != NULL);
2128
2129         rc = lprocfs_write_helper(buffer, count, &val);
2130         if (rc)
2131                 return rc;
2132
2133         obd->obd_recovery_max_time = val;
2134         return count;
2135 }
2136 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2137
2138 EXPORT_SYMBOL(lprocfs_register);
2139 EXPORT_SYMBOL(lprocfs_srch);
2140 EXPORT_SYMBOL(lprocfs_remove);
2141 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2142 EXPORT_SYMBOL(lprocfs_add_vars);
2143 EXPORT_SYMBOL(lprocfs_obd_setup);
2144 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2145 EXPORT_SYMBOL(lprocfs_add_simple);
2146 EXPORT_SYMBOL(lprocfs_add_symlink);
2147 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2148 EXPORT_SYMBOL(lprocfs_alloc_stats);
2149 EXPORT_SYMBOL(lprocfs_free_stats);
2150 EXPORT_SYMBOL(lprocfs_clear_stats);
2151 EXPORT_SYMBOL(lprocfs_register_stats);
2152 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2153 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2154 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2155 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2156 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2157 EXPORT_SYMBOL(lprocfs_exp_setup);
2158 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2159
2160 EXPORT_SYMBOL(lprocfs_rd_u64);
2161 EXPORT_SYMBOL(lprocfs_rd_atomic);
2162 EXPORT_SYMBOL(lprocfs_wr_atomic);
2163 EXPORT_SYMBOL(lprocfs_rd_uint);
2164 EXPORT_SYMBOL(lprocfs_wr_uint);
2165 EXPORT_SYMBOL(lprocfs_rd_uuid);
2166 EXPORT_SYMBOL(lprocfs_rd_name);
2167 EXPORT_SYMBOL(lprocfs_rd_fstype);
2168 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2169 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2170 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2171 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2172 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2173 EXPORT_SYMBOL(lprocfs_rd_import);
2174 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2175 EXPORT_SYMBOL(lprocfs_rd_blksize);
2176 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2177 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2178 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2179 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2180 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2181
2182 EXPORT_SYMBOL(lprocfs_write_helper);
2183 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2184 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2185 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2186 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2187 #endif /* LPROCFS*/