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,
210                                   size_t size, loff_t *ppos)
211 {
212         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
213         int rc = -EIO;
214
215         LPROCFS_ENTRY();
216         if (!dp->deleted && dp->write_proc)
217                 rc = dp->write_proc(f, buf, size, dp->data);
218         LPROCFS_EXIT();
219         return rc;
220 }
221
222 static struct file_operations lprocfs_generic_fops = {
223         .owner = THIS_MODULE,
224         .read = lprocfs_fops_read,
225         .write = lprocfs_fops_write,
226 };
227
228 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
229 {
230         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
231         struct obd_device *obd = dp->data;
232
233         atomic_inc(&obd->obd_evict_inprogress);
234
235         return 0;
236 }
237
238 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
239 {
240         struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
241         struct obd_device *obd = dp->data;
242
243         atomic_dec(&obd->obd_evict_inprogress);
244         wake_up(&obd->obd_evict_inprogress_waitq);
245
246         return 0;
247 }
248
249 struct file_operations lprocfs_evict_client_fops = {
250         .owner = THIS_MODULE,
251         .read = lprocfs_fops_read,
252         .write = lprocfs_fops_write,
253         .open = lprocfs_evict_client_open,
254         .release = lprocfs_evict_client_release,
255 };
256 EXPORT_SYMBOL(lprocfs_evict_client_fops);
257
258 /**
259  * Add /proc entries.
260  *
261  * \param root [in]  The parent proc entry on which new entry will be added.
262  * \param list [in]  Array of proc entries to be added.
263  * \param data [in]  The argument to be passed when entries read/write routines
264  *                   are called through /proc file.
265  *
266  * \retval 0   on success
267  *         < 0 on error
268  */
269 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
270                      void *data)
271 {
272         if (root == NULL || list == NULL)
273                 return -EINVAL;
274
275         while (list->name != NULL) {
276                 struct proc_dir_entry *cur_root, *proc;
277                 char *pathcopy, *cur, *next, pathbuf[64];
278                 int pathsize = strlen(list->name) + 1;
279
280                 proc = NULL;
281                 cur_root = root;
282
283                 /* need copy of path for strsep */
284                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
285                         OBD_ALLOC(pathcopy, pathsize);
286                         if (pathcopy == NULL)
287                                 return -ENOMEM;
288                 } else {
289                         pathcopy = pathbuf;
290                 }
291
292                 next = pathcopy;
293                 strcpy(pathcopy, list->name);
294
295                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
296                         if (*cur =='\0') /* skip double/trailing "/" */
297                                 continue;
298
299                         proc = lprocfs_srch(cur_root, cur);
300                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
301                                cur_root->name, cur, next,
302                                (proc ? "exists" : "new"));
303                         if (next != NULL) {
304                                 cur_root = (proc ? proc :
305                                             proc_mkdir(cur, cur_root));
306                         } else if (proc == NULL) {
307                                 mode_t mode = 0;
308                                 if (list->proc_mode != 0000) {
309                                         mode = list->proc_mode;
310                                 } else {
311                                         if (list->read_fptr)
312                                                 mode = 0444;
313                                         if (list->write_fptr)
314                                                 mode |= 0200;
315                                 }
316                                 proc = create_proc_entry(cur, mode, cur_root);
317                         }
318                 }
319
320                 if (pathcopy != pathbuf)
321                         OBD_FREE(pathcopy, pathsize);
322
323                 if (cur_root == NULL || proc == NULL) {
324                         CERROR("LprocFS: No memory to create /proc entry %s",
325                                list->name);
326                         return -ENOMEM;
327                 }
328
329                 if (list->fops)
330                         proc->proc_fops = list->fops;
331                 else
332                         proc->proc_fops = &lprocfs_generic_fops;
333                 proc->read_proc = list->read_fptr;
334                 proc->write_proc = list->write_fptr;
335                 proc->data = (list->data ? list->data : data);
336                 list++;
337         }
338         return 0;
339 }
340
341 void lprocfs_remove(struct proc_dir_entry **rooth)
342 {
343         struct proc_dir_entry *root = *rooth;
344         struct proc_dir_entry *temp = root;
345         struct proc_dir_entry *rm_entry;
346         struct proc_dir_entry *parent;
347
348         if (!root)
349                 return;
350         *rooth = NULL;
351
352         parent = root->parent;
353         LASSERT(parent != NULL);
354         LPROCFS_WRITE_ENTRY(); /* search vs remove race */
355
356         while (1) {
357                 while (temp->subdir != NULL)
358                         temp = temp->subdir;
359
360                 rm_entry = temp;
361                 temp = temp->parent;
362
363                 /* Memory corruption once caused this to fail, and
364                    without this LASSERT we would loop here forever. */
365                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
366                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
367                          rm_entry->name, (int)strlen(rm_entry->name));
368
369                 /* Now, the rm_entry->deleted flags is protected
370                  * by _lprocfs_lock. */
371                 rm_entry->data = NULL;
372                 remove_proc_entry(rm_entry->name, temp);
373                 if (temp == parent)
374                         break;
375         }
376         LPROCFS_WRITE_EXIT();
377 }
378
379 void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
380 {
381         LASSERT(parent != NULL);
382         remove_proc_entry(name, parent);
383 }
384
385 struct proc_dir_entry *lprocfs_register(const char *name,
386                                         struct proc_dir_entry *parent,
387                                         struct lprocfs_vars *list, void *data)
388 {
389         struct proc_dir_entry *newchild;
390
391         newchild = lprocfs_srch(parent, name);
392         if (newchild != NULL) {
393                 CERROR(" Lproc: Attempting to register %s more than once \n",
394                        name);
395                 return ERR_PTR(-EALREADY);
396         }
397
398         newchild = proc_mkdir(name, parent);
399         if (newchild != NULL && list != NULL) {
400                 int rc = lprocfs_add_vars(newchild, list, data);
401                 if (rc) {
402                         lprocfs_remove(&newchild);
403                         return ERR_PTR(rc);
404                 }
405         }
406         return newchild;
407 }
408
409 /* Generic callbacks */
410 int lprocfs_rd_uint(char *page, char **start, off_t off,
411                     int count, int *eof, void *data)
412 {
413         unsigned int *temp = data;
414         return snprintf(page, count, "%u\n", *temp);
415 }
416
417 int lprocfs_wr_uint(struct file *file, const char *buffer,
418                     unsigned long count, void *data)
419 {
420         unsigned *p = data;
421         char dummy[MAX_STRING_SIZE + 1], *end;
422         unsigned long tmp;
423
424         dummy[MAX_STRING_SIZE] = '\0';
425         if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))
426                 return -EFAULT;
427
428         tmp = simple_strtoul(dummy, &end, 0);
429         if (dummy == end)
430                 return -EINVAL;
431
432         *p = (unsigned int)tmp;
433         return count;
434 }
435
436 int lprocfs_rd_u64(char *page, char **start, off_t off,
437                    int count, int *eof, void *data)
438 {
439         LASSERT(data != NULL);
440         *eof = 1;
441         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
442 }
443
444 int lprocfs_rd_atomic(char *page, char **start, off_t off,
445                    int count, int *eof, void *data)
446 {
447         atomic_t *atom = data;
448         LASSERT(atom != NULL);
449         *eof = 1;
450         return snprintf(page, count, "%d\n", atomic_read(atom));
451 }
452
453 int lprocfs_wr_atomic(struct file *file, const char *buffer,
454                       unsigned long count, void *data)
455 {
456         atomic_t *atm = data;
457         int val = 0;
458         int rc;
459
460         rc = lprocfs_write_helper(buffer, count, &val);
461         if (rc < 0)
462                 return rc;
463
464         if (val <= 0)
465                 return -ERANGE;
466
467         atomic_set(atm, val);
468         return count;
469 }
470
471 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
472                     int *eof, void *data)
473 {
474         struct obd_device *obd = data;
475
476         LASSERT(obd != NULL);
477         *eof = 1;
478         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
479 }
480
481 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
482                     int *eof, void *data)
483 {
484         struct obd_device *dev = data;
485
486         LASSERT(dev != NULL);
487         LASSERT(dev->obd_name != NULL);
488         *eof = 1;
489         return snprintf(page, count, "%s\n", dev->obd_name);
490 }
491
492 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
493                       void *data)
494 {
495         struct obd_device *obd = data;
496
497         LASSERT(obd != NULL);
498         LASSERT(obd->obd_fsops != NULL);
499         LASSERT(obd->obd_fsops->fs_type != NULL);
500         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
501 }
502
503 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
504                        int *eof, void *data)
505 {
506         struct obd_statfs osfs;
507         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
508                             OBD_STATFS_NODELAY);
509         if (!rc) {
510                 *eof = 1;
511                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
512         }
513         return rc;
514 }
515
516 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
517                            int *eof, void *data)
518 {
519         struct obd_statfs osfs;
520         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
521                             OBD_STATFS_NODELAY);
522         if (!rc) {
523                 __u32 blk_size = osfs.os_bsize >> 10;
524                 __u64 result = osfs.os_blocks;
525
526                 while (blk_size >>= 1)
527                         result <<= 1;
528
529                 *eof = 1;
530                 rc = snprintf(page, count, LPU64"\n", result);
531         }
532         return rc;
533 }
534
535 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
536                           int *eof, void *data)
537 {
538         struct obd_statfs osfs;
539         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
540                             OBD_STATFS_NODELAY);
541         if (!rc) {
542                 __u32 blk_size = osfs.os_bsize >> 10;
543                 __u64 result = osfs.os_bfree;
544
545                 while (blk_size >>= 1)
546                         result <<= 1;
547
548                 *eof = 1;
549                 rc = snprintf(page, count, LPU64"\n", result);
550         }
551         return rc;
552 }
553
554 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
555                            int *eof, void *data)
556 {
557         struct obd_statfs osfs;
558         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
559                             OBD_STATFS_NODELAY);
560         if (!rc) {
561                 __u32 blk_size = osfs.os_bsize >> 10;
562                 __u64 result = osfs.os_bavail;
563
564                 while (blk_size >>= 1)
565                         result <<= 1;
566
567                 *eof = 1;
568                 rc = snprintf(page, count, LPU64"\n", result);
569         }
570         return rc;
571 }
572
573 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
574                           int *eof, void *data)
575 {
576         struct obd_statfs osfs;
577         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
578                             OBD_STATFS_NODELAY);
579         if (!rc) {
580                 *eof = 1;
581                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
582         }
583
584         return rc;
585 }
586
587 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
588                          int *eof, void *data)
589 {
590         struct obd_statfs osfs;
591         int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ,
592                             OBD_STATFS_NODELAY);
593         if (!rc) {
594                 *eof = 1;
595                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
596         }
597         return rc;
598 }
599
600 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
601                            int *eof, void *data)
602 {
603         struct obd_device *obd = data;
604         struct obd_import *imp;
605         char *imp_state_name = NULL;
606         int rc = 0;
607
608         LASSERT(obd != NULL);
609         LPROCFS_CLIMP_CHECK(obd);
610         imp = obd->u.cli.cl_import;
611         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
612         *eof = 1;
613         rc = snprintf(page, count, "%s\t%s%s\n",
614                       obd2cli_tgt(obd), imp_state_name,
615                       imp->imp_deactive ? "\tDEACTIVATED" : "");
616
617         LPROCFS_CLIMP_EXIT(obd);
618         return rc;
619 }
620
621 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
622                          int *eof,  void *data)
623 {
624         struct obd_device *obd = data;
625         struct ptlrpc_connection *conn;
626         int rc = 0;
627
628         LASSERT(obd != NULL);
629
630         LPROCFS_CLIMP_CHECK(obd);
631         conn = obd->u.cli.cl_import->imp_connection;
632         LASSERT(conn != NULL);
633         *eof = 1;
634         if (obd->u.cli.cl_import) {
635                 rc = snprintf(page, count, "%s\n",
636                               conn->c_remote_uuid.uuid);
637         } else {
638                 rc = snprintf(page, count, "%s\n", "<none>");
639         }
640
641         LPROCFS_CLIMP_EXIT(obd);
642         return rc;
643 }
644
645 #define flag2str(flag) \
646         if (imp->imp_##flag && max - len > 0) \
647                 len += snprintf(str + len, max - len, " " #flag);
648
649 /**
650  * Append a space separated list of current set flags to str.
651  */
652 static int obd_import_flags2str(struct obd_import *imp, char *str,
653                                           int max)
654 {
655         int len = 0;
656
657         if (imp->imp_obd->obd_no_recov)
658                 len += snprintf(str, max - len, " no_recov");
659
660         flag2str(invalid);
661         flag2str(deactive);
662         flag2str(replayable);
663         flag2str(pingable);
664         flag2str(recon_bk);
665         flag2str(last_recon);
666         return len;
667 }
668 #undef flags2str
669
670 int lprocfs_rd_import(char *page, char **start, off_t off, int count,
671                       int *eof, void *data)
672 {
673         struct obd_device *obd = (struct obd_device *)data;
674         struct obd_import *imp;
675         char *imp_state_name = NULL;
676         int rc = 0;
677
678         LASSERT(obd != NULL);
679         LPROCFS_CLIMP_CHECK(obd);
680         imp = obd->u.cli.cl_import;
681         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
682         *eof = 1;
683
684         rc = snprintf(page, count,
685                       "import: %s\n"
686                       "    target: %s@%s\n"
687                       "    state: %s\n"
688                       "    inflight: %u\n"
689                       "    conn_cnt: %u\n"
690                       "    generation: %u\n"
691                       "    inval_cnt: %u\n"
692                       "    last_replay_transno: "LPU64"\n"
693                       "    peer_committed_transno: "LPU64"\n"
694                       "    last_trasno_checked: "LPU64"\n"
695                       "    flags:",
696                       obd->obd_name,
697                       obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
698                       imp_state_name,
699                       atomic_read(&imp->imp_inflight),
700                       imp->imp_conn_cnt,
701                       imp->imp_generation,
702                       atomic_read(&imp->imp_inval_count),
703                       imp->imp_last_replay_transno,
704                       imp->imp_peer_committed_transno,
705                       imp->imp_last_transno_checked);
706         rc += obd_import_flags2str(imp, page + rc, count - rc);
707         rc += snprintf(page+rc, count - rc, "\n");
708         LPROCFS_CLIMP_EXIT(obd);
709         return rc;
710 }
711
712 int lprocfs_at_hist_helper(char *page, int count, int rc,
713                            struct adaptive_timeout *at)
714 {
715         int i;
716         for (i = 0; i < AT_BINS; i++)
717                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
718         rc += snprintf(page + rc, count - rc, "\n");
719         return rc;
720 }
721
722 /* See also ptlrpc_lprocfs_rd_timeouts */
723 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
724                         int *eof, void *data)
725 {
726         struct obd_device *obd = (struct obd_device *)data;
727         struct obd_import *imp;
728         unsigned int cur, worst;
729         time_t now, worstt;
730         struct dhms ts;
731         int i, rc = 0;
732
733         LASSERT(obd != NULL);
734         LPROCFS_CLIMP_CHECK(obd);
735         imp = obd->u.cli.cl_import;
736         *eof = 1;
737
738         now = cfs_time_current_sec();
739
740         /* Some network health info for kicks */
741         s2dhms(&ts, now - imp->imp_last_reply_time);
742         rc += snprintf(page + rc, count - rc,
743                        "%-10s : %ld, "DHMS_FMT" ago\n",
744                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
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,
1585                                          nid_list);
1586                 list_del_init(&client_stat->nid_list);
1587                 lprocfs_free_client_stats(client_stat);
1588         }
1589
1590         return count;
1591 }
1592 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1593
1594 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1595 {
1596         struct nid_stat *new_stat, *old_stat;
1597         struct nid_stat_uuid *new_ns_uuid;
1598         struct obd_device *obd = NULL;
1599         cfs_proc_dir_entry_t *entry;
1600         int rc = 0;
1601         ENTRY;
1602
1603         *newnid = 0;
1604
1605         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1606             !exp->exp_obd->obd_nid_stats_hash)
1607                 RETURN(-EINVAL);
1608
1609         /* not test against zero because eric say:
1610          * You may only test nid against another nid, or LNET_NID_ANY.
1611          * Anything else is nonsense.*/
1612         if (!nid || *nid == LNET_NID_ANY)
1613                 RETURN(0);
1614
1615         obd = exp->exp_obd;
1616
1617         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1618
1619         OBD_ALLOC_PTR(new_stat);
1620         if (new_stat == NULL)
1621                 RETURN(-ENOMEM);
1622
1623         OBD_ALLOC_PTR(new_ns_uuid);
1624         if (new_ns_uuid == NULL) {
1625                 OBD_FREE_PTR(new_stat);
1626                 RETURN(-ENOMEM);
1627         }
1628         CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1629         strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1630                 sizeof(struct obd_uuid));
1631
1632         CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1633         new_stat->nid               = *nid;
1634         new_stat->nid_obd           = exp->exp_obd;
1635         new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1636
1637         old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1638                                               nid, &new_stat->nid_hash);
1639         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1640                old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1641
1642         /* Return -EALREADY here so that we know that the /proc
1643          * entry already has been created */
1644         if (old_stat != new_stat) {
1645                 struct nid_stat_uuid *tmp_uuid;
1646                 int found = 0;
1647
1648                 exp->exp_nid_stats = old_stat;
1649                 /* We need to decrement the refcount if the uuid was
1650                  * already in our list */
1651                 spin_lock(&obd->obd_nid_lock);
1652                 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1653                                     ns_uuid_list) {
1654                         if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1655                                                         &exp->exp_client_uuid)){
1656                                 found = 1;
1657                                 --old_stat->nid_exp_ref_count;
1658                                 break;
1659                         }
1660                 }
1661
1662                 if (!found)
1663                         list_add(&new_ns_uuid->ns_uuid_list,
1664                                  &old_stat->nid_uuid_list);
1665                 else
1666                         OBD_FREE_PTR(new_ns_uuid);
1667
1668                 spin_unlock(&obd->obd_nid_lock);
1669
1670                 GOTO(destroy_new, rc = -EALREADY);
1671         }
1672         /* not found - create */
1673         new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1674                                               obd->obd_proc_exports_entry,
1675                                               NULL, NULL);
1676         if (new_stat->nid_proc == NULL) {
1677                 CERROR("Error making export directory for nid %s\n",
1678                        libcfs_nid2str(*nid));
1679                 GOTO(destroy_new_ns, rc = -ENOMEM);
1680         }
1681
1682         /* Add in uuid to our nid_stats list */
1683         spin_lock(&obd->obd_nid_lock);
1684         list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1685         spin_unlock(&obd->obd_nid_lock);
1686
1687         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1688                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1689         if (IS_ERR(entry)) {
1690                 CWARN("Error adding the NID stats file\n");
1691                 rc = PTR_ERR(entry);
1692                 GOTO(destroy_new_ns, rc);
1693         }
1694
1695         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1696                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1697         if (IS_ERR(entry)) {
1698                 CWARN("Error adding the hash file\n");
1699                 lprocfs_remove(&new_stat->nid_proc);
1700                 rc = PTR_ERR(entry);
1701                 GOTO(destroy_new_ns, rc);
1702         }
1703
1704         exp->exp_nid_stats = new_stat;
1705         *newnid = 1;
1706         /* protect competitive add to list, not need locking on destroy */
1707         spin_lock(&obd->obd_nid_lock);
1708         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1709         spin_unlock(&obd->obd_nid_lock);
1710
1711         RETURN(rc);
1712
1713 destroy_new_ns:
1714         lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1715         OBD_FREE_PTR(new_ns_uuid);
1716
1717 destroy_new:
1718         OBD_FREE_PTR(new_stat);
1719         RETURN(rc);
1720 }
1721
1722 int lprocfs_exp_cleanup(struct obd_export *exp)
1723 {
1724         struct nid_stat *stat = exp->exp_nid_stats;
1725         struct nid_stat_uuid *cursor, *tmp;
1726         int found = 0;
1727
1728         if(!stat || !exp->exp_obd)
1729                 RETURN(0);
1730
1731         spin_lock(&exp->exp_obd->obd_nid_lock);
1732         list_for_each_entry_safe(cursor, tmp,
1733                                  &stat->nid_uuid_list,
1734                                  ns_uuid_list) {
1735                 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1736                                               &exp->exp_client_uuid)) {
1737                         found = 1;
1738                         list_del(&cursor->ns_uuid_list);
1739                         OBD_FREE_PTR(cursor);
1740                         --stat->nid_exp_ref_count;
1741                         CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1742                                stat->nid_exp_ref_count);
1743                         break;
1744                 }
1745         }
1746         spin_unlock(&exp->exp_obd->obd_nid_lock);
1747         if (!found)
1748                 CERROR("obd_export's client uuid %s are not found in its "
1749                        "nid_stats list\n", exp->exp_client_uuid.uuid);
1750
1751         exp->exp_nid_stats = NULL;
1752         lprocfs_free_md_stats(exp->exp_obd);
1753
1754         return 0;
1755 }
1756
1757 int lprocfs_write_helper(const char *buffer, unsigned long count,
1758                          int *val)
1759 {
1760         return lprocfs_write_frac_helper(buffer, count, val, 1);
1761 }
1762
1763 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1764                               int *val, int mult)
1765 {
1766         char kernbuf[20], *end, *pbuf;
1767
1768         if (count > (sizeof(kernbuf) - 1))
1769                 return -EINVAL;
1770
1771         if (copy_from_user(kernbuf, buffer, count))
1772                 return -EFAULT;
1773
1774         kernbuf[count] = '\0';
1775         pbuf = kernbuf;
1776         if (*pbuf == '-') {
1777                 mult = -mult;
1778                 pbuf++;
1779         }
1780
1781         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1782         if (pbuf == end)
1783                 return -EINVAL;
1784
1785         if (end != NULL && *end == '.') {
1786                 int temp_val, pow = 1;
1787                 int i;
1788
1789                 pbuf = end + 1;
1790                 if (strlen(pbuf) > 5)
1791                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1792
1793                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1794
1795                 if (pbuf < end) {
1796                         for (i = 0; i < (end - pbuf); i++)
1797                                 pow *= 10;
1798
1799                         *val += temp_val / pow;
1800                 }
1801         }
1802         return 0;
1803 }
1804
1805 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1806                              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*/