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                 lprocfs_free_stats(&stats);
1421         }
1422 }
1423
1424 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1425 {
1426         lprocfs_counter_init(ldlm_stats,
1427                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1428                              0, "ldlm_enqueue", "reqs");
1429         lprocfs_counter_init(ldlm_stats,
1430                              LDLM_CONVERT - LDLM_FIRST_OPC,
1431                              0, "ldlm_convert", "reqs");
1432         lprocfs_counter_init(ldlm_stats,
1433                              LDLM_CANCEL - LDLM_FIRST_OPC,
1434                              0, "ldlm_cancel", "reqs");
1435         lprocfs_counter_init(ldlm_stats,
1436                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1437                              0, "ldlm_bl_callback", "reqs");
1438         lprocfs_counter_init(ldlm_stats,
1439                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1440                              0, "ldlm_cp_callback", "reqs");
1441         lprocfs_counter_init(ldlm_stats,
1442                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1443                              0, "ldlm_gl_callback", "reqs");
1444 }
1445
1446 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1447                          int *eof,  void *data)
1448 {
1449         struct obd_export *exp = data;
1450         LASSERT(exp != NULL);
1451         *eof = 1;
1452         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1453 }
1454
1455 struct exp_uuid_cb_data {
1456         char                   *page;
1457         int                     count;
1458         int                    *eof;
1459         int                    *len;
1460 };
1461
1462 static void
1463 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1464                             int count, int *eof, int *len)
1465 {
1466         cb_data->page = page;
1467         cb_data->count = count;
1468         cb_data->eof = eof;
1469         cb_data->len = len;
1470 }
1471
1472 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1473 {
1474         struct obd_export *exp = (struct obd_export *)obj;
1475         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1476
1477         if (exp->exp_nid_stats)
1478                 *data->len += snprintf((data->page + *data->len),
1479                                        data->count, "%s\n",
1480                                        obd_uuid2str(&exp->exp_client_uuid));
1481 }
1482
1483 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1484                         int *eof,  void *data)
1485 {
1486         struct nid_stat *stats = (struct nid_stat *)data;
1487         struct exp_uuid_cb_data cb_data;
1488         struct obd_device *obd = stats->nid_obd;
1489         int len = 0;
1490
1491         *eof = 1;
1492         page[0] = '\0';
1493         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1494         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1495                                  lprocfs_exp_print_uuid, &cb_data);
1496         return (*cb_data.len);
1497 }
1498
1499 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1500 {
1501         struct exp_uuid_cb_data *data = cb_data;
1502         struct obd_export       *exp = obj;
1503         lustre_hash_t           *lh;
1504
1505         lh = exp->exp_lock_hash;
1506         if (lh) {
1507                 if (!*data->len)
1508                         *data->len += lustre_hash_debug_header(data->page,
1509                                                                data->count);
1510
1511                 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1512                                                     data->count);
1513         }
1514 }
1515
1516 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1517                         int *eof,  void *data)
1518 {
1519         struct nid_stat *stats = (struct nid_stat *)data;
1520         struct exp_uuid_cb_data cb_data;
1521         struct obd_device *obd = stats->nid_obd;
1522         int len = 0;
1523
1524         *eof = 1;
1525         page[0] = '\0';
1526         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1527
1528         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1529                                  lprocfs_exp_print_hash, &cb_data);
1530         return (*cb_data.len);
1531 }
1532
1533 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1534                                         int count, int *eof,  void *data)
1535 {
1536         *eof = 1;
1537         return snprintf(page, count, "%s\n",
1538                         "Write into this file to clear all nid stats and "
1539                         "stale nid entries");
1540 }
1541 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1542
1543 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1544 {
1545         struct nid_stat *stat = obj;
1546         int i;
1547         ENTRY;
1548         /* object has only hash + iterate_all references.
1549          * add/delete blocked by hash bucket lock */
1550         CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1551         if (stat->nid_exp_ref_count == 2) {
1552                 hlist_del_init(&stat->nid_hash);
1553                 stat->nid_exp_ref_count--;
1554                 spin_lock(&stat->nid_obd->obd_nid_lock);
1555                 list_move(&stat->nid_list, data);
1556                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1557                 EXIT;
1558                 return;
1559         }
1560         /* we has reference to object - only clear data*/
1561         if (stat->nid_stats)
1562                 lprocfs_clear_stats(stat->nid_stats);
1563
1564         if (stat->nid_brw_stats) {
1565                 for (i = 0; i < BRW_LAST; i++)
1566                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1567         }
1568         EXIT;
1569         return;
1570 }
1571
1572 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1573                                          unsigned long count, void *data)
1574 {
1575         struct obd_device *obd = (struct obd_device *)data;
1576         struct nid_stat *client_stat;
1577         CFS_LIST_HEAD(free_list);
1578
1579         lustre_hash_for_each(obd->obd_nid_stats_hash,
1580                              lprocfs_nid_stats_clear_write_cb, &free_list);
1581
1582         while (!list_empty(&free_list)) {
1583                 client_stat = list_entry(free_list.next, struct nid_stat, nid_list);
1584                 list_del_init(&client_stat->nid_list);
1585                 lprocfs_free_client_stats(client_stat);
1586         }
1587
1588         return count;
1589 }
1590 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1591
1592 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1593 {
1594         struct nid_stat *new_stat, *old_stat;
1595         struct nid_stat_uuid *new_ns_uuid;
1596         struct obd_device *obd = NULL;
1597         cfs_proc_dir_entry_t *entry;
1598         int rc = 0;
1599         ENTRY;
1600
1601         *newnid = 0;
1602
1603         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1604             !exp->exp_obd->obd_nid_stats_hash)
1605                 RETURN(-EINVAL);
1606
1607         /* not test against zero because eric say:
1608          * You may only test nid against another nid, or LNET_NID_ANY.
1609          * Anything else is nonsense.*/
1610         if (!nid || *nid == LNET_NID_ANY)
1611                 RETURN(0);
1612
1613         obd = exp->exp_obd;
1614
1615         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1616
1617         OBD_ALLOC_PTR(new_stat);
1618         if (new_stat == NULL)
1619                 RETURN(-ENOMEM);
1620
1621         OBD_ALLOC_PTR(new_ns_uuid);
1622         if (new_ns_uuid == NULL) {
1623                 OBD_FREE_PTR(new_stat);
1624                 RETURN(-ENOMEM);
1625         }
1626         CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1627         strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1628                 sizeof(struct obd_uuid));
1629
1630         CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1631         new_stat->nid               = *nid;
1632         new_stat->nid_obd           = exp->exp_obd;
1633         new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1634
1635        /* protect competitive add to list, not need locking on destroy */
1636         spin_lock(&obd->obd_nid_lock);
1637         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1638         spin_unlock(&obd->obd_nid_lock);
1639
1640         old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1641                                               nid, &new_stat->nid_hash);
1642         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1643                old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1644
1645         /* Return -EALREADY here so that we know that the /proc
1646          * entry already has been created */
1647         if (old_stat != new_stat) {
1648                 struct nid_stat_uuid *tmp_uuid;
1649                 int found = 0;
1650
1651                 exp->exp_nid_stats = old_stat;
1652                 /* We need to decrement the refcount if the uuid was
1653                  * already in our list */
1654                 spin_lock(&obd->obd_nid_lock);
1655                 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1656                                     ns_uuid_list) {
1657                         if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1658                                                         &exp->exp_client_uuid)){
1659                                 found = 1;
1660                                 --old_stat->nid_exp_ref_count;
1661                                 break;
1662                         }
1663                 }
1664
1665                 if (!found)
1666                         list_add(&new_ns_uuid->ns_uuid_list,
1667                                  &old_stat->nid_uuid_list);
1668                 else
1669                         OBD_FREE_PTR(new_ns_uuid);
1670
1671                 spin_unlock(&obd->obd_nid_lock);
1672
1673                 GOTO(destroy_new, rc = -EALREADY);
1674         }
1675         /* not found - create */
1676         new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1677                                               obd->obd_proc_exports_entry,
1678                                               NULL, NULL);
1679         if (new_stat->nid_proc == NULL) {
1680                 CERROR("Error making export directory for nid %s\n",
1681                        libcfs_nid2str(*nid));
1682                 GOTO(destroy_new_ns, rc = -ENOMEM);
1683         }
1684
1685         /* Add in uuid to our nid_stats list */
1686         spin_lock(&obd->obd_nid_lock);
1687         list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1688         spin_unlock(&obd->obd_nid_lock);
1689
1690         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1691                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1692         if (IS_ERR(entry)) {
1693                 CWARN("Error adding the NID stats file\n");
1694                 rc = PTR_ERR(entry);
1695                 GOTO(destroy_new_ns, rc);
1696         }
1697
1698         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1699                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1700         if (IS_ERR(entry)) {
1701                 CWARN("Error adding the hash file\n");
1702                 lprocfs_remove(&new_stat->nid_proc);
1703                 rc = PTR_ERR(entry);
1704                 GOTO(destroy_new_ns, rc);
1705         }
1706
1707         exp->exp_nid_stats = new_stat;
1708         *newnid = 1;
1709         RETURN(rc);
1710
1711 destroy_new_ns:
1712         lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1713         OBD_FREE_PTR(new_ns_uuid);
1714
1715 destroy_new:
1716         spin_lock(&obd->obd_nid_lock);
1717         list_del(&new_stat->nid_list);
1718         spin_unlock(&obd->obd_nid_lock);
1719         OBD_FREE_PTR(new_stat);
1720         RETURN(rc);
1721 }
1722
1723 int lprocfs_exp_cleanup(struct obd_export *exp)
1724 {
1725         struct nid_stat *stat = exp->exp_nid_stats;
1726         struct nid_stat_uuid *cursor, *tmp;
1727         int found = 0;
1728
1729         if(!stat || !exp->exp_obd)
1730                 RETURN(0);
1731
1732         spin_lock(&exp->exp_obd->obd_nid_lock);
1733         list_for_each_entry_safe(cursor, tmp,
1734                                  &stat->nid_uuid_list,
1735                                  ns_uuid_list) {
1736                 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1737                                               &exp->exp_client_uuid)) {
1738                         found = 1;
1739                         list_del(&cursor->ns_uuid_list);
1740                         OBD_FREE_PTR(cursor);
1741                         break;
1742                 }
1743         }
1744         spin_unlock(&exp->exp_obd->obd_nid_lock);
1745         if (!found)
1746                 CERROR("obd_export's client uuid %s are not found in its "
1747                        "nid_stats list\n", exp->exp_client_uuid.uuid);
1748
1749         stat->nid_exp_ref_count--;
1750         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1751
1752         exp->exp_nid_stats = NULL;
1753         lprocfs_free_md_stats(exp->exp_obd);
1754
1755         return 0;
1756 }
1757
1758 int lprocfs_write_helper(const char *buffer, unsigned long count,
1759                          int *val)
1760 {
1761         return lprocfs_write_frac_helper(buffer, count, val, 1);
1762 }
1763
1764 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1765                               int *val, int mult)
1766 {
1767         char kernbuf[20], *end, *pbuf;
1768
1769         if (count > (sizeof(kernbuf) - 1))
1770                 return -EINVAL;
1771
1772         if (copy_from_user(kernbuf, buffer, count))
1773                 return -EFAULT;
1774
1775         kernbuf[count] = '\0';
1776         pbuf = kernbuf;
1777         if (*pbuf == '-') {
1778                 mult = -mult;
1779                 pbuf++;
1780         }
1781
1782         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1783         if (pbuf == end)
1784                 return -EINVAL;
1785
1786         if (end != NULL && *end == '.') {
1787                 int temp_val, pow = 1;
1788                 int i;
1789
1790                 pbuf = end + 1;
1791                 if (strlen(pbuf) > 5)
1792                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1793
1794                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1795
1796                 if (pbuf < end) {
1797                         for (i = 0; i < (end - pbuf); i++)
1798                                 pow *= 10;
1799
1800                         *val += temp_val / pow;
1801                 }
1802         }
1803         return 0;
1804 }
1805
1806 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1807 {
1808         long decimal_val, frac_val;
1809         int prtn;
1810
1811         if (count < 10)
1812                 return -EINVAL;
1813
1814         decimal_val = val / mult;
1815         prtn = snprintf(buffer, count, "%ld", decimal_val);
1816         frac_val = val % mult;
1817
1818         if (prtn < (count - 4) && frac_val > 0) {
1819                 long temp_frac;
1820                 int i, temp_mult = 1, frac_bits = 0;
1821
1822                 temp_frac = frac_val * 10;
1823                 buffer[prtn++] = '.';
1824                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1825                         /* only reserved 2 bits fraction */
1826                         buffer[prtn++] ='0';
1827                         temp_frac *= 10;
1828                         frac_bits++;
1829                 }
1830                 /*
1831                  * Need to think these cases :
1832                  *      1. #echo x.00 > /proc/xxx       output result : x
1833                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1834                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1835                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1836                  *      Only reserved 2 bits fraction.
1837                  */
1838                 for (i = 0; i < (5 - prtn); i++)
1839                         temp_mult *= 10;
1840
1841                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1842                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1843                                  frac_val * temp_mult / mult);
1844
1845                 prtn--;
1846                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1847                         prtn--;
1848                         if (buffer[prtn] == '.') {
1849                                 prtn--;
1850                                 break;
1851                         }
1852                 }
1853                 prtn++;
1854         }
1855         buffer[prtn++] ='\n';
1856         return prtn;
1857 }
1858
1859 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1860 {
1861         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1862 }
1863
1864 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1865                               __u64 *val, int mult)
1866 {
1867         char kernbuf[22], *end, *pbuf;
1868         __u64 whole, frac = 0, units;
1869         unsigned frac_d = 1;
1870
1871         if (count > (sizeof(kernbuf) - 1) )
1872                 return -EINVAL;
1873
1874         if (copy_from_user(kernbuf, buffer, count))
1875                 return -EFAULT;
1876
1877         kernbuf[count] = '\0';
1878         pbuf = kernbuf;
1879         if (*pbuf == '-') {
1880                 mult = -mult;
1881                 pbuf++;
1882         }
1883
1884         whole = simple_strtoull(pbuf, &end, 10);
1885         if (pbuf == end)
1886                 return -EINVAL;
1887
1888         if (end != NULL && *end == '.') {
1889                 int i;
1890                 pbuf = end + 1;
1891
1892                 /* need to limit frac_d to a __u32 */
1893                 if (strlen(pbuf) > 10)
1894                         pbuf[10] = '\0';
1895
1896                 frac = simple_strtoull(pbuf, &end, 10);
1897                 /* count decimal places */
1898                 for (i = 0; i < (end - pbuf); i++)
1899                         frac_d *= 10;
1900         }
1901
1902         units = 1;
1903         switch(*end) {
1904         case 'p': case 'P':
1905                 units <<= 10;
1906         case 't': case 'T':
1907                 units <<= 10;
1908         case 'g': case 'G':
1909                 units <<= 10;
1910         case 'm': case 'M':
1911                 units <<= 10;
1912         case 'k': case 'K':
1913                 units <<= 10;
1914         }
1915         /* Specified units override the multiplier */
1916         if (units)
1917                 mult = mult < 0 ? -units : units;
1918
1919         frac *= mult;
1920         do_div(frac, frac_d);
1921         *val = whole * mult + frac;
1922         return 0;
1923 }
1924
1925 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1926                        struct file_operations *seq_fops, void *data)
1927 {
1928         struct proc_dir_entry *entry;
1929         ENTRY;
1930
1931         entry = create_proc_entry(name, mode, parent);
1932         if (entry == NULL)
1933                 RETURN(-ENOMEM);
1934         entry->proc_fops = seq_fops;
1935         entry->data = data;
1936
1937         RETURN(0);
1938 }
1939 EXPORT_SYMBOL(lprocfs_seq_create);
1940
1941 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1942                                       mode_t mode,
1943                                       struct file_operations *seq_fops,
1944                                       void *data)
1945 {
1946         return (lprocfs_seq_create(dev->obd_proc_entry, name,
1947                                    mode, seq_fops, data));
1948 }
1949 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1950
1951 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1952 {
1953         if (value >= OBD_HIST_MAX)
1954                 value = OBD_HIST_MAX - 1;
1955
1956         spin_lock(&oh->oh_lock);
1957         oh->oh_buckets[value]++;
1958         spin_unlock(&oh->oh_lock);
1959 }
1960 EXPORT_SYMBOL(lprocfs_oh_tally);
1961
1962 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1963 {
1964         unsigned int val;
1965
1966         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1967                 ;
1968
1969         lprocfs_oh_tally(oh, val);
1970 }
1971 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1972
1973 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1974 {
1975         unsigned long ret = 0;
1976         int i;
1977
1978         for (i = 0; i < OBD_HIST_MAX; i++)
1979                 ret +=  oh->oh_buckets[i];
1980         return ret;
1981 }
1982 EXPORT_SYMBOL(lprocfs_oh_sum);
1983
1984 void lprocfs_oh_clear(struct obd_histogram *oh)
1985 {
1986         spin_lock(&oh->oh_lock);
1987         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1988         spin_unlock(&oh->oh_lock);
1989 }
1990 EXPORT_SYMBOL(lprocfs_oh_clear);
1991
1992 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1993                         int count, int *eof, void *data)
1994 {
1995         struct obd_device *obd = data;
1996         int c = 0;
1997
1998         if (obd == NULL)
1999                 return 0;
2000
2001         c += lustre_hash_debug_header(page, count);
2002         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2003         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2004         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2005
2006         return c;
2007 }
2008 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2009
2010 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2011                                    int count, int *eof, void *data)
2012 {
2013         struct obd_device *obd = data;
2014         int len = 0, size;
2015
2016         LASSERT(obd != NULL);
2017         LASSERT(count >= 0);
2018
2019         /* Set start of user data returned to
2020            page + off since the user may have
2021            requested to read much smaller than
2022            what we need to read */
2023         *start = page + off;
2024
2025         /* We know we are allocated a page here.
2026            Also we know that this function will
2027            not need to write more than a page
2028            so we can truncate at CFS_PAGE_SIZE.  */
2029         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2030
2031         /* Initialize the page */
2032         memset(page, 0, size);
2033
2034         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2035                 goto out;
2036         if (obd->obd_max_recoverable_clients == 0) {
2037                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2038                         goto out;
2039
2040                 goto fclose;
2041         }
2042
2043         /* sampled unlocked, but really... */
2044         if (obd->obd_recovering == 0) {
2045                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2046                         goto out;
2047                 if (lprocfs_obd_snprintf(&page, size, &len,
2048                                          "recovery_start: %lu\n",
2049                                          obd->obd_recovery_start) <= 0)
2050                         goto out;
2051                 if (lprocfs_obd_snprintf(&page, size, &len,
2052                                          "recovery_duration: %lu\n",
2053                                          obd->obd_recovery_end -
2054                                          obd->obd_recovery_start) <= 0)
2055                         goto out;
2056                 /* Number of clients that have completed recovery */
2057                 if (lprocfs_obd_snprintf(&page, size, &len,
2058                                          "completed_clients: %d/%d\n",
2059                                          obd->obd_max_recoverable_clients -
2060                                          obd->obd_recoverable_clients,
2061                                          obd->obd_max_recoverable_clients) <= 0)
2062                         goto out;
2063                 if (lprocfs_obd_snprintf(&page, size, &len,
2064                                          "replayed_requests: %d\n",
2065                                          obd->obd_replayed_requests) <= 0)
2066                         goto out;
2067                 if (lprocfs_obd_snprintf(&page, size, &len,
2068                                          "last_transno: "LPD64"\n",
2069                                          obd->obd_next_recovery_transno - 1)<=0)
2070                         goto out;
2071                 goto fclose;
2072         }
2073
2074         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2075                 goto out;
2076         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2077                                  obd->obd_recovery_start) <= 0)
2078                 goto out;
2079         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2080                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2081                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2082                 goto out;
2083         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2084                                  obd->obd_connected_clients,
2085                                  obd->obd_max_recoverable_clients) <= 0)
2086                 goto out;
2087         /* Number of clients that have completed recovery */
2088         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2089                                  obd->obd_max_recoverable_clients -
2090                                  obd->obd_recoverable_clients,
2091                                  obd->obd_max_recoverable_clients) <= 0)
2092                 goto out;
2093         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2094                                  obd->obd_replayed_requests) <= 0)
2095                 goto out;
2096         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2097                                  obd->obd_requests_queued_for_recovery) <= 0)
2098                 goto out;
2099
2100         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2101                                  obd->obd_next_recovery_transno) <= 0)
2102                 goto out;
2103
2104 fclose:
2105         *eof = 1;
2106 out:
2107         return min(count, len - (int)off);
2108 }
2109 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2110
2111 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2112                                     int count, int *eof, void *data)
2113 {
2114         struct obd_device *obd = data;
2115         LASSERT(obd != NULL);
2116
2117         return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2118 }
2119 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2120
2121 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2122                                     unsigned long count, void *data)
2123 {
2124         struct obd_device *obd = data;
2125         int val, rc;
2126         LASSERT(obd != NULL);
2127
2128         rc = lprocfs_write_helper(buffer, count, &val);
2129         if (rc)
2130                 return rc;
2131
2132         obd->obd_recovery_max_time = val;
2133         return count;
2134 }
2135 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2136
2137 EXPORT_SYMBOL(lprocfs_register);
2138 EXPORT_SYMBOL(lprocfs_srch);
2139 EXPORT_SYMBOL(lprocfs_remove);
2140 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2141 EXPORT_SYMBOL(lprocfs_add_vars);
2142 EXPORT_SYMBOL(lprocfs_obd_setup);
2143 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2144 EXPORT_SYMBOL(lprocfs_add_simple);
2145 EXPORT_SYMBOL(lprocfs_add_symlink);
2146 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2147 EXPORT_SYMBOL(lprocfs_alloc_stats);
2148 EXPORT_SYMBOL(lprocfs_free_stats);
2149 EXPORT_SYMBOL(lprocfs_clear_stats);
2150 EXPORT_SYMBOL(lprocfs_register_stats);
2151 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2152 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2153 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2154 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2155 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2156 EXPORT_SYMBOL(lprocfs_exp_setup);
2157 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2158
2159 EXPORT_SYMBOL(lprocfs_rd_u64);
2160 EXPORT_SYMBOL(lprocfs_rd_atomic);
2161 EXPORT_SYMBOL(lprocfs_wr_atomic);
2162 EXPORT_SYMBOL(lprocfs_rd_uint);
2163 EXPORT_SYMBOL(lprocfs_wr_uint);
2164 EXPORT_SYMBOL(lprocfs_rd_uuid);
2165 EXPORT_SYMBOL(lprocfs_rd_name);
2166 EXPORT_SYMBOL(lprocfs_rd_fstype);
2167 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2168 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2169 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2170 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2171 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2172 EXPORT_SYMBOL(lprocfs_rd_import);
2173 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2174 EXPORT_SYMBOL(lprocfs_rd_blksize);
2175 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2176 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2177 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2178 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2179 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2180
2181 EXPORT_SYMBOL(lprocfs_write_helper);
2182 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2183 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2184 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2185 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2186 #endif /* LPROCFS*/