Whamcloud - gitweb
b=17310
[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                       "    unregistering: %u\n"
690                       "    conn_cnt: %u\n"
691                       "    generation: %u\n"
692                       "    inval_cnt: %u\n"
693                       "    last_replay_transno: "LPU64"\n"
694                       "    peer_committed_transno: "LPU64"\n"
695                       "    last_trasno_checked: "LPU64"\n"
696                       "    flags:",
697                       obd->obd_name,
698                       obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid,
699                       imp_state_name,
700                       atomic_read(&imp->imp_inflight),
701                       atomic_read(&imp->imp_unregistering),
702                       imp->imp_conn_cnt,
703                       imp->imp_generation,
704                       atomic_read(&imp->imp_inval_count),
705                       imp->imp_last_replay_transno,
706                       imp->imp_peer_committed_transno,
707                       imp->imp_last_transno_checked);
708         rc += obd_import_flags2str(imp, page + rc, count - rc);
709         rc += snprintf(page+rc, count - rc, "\n");
710         LPROCFS_CLIMP_EXIT(obd);
711         return rc;
712 }
713
714 int lprocfs_at_hist_helper(char *page, int count, int rc,
715                            struct adaptive_timeout *at)
716 {
717         int i;
718         for (i = 0; i < AT_BINS; i++)
719                 rc += snprintf(page + rc, count - rc, "%3u ", at->at_hist[i]);
720         rc += snprintf(page + rc, count - rc, "\n");
721         return rc;
722 }
723
724 /* See also ptlrpc_lprocfs_rd_timeouts */
725 int lprocfs_rd_timeouts(char *page, char **start, off_t off, int count,
726                         int *eof, void *data)
727 {
728         struct obd_device *obd = (struct obd_device *)data;
729         struct obd_import *imp;
730         unsigned int cur, worst;
731         time_t now, worstt;
732         struct dhms ts;
733         int i, rc = 0;
734
735         LASSERT(obd != NULL);
736         LPROCFS_CLIMP_CHECK(obd);
737         imp = obd->u.cli.cl_import;
738         *eof = 1;
739
740         now = cfs_time_current_sec();
741
742         /* Some network health info for kicks */
743         s2dhms(&ts, now - imp->imp_last_reply_time);
744         rc += snprintf(page + rc, count - rc,
745                        "%-10s : %ld, "DHMS_FMT" ago\n",
746                        "last reply", imp->imp_last_reply_time, DHMS_VARS(&ts));
747
748         cur = at_get(&imp->imp_at.iat_net_latency);
749         worst = imp->imp_at.iat_net_latency.at_worst_ever;
750         worstt = imp->imp_at.iat_net_latency.at_worst_time;
751         s2dhms(&ts, now - worstt);
752         rc += snprintf(page + rc, count - rc,
753                        "%-10s : cur %3u  worst %3u (at %ld, "DHMS_FMT" ago) ",
754                        "network", cur, worst, worstt, DHMS_VARS(&ts));
755         rc = lprocfs_at_hist_helper(page, count, rc,
756                                     &imp->imp_at.iat_net_latency);
757
758         for(i = 0; i < IMP_AT_MAX_PORTALS; i++) {
759                 if (imp->imp_at.iat_portal[i] == 0)
760                         break;
761                 cur = at_get(&imp->imp_at.iat_service_estimate[i]);
762                 worst = imp->imp_at.iat_service_estimate[i].at_worst_ever;
763                 worstt = imp->imp_at.iat_service_estimate[i].at_worst_time;
764                 s2dhms(&ts, now - worstt);
765                 rc += snprintf(page + rc, count - rc,
766                                "portal %-2d  : cur %3u  worst %3u (at %ld, "
767                                DHMS_FMT" ago) ", imp->imp_at.iat_portal[i],
768                                cur, worst, worstt, DHMS_VARS(&ts));
769                 rc = lprocfs_at_hist_helper(page, count, rc,
770                                           &imp->imp_at.iat_service_estimate[i]);
771         }
772
773         LPROCFS_CLIMP_EXIT(obd);
774         return rc;
775 }
776
777 static const char *obd_connect_names[] = {
778         "read_only",
779         "lov_index",
780         "unused",
781         "write_grant",
782         "server_lock",
783         "version",
784         "request_portal",
785         "acl",
786         "xattr",
787         "create_on_write",
788         "truncate_lock",
789         "initial_transno",
790         "inode_bit_locks",
791         "join_file",
792         "getattr_by_fid",
793         "no_oh_for_devices",
794         "local_client",
795         "remote_client",
796         "max_byte_per_rpc",
797         "64bit_qdata",
798         "mds_capability",
799         "oss_capability",
800         "early_lock_cancel",
801         "size_on_mds",
802         "adaptive_timeouts",
803         "lru_resize",
804         "mds_mds_connection",
805         "real_conn",
806         "change_qunit_size",
807         "alt_checksum_algorithm",
808         "fid_is_enabled",
809         "version_recovery",
810         "pools",
811         NULL
812 };
813
814 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
815                              int count, int *eof, void *data)
816 {
817         struct obd_device *obd = data;
818         __u64 mask = 1, flags;
819         int i, ret = 0;
820
821         LPROCFS_CLIMP_CHECK(obd);
822         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
823         ret = snprintf(page, count, "flags="LPX64"\n", flags);
824         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
825                 if (flags & mask)
826                         ret += snprintf(page + ret, count - ret, "%s\n",
827                                         obd_connect_names[i]);
828         }
829         if (flags & ~(mask - 1))
830                 ret += snprintf(page + ret, count - ret,
831                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
832
833         LPROCFS_CLIMP_EXIT(obd);
834         return ret;
835 }
836 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
837
838 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
839                            int *eof,  void *data)
840 {
841         struct obd_device *obd = data;
842
843         LASSERT(obd != NULL);
844         *eof = 1;
845         return snprintf(page, count, "%u\n", obd->obd_num_exports);
846 }
847
848 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
849                        int *eof, void *data)
850 {
851         struct obd_type *class = (struct obd_type*) data;
852
853         LASSERT(class != NULL);
854         *eof = 1;
855         return snprintf(page, count, "%d\n", class->typ_refcnt);
856 }
857
858 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
859 {
860         int rc = 0;
861
862         LASSERT(obd != NULL);
863         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
864         LASSERT(obd->obd_type->typ_procroot != NULL);
865
866         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
867                                                obd->obd_type->typ_procroot,
868                                                list, obd);
869         if (IS_ERR(obd->obd_proc_entry)) {
870                 rc = PTR_ERR(obd->obd_proc_entry);
871                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
872                 obd->obd_proc_entry = NULL;
873         }
874         return rc;
875 }
876
877 int lprocfs_obd_cleanup(struct obd_device *obd)
878 {
879         if (!obd)
880                 return -EINVAL;
881         if (obd->obd_proc_exports_entry) {
882                 /* Should be no exports left */
883                 LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
884                 lprocfs_remove(&obd->obd_proc_exports_entry);
885         }
886         lprocfs_remove(&obd->obd_proc_entry);
887         return 0;
888 }
889
890 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
891 {
892         CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
893                client_stat->nid_proc, client_stat->nid_stats,
894                client_stat->nid_brw_stats);
895
896         LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
897                  client_stat->nid_exp_ref_count);
898
899         hlist_del_init(&client_stat->nid_hash);
900
901         if (client_stat->nid_proc)
902                 lprocfs_remove(&client_stat->nid_proc);
903
904         if (client_stat->nid_stats)
905                 lprocfs_free_stats(&client_stat->nid_stats);
906
907         if (client_stat->nid_brw_stats)
908                 OBD_FREE_PTR(client_stat->nid_brw_stats);
909
910         if (client_stat->nid_ldlm_stats)
911                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
912
913         OBD_FREE_PTR(client_stat);
914         return;
915
916 }
917
918 void lprocfs_free_per_client_stats(struct obd_device *obd)
919 {
920         struct nid_stat *stat;
921         ENTRY;
922
923         /* we need extra list - because hash_exit called to early */
924         /* not need locking because all clients is died */
925         while(!list_empty(&obd->obd_nid_stats)) {
926                 stat = list_entry(obd->obd_nid_stats.next,
927                                   struct nid_stat, nid_list);
928                 list_del_init(&stat->nid_list);
929                 lprocfs_free_client_stats(stat);
930         }
931
932         EXIT;
933 }
934
935 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
936                                           enum lprocfs_stats_flags flags)
937 {
938         struct lprocfs_stats *stats;
939         unsigned int percpusize;
940         unsigned int i, j;
941         unsigned int num_cpu;
942
943         if (num == 0)
944                 return NULL;
945
946         if (flags & LPROCFS_STATS_FLAG_NOPERCPU)
947                 num_cpu = 1;
948         else
949                 num_cpu = num_possible_cpus();
950
951         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
952         if (stats == NULL)
953                 return NULL;
954
955         if (flags & LPROCFS_STATS_FLAG_NOPERCPU) {
956                 stats->ls_flags = flags;
957                 spin_lock_init(&stats->ls_lock);
958                 /* Use this lock only if there are no percpu areas */
959         } else {
960                 stats->ls_flags = 0;
961         }
962
963         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
964         if (num_cpu > 1)
965                 percpusize = L1_CACHE_ALIGN(percpusize);
966
967         for (i = 0; i < num_cpu; i++) {
968                 OBD_ALLOC(stats->ls_percpu[i], percpusize);
969                 if (stats->ls_percpu[i] == NULL) {
970                         for (j = 0; j < i; j++) {
971                                 OBD_FREE(stats->ls_percpu[j], percpusize);
972                                 stats->ls_percpu[j] = NULL;
973                         }
974                         break;
975                 }
976         }
977         if (stats->ls_percpu[0] == NULL) {
978                 OBD_FREE(stats, offsetof(typeof(*stats),
979                                          ls_percpu[num_cpu]));
980                 return NULL;
981         }
982
983         stats->ls_num = num;
984         return stats;
985 }
986
987 void lprocfs_free_stats(struct lprocfs_stats **statsh)
988 {
989         struct lprocfs_stats *stats = *statsh;
990         unsigned int num_cpu;
991         unsigned int percpusize;
992         unsigned int i;
993
994         if (stats == NULL || stats->ls_num == 0)
995                 return;
996         *statsh = NULL;
997
998         if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
999                 num_cpu = 1;
1000         else
1001                 num_cpu = num_possible_cpus();
1002
1003         percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
1004         if (num_cpu > 1)
1005                 percpusize = L1_CACHE_ALIGN(percpusize);
1006         for (i = 0; i < num_cpu; i++)
1007                 OBD_FREE(stats->ls_percpu[i], percpusize);
1008         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
1009 }
1010
1011 void lprocfs_clear_stats(struct lprocfs_stats *stats)
1012 {
1013         struct lprocfs_counter *percpu_cntr;
1014         int i,j;
1015         unsigned int num_cpu;
1016
1017         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1018
1019         for (i = 0; i < num_cpu; i++) {
1020                 for (j = 0; j < stats->ls_num; j++) {
1021                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
1022                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
1023                         percpu_cntr->lc_count = 0;
1024                         percpu_cntr->lc_sum = 0;
1025                         percpu_cntr->lc_min = LC_MIN_INIT;
1026                         percpu_cntr->lc_max = 0;
1027                         percpu_cntr->lc_sumsquare = 0;
1028                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
1029                 }
1030         }
1031
1032         lprocfs_stats_unlock(stats);
1033 }
1034
1035 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
1036                                        size_t len, loff_t *off)
1037 {
1038         struct seq_file *seq = file->private_data;
1039         struct lprocfs_stats *stats = seq->private;
1040
1041         lprocfs_clear_stats(stats);
1042
1043         return len;
1044 }
1045
1046 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
1047 {
1048         struct lprocfs_stats *stats = p->private;
1049         /* return 1st cpu location */
1050         return (*pos >= stats->ls_num) ? NULL :
1051                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1052 }
1053
1054 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
1055 {
1056 }
1057
1058 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
1059 {
1060         struct lprocfs_stats *stats = p->private;
1061         ++*pos;
1062         return (*pos >= stats->ls_num) ? NULL :
1063                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
1064 }
1065
1066 /* seq file export of one lprocfs counter */
1067 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
1068 {
1069        struct lprocfs_stats *stats = p->private;
1070        struct lprocfs_counter  *cntr = v;
1071        struct lprocfs_counter  t, ret = { .lc_min = LC_MIN_INIT };
1072        int i, idx, rc = 0;
1073        unsigned int num_cpu;
1074
1075        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
1076                struct timeval now;
1077                do_gettimeofday(&now);
1078                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
1079                                "snapshot_time", now.tv_sec, now.tv_usec);
1080                if (rc < 0)
1081                        return rc;
1082        }
1083        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
1084
1085        if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU)
1086                num_cpu = 1;
1087        else
1088                num_cpu = num_possible_cpus();
1089
1090        for (i = 0; i < num_cpu; i++) {
1091                struct lprocfs_counter *percpu_cntr =
1092                        &(stats->ls_percpu[i])->lp_cntr[idx];
1093                int centry;
1094
1095                do {
1096                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
1097                        t.lc_count = percpu_cntr->lc_count;
1098                        t.lc_sum = percpu_cntr->lc_sum;
1099                        t.lc_min = percpu_cntr->lc_min;
1100                        t.lc_max = percpu_cntr->lc_max;
1101                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
1102                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
1103                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
1104                ret.lc_count += t.lc_count;
1105                ret.lc_sum += t.lc_sum;
1106                if (t.lc_min < ret.lc_min)
1107                        ret.lc_min = t.lc_min;
1108                if (t.lc_max > ret.lc_max)
1109                        ret.lc_max = t.lc_max;
1110                ret.lc_sumsquare += t.lc_sumsquare;
1111        }
1112
1113        if (ret.lc_count == 0)
1114                goto out;
1115
1116        rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
1117                        ret.lc_count, cntr->lc_units);
1118        if (rc < 0)
1119                goto out;
1120
1121        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
1122                rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
1123                                ret.lc_min, ret.lc_max, ret.lc_sum);
1124                if (rc < 0)
1125                        goto out;
1126                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
1127                        rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
1128                if (rc < 0)
1129                        goto out;
1130        }
1131        rc = seq_printf(p, "\n");
1132  out:
1133        return (rc < 0) ? rc : 0;
1134 }
1135
1136 struct seq_operations lprocfs_stats_seq_sops = {
1137         start: lprocfs_stats_seq_start,
1138         stop:  lprocfs_stats_seq_stop,
1139         next:  lprocfs_stats_seq_next,
1140         show:  lprocfs_stats_seq_show,
1141 };
1142
1143 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
1144 {
1145         struct proc_dir_entry *dp = PDE(inode);
1146         struct seq_file *seq;
1147         int rc;
1148
1149         LPROCFS_ENTRY_AND_CHECK(dp);
1150         rc = seq_open(file, &lprocfs_stats_seq_sops);
1151         if (rc) {
1152                 LPROCFS_EXIT();
1153                 return rc;
1154         }
1155         seq = file->private_data;
1156         seq->private = dp->data;
1157         return 0;
1158 }
1159
1160 struct file_operations lprocfs_stats_seq_fops = {
1161         .owner   = THIS_MODULE,
1162         .open    = lprocfs_stats_seq_open,
1163         .read    = seq_read,
1164         .write   = lprocfs_stats_seq_write,
1165         .llseek  = seq_lseek,
1166         .release = lprocfs_seq_release,
1167 };
1168
1169 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
1170                            struct lprocfs_stats *stats)
1171 {
1172         struct proc_dir_entry *entry;
1173         LASSERT(root != NULL);
1174
1175         entry = create_proc_entry(name, 0644, root);
1176         if (entry == NULL)
1177                 return -ENOMEM;
1178         entry->proc_fops = &lprocfs_stats_seq_fops;
1179         entry->data = stats;
1180         return 0;
1181 }
1182
1183 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
1184                           unsigned conf, const char *name, const char *units)
1185 {
1186         struct lprocfs_counter *c;
1187         int i;
1188         unsigned int num_cpu;
1189
1190         LASSERT(stats != NULL);
1191
1192         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
1193
1194         for (i = 0; i < num_cpu; i++) {
1195                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
1196                 c->lc_config = conf;
1197                 c->lc_count = 0;
1198                 c->lc_sum = 0;
1199                 c->lc_min = LC_MIN_INIT;
1200                 c->lc_max = 0;
1201                 c->lc_name = name;
1202                 c->lc_units = units;
1203         }
1204
1205         lprocfs_stats_unlock(stats);
1206 }
1207 EXPORT_SYMBOL(lprocfs_counter_init);
1208
1209 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
1210 do {                                                                       \
1211         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
1212         LASSERT(coffset < stats->ls_num);                                  \
1213         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
1214 } while (0)
1215
1216 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
1217 {
1218         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
1219         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
1220         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
1221         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
1222         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
1223         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
1224         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
1225         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
1226         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
1227         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
1228         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
1229         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
1230         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
1231         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
1232         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
1233         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
1234         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
1235         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
1236         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
1237         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
1238         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
1239         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
1240         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
1241         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
1242         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
1243         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
1244         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
1245         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
1246         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
1247         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
1248         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
1249         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
1250         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
1251         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
1252         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
1253         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reget_short_lock);
1254         LPROCFS_OBD_OP_INIT(num_private_stats, stats, release_short_lock);
1255         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
1256         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
1257         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
1258         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
1259         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
1260         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
1261         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
1262         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
1263         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
1264         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
1265         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
1266         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
1267         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
1268         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
1269         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
1270         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
1271         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
1272         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
1273         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
1274         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
1275         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
1276         LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
1277         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
1278         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
1279         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
1280         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
1281         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
1282         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
1283         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
1284         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
1285         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
1286         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
1287         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
1288         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
1289         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
1290         LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
1291         LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_lock_cancel_cb);
1292         LPROCFS_OBD_OP_INIT(num_private_stats, stats,unregister_lock_cancel_cb);
1293         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
1294         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
1295         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
1296         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
1297 }
1298
1299 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1300 {
1301         struct lprocfs_stats *stats;
1302         unsigned int num_stats;
1303         int rc, i;
1304
1305         LASSERT(obd->obd_stats == NULL);
1306         LASSERT(obd->obd_proc_entry != NULL);
1307         LASSERT(obd->obd_cntr_base == 0);
1308
1309         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1310                 num_private_stats - 1 /* o_owner */;
1311         stats = lprocfs_alloc_stats(num_stats, 0);
1312         if (stats == NULL)
1313                 return -ENOMEM;
1314
1315         lprocfs_init_ops_stats(num_private_stats, stats);
1316
1317         for (i = num_private_stats; i < num_stats; i++) {
1318                 /* If this LBUGs, it is likely that an obd
1319                  * operation was added to struct obd_ops in
1320                  * <obd.h>, and that the corresponding line item
1321                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1322                  * is missing from the list above. */
1323                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1324                          "Missing obd_stat initializer obd_op "
1325                          "operation at offset %d.\n", i - num_private_stats);
1326         }
1327         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1328         if (rc < 0) {
1329                 lprocfs_free_stats(&stats);
1330         } else {
1331                 obd->obd_stats  = stats;
1332                 obd->obd_cntr_base = num_private_stats;
1333         }
1334         return rc;
1335 }
1336
1337 void lprocfs_free_obd_stats(struct obd_device *obd)
1338 {
1339         if (obd->obd_stats)
1340                 lprocfs_free_stats(&obd->obd_stats);
1341 }
1342
1343 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1344 do {                                                                    \
1345         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1346         LASSERT(coffset < stats->ls_num);                               \
1347         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1348 } while (0)
1349
1350 int lprocfs_alloc_md_stats(struct obd_device *obd,
1351                            unsigned num_private_stats)
1352 {
1353         struct lprocfs_stats *stats;
1354         unsigned int num_stats;
1355         int rc, i;
1356
1357         LASSERT(obd->md_stats == NULL);
1358         LASSERT(obd->obd_proc_entry != NULL);
1359         LASSERT(obd->md_cntr_base == 0);
1360
1361         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1362                     num_private_stats;
1363         stats = lprocfs_alloc_stats(num_stats, 0);
1364         if (stats == NULL)
1365                 return -ENOMEM;
1366
1367         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1368         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1369         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1370         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1371         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1372         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1373         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1374         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1375         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1376         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1377         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1378         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1379         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1380         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1381         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1382         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1383         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1384         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1385         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1386         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1387         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1388         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1389         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1390         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1391         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1392         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1393         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1394         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1395         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1396         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1397
1398         for (i = num_private_stats; i < num_stats; i++) {
1399                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1400                         CERROR("Missing md_stat initializer md_op "
1401                                "operation at offset %d. Aborting.\n",
1402                                i - num_private_stats);
1403                         LBUG();
1404                 }
1405         }
1406         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1407         if (rc < 0) {
1408                 lprocfs_free_stats(&stats);
1409         } else {
1410                 obd->md_stats  = stats;
1411                 obd->md_cntr_base = num_private_stats;
1412         }
1413         return rc;
1414 }
1415
1416 void lprocfs_free_md_stats(struct obd_device *obd)
1417 {
1418         struct lprocfs_stats *stats = obd->md_stats;
1419
1420         if (stats != NULL) {
1421                 obd->md_stats = NULL;
1422                 obd->md_cntr_base = 0;
1423                 lprocfs_free_stats(&stats);
1424         }
1425 }
1426
1427 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1428 {
1429         lprocfs_counter_init(ldlm_stats,
1430                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1431                              0, "ldlm_enqueue", "reqs");
1432         lprocfs_counter_init(ldlm_stats,
1433                              LDLM_CONVERT - LDLM_FIRST_OPC,
1434                              0, "ldlm_convert", "reqs");
1435         lprocfs_counter_init(ldlm_stats,
1436                              LDLM_CANCEL - LDLM_FIRST_OPC,
1437                              0, "ldlm_cancel", "reqs");
1438         lprocfs_counter_init(ldlm_stats,
1439                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1440                              0, "ldlm_bl_callback", "reqs");
1441         lprocfs_counter_init(ldlm_stats,
1442                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1443                              0, "ldlm_cp_callback", "reqs");
1444         lprocfs_counter_init(ldlm_stats,
1445                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1446                              0, "ldlm_gl_callback", "reqs");
1447 }
1448
1449 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1450                          int *eof,  void *data)
1451 {
1452         struct obd_export *exp = data;
1453         LASSERT(exp != NULL);
1454         *eof = 1;
1455         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1456 }
1457
1458 struct exp_uuid_cb_data {
1459         char                   *page;
1460         int                     count;
1461         int                    *eof;
1462         int                    *len;
1463 };
1464
1465 static void
1466 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1467                             int count, int *eof, int *len)
1468 {
1469         cb_data->page = page;
1470         cb_data->count = count;
1471         cb_data->eof = eof;
1472         cb_data->len = len;
1473 }
1474
1475 void lprocfs_exp_print_uuid(void *obj, void *cb_data)
1476 {
1477         struct obd_export *exp = (struct obd_export *)obj;
1478         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1479
1480         if (exp->exp_nid_stats)
1481                 *data->len += snprintf((data->page + *data->len),
1482                                        data->count, "%s\n",
1483                                        obd_uuid2str(&exp->exp_client_uuid));
1484 }
1485
1486 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1487                         int *eof,  void *data)
1488 {
1489         struct nid_stat *stats = (struct nid_stat *)data;
1490         struct exp_uuid_cb_data cb_data;
1491         struct obd_device *obd = stats->nid_obd;
1492         int len = 0;
1493
1494         *eof = 1;
1495         page[0] = '\0';
1496         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1497         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1498                                  lprocfs_exp_print_uuid, &cb_data);
1499         return (*cb_data.len);
1500 }
1501
1502 void lprocfs_exp_print_hash(void *obj, void *cb_data)
1503 {
1504         struct exp_uuid_cb_data *data = cb_data;
1505         struct obd_export       *exp = obj;
1506         lustre_hash_t           *lh;
1507
1508         lh = exp->exp_lock_hash;
1509         if (lh) {
1510                 if (!*data->len)
1511                         *data->len += lustre_hash_debug_header(data->page,
1512                                                                data->count);
1513
1514                 *data->len += lustre_hash_debug_str(lh, data->page + *data->len,
1515                                                     data->count);
1516         }
1517 }
1518
1519 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1520                         int *eof,  void *data)
1521 {
1522         struct nid_stat *stats = (struct nid_stat *)data;
1523         struct exp_uuid_cb_data cb_data;
1524         struct obd_device *obd = stats->nid_obd;
1525         int len = 0;
1526
1527         *eof = 1;
1528         page[0] = '\0';
1529         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1530
1531         lustre_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1532                                  lprocfs_exp_print_hash, &cb_data);
1533         return (*cb_data.len);
1534 }
1535
1536 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1537                                         int count, int *eof,  void *data)
1538 {
1539         *eof = 1;
1540         return snprintf(page, count, "%s\n",
1541                         "Write into this file to clear all nid stats and "
1542                         "stale nid entries");
1543 }
1544 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1545
1546 void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1547 {
1548         struct nid_stat *stat = obj;
1549         int i;
1550         ENTRY;
1551         /* object has only hash + iterate_all references.
1552          * add/delete blocked by hash bucket lock */
1553         CDEBUG(D_INFO,"refcnt %d\n", stat->nid_exp_ref_count);
1554         if (stat->nid_exp_ref_count == 2) {
1555                 hlist_del_init(&stat->nid_hash);
1556                 stat->nid_exp_ref_count--;
1557                 spin_lock(&stat->nid_obd->obd_nid_lock);
1558                 list_move(&stat->nid_list, data);
1559                 spin_unlock(&stat->nid_obd->obd_nid_lock);
1560                 EXIT;
1561                 return;
1562         }
1563         /* we has reference to object - only clear data*/
1564         if (stat->nid_stats)
1565                 lprocfs_clear_stats(stat->nid_stats);
1566
1567         if (stat->nid_brw_stats) {
1568                 for (i = 0; i < BRW_LAST; i++)
1569                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1570         }
1571         EXIT;
1572         return;
1573 }
1574
1575 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1576                                          unsigned long count, void *data)
1577 {
1578         struct obd_device *obd = (struct obd_device *)data;
1579         struct nid_stat *client_stat;
1580         CFS_LIST_HEAD(free_list);
1581
1582         lustre_hash_for_each(obd->obd_nid_stats_hash,
1583                              lprocfs_nid_stats_clear_write_cb, &free_list);
1584
1585         while (!list_empty(&free_list)) {
1586                 client_stat = list_entry(free_list.next, struct nid_stat,
1587                                          nid_list);
1588                 list_del_init(&client_stat->nid_list);
1589                 lprocfs_free_client_stats(client_stat);
1590         }
1591
1592         return count;
1593 }
1594 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1595
1596 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
1597 {
1598         struct nid_stat *new_stat, *old_stat;
1599         struct nid_stat_uuid *new_ns_uuid;
1600         struct obd_device *obd = NULL;
1601         cfs_proc_dir_entry_t *entry;
1602         int rc = 0;
1603         ENTRY;
1604
1605         *newnid = 0;
1606
1607         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1608             !exp->exp_obd->obd_nid_stats_hash)
1609                 RETURN(-EINVAL);
1610
1611         /* not test against zero because eric say:
1612          * You may only test nid against another nid, or LNET_NID_ANY.
1613          * Anything else is nonsense.*/
1614         if (!nid || *nid == LNET_NID_ANY)
1615                 RETURN(0);
1616
1617         obd = exp->exp_obd;
1618
1619         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1620
1621         OBD_ALLOC_PTR(new_stat);
1622         if (new_stat == NULL)
1623                 RETURN(-ENOMEM);
1624
1625         OBD_ALLOC_PTR(new_ns_uuid);
1626         if (new_ns_uuid == NULL) {
1627                 OBD_FREE_PTR(new_stat);
1628                 RETURN(-ENOMEM);
1629         }
1630         CFS_INIT_LIST_HEAD(&new_ns_uuid->ns_uuid_list);
1631         strncpy(new_ns_uuid->ns_uuid.uuid, exp->exp_client_uuid.uuid,
1632                 sizeof(struct obd_uuid));
1633
1634         CFS_INIT_LIST_HEAD(&new_stat->nid_uuid_list);
1635         new_stat->nid               = *nid;
1636         new_stat->nid_obd           = exp->exp_obd;
1637         new_stat->nid_exp_ref_count = 1; /* live in hash after destroy export */
1638
1639         old_stat = lustre_hash_findadd_unique(obd->obd_nid_stats_hash,
1640                                               nid, &new_stat->nid_hash);
1641         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1642                old_stat, libcfs_nid2str(*nid), new_stat->nid_exp_ref_count);
1643
1644         /* Return -EALREADY here so that we know that the /proc
1645          * entry already has been created */
1646         if (old_stat != new_stat) {
1647                 struct nid_stat_uuid *tmp_uuid;
1648                 int found = 0;
1649
1650                 exp->exp_nid_stats = old_stat;
1651                 /* We need to decrement the refcount if the uuid was
1652                  * already in our list */
1653                 spin_lock(&obd->obd_nid_lock);
1654                 list_for_each_entry(tmp_uuid, &old_stat->nid_uuid_list,
1655                                     ns_uuid_list) {
1656                         if (tmp_uuid && obd_uuid_equals(&tmp_uuid->ns_uuid,
1657                                                         &exp->exp_client_uuid)){
1658                                 found = 1;
1659                                 --old_stat->nid_exp_ref_count;
1660                                 break;
1661                         }
1662                 }
1663
1664                 if (!found)
1665                         list_add(&new_ns_uuid->ns_uuid_list,
1666                                  &old_stat->nid_uuid_list);
1667                 else
1668                         OBD_FREE_PTR(new_ns_uuid);
1669
1670                 spin_unlock(&obd->obd_nid_lock);
1671
1672                 GOTO(destroy_new, rc = -EALREADY);
1673         }
1674         /* not found - create */
1675         new_stat->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
1676                                               obd->obd_proc_exports_entry,
1677                                               NULL, NULL);
1678         if (new_stat->nid_proc == NULL) {
1679                 CERROR("Error making export directory for nid %s\n",
1680                        libcfs_nid2str(*nid));
1681                 GOTO(destroy_new_ns, rc = -ENOMEM);
1682         }
1683
1684         /* Add in uuid to our nid_stats list */
1685         spin_lock(&obd->obd_nid_lock);
1686         list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1687         spin_unlock(&obd->obd_nid_lock);
1688
1689         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1690                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1691         if (IS_ERR(entry)) {
1692                 CWARN("Error adding the NID stats file\n");
1693                 rc = PTR_ERR(entry);
1694                 GOTO(destroy_new_ns, rc);
1695         }
1696
1697         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1698                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1699         if (IS_ERR(entry)) {
1700                 CWARN("Error adding the hash file\n");
1701                 lprocfs_remove(&new_stat->nid_proc);
1702                 rc = PTR_ERR(entry);
1703                 GOTO(destroy_new_ns, rc);
1704         }
1705
1706         exp->exp_nid_stats = new_stat;
1707         *newnid = 1;
1708         /* protect competitive add to list, not need locking on destroy */
1709         spin_lock(&obd->obd_nid_lock);
1710         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1711         spin_unlock(&obd->obd_nid_lock);
1712
1713         RETURN(rc);
1714
1715 destroy_new_ns:
1716         lustre_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1717         OBD_FREE_PTR(new_ns_uuid);
1718
1719 destroy_new:
1720         OBD_FREE_PTR(new_stat);
1721         RETURN(rc);
1722 }
1723
1724 int lprocfs_exp_cleanup(struct obd_export *exp)
1725 {
1726         struct nid_stat *stat = exp->exp_nid_stats;
1727         struct nid_stat_uuid *cursor, *tmp;
1728         int found = 0;
1729
1730         if(!stat || !exp->exp_obd)
1731                 RETURN(0);
1732
1733         spin_lock(&exp->exp_obd->obd_nid_lock);
1734         list_for_each_entry_safe(cursor, tmp,
1735                                  &stat->nid_uuid_list,
1736                                  ns_uuid_list) {
1737                 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1738                                               &exp->exp_client_uuid)) {
1739                         found = 1;
1740                         list_del(&cursor->ns_uuid_list);
1741                         OBD_FREE_PTR(cursor);
1742                         --stat->nid_exp_ref_count;
1743                         CDEBUG(D_INFO, "Put stat %p - %d\n", stat,
1744                                stat->nid_exp_ref_count);
1745                         break;
1746                 }
1747         }
1748         spin_unlock(&exp->exp_obd->obd_nid_lock);
1749         if (!found)
1750                 CERROR("obd_export's client uuid %s are not found in its "
1751                        "nid_stats list\n", exp->exp_client_uuid.uuid);
1752
1753         exp->exp_nid_stats = NULL;
1754         lprocfs_free_md_stats(exp->exp_obd);
1755
1756         return 0;
1757 }
1758
1759 int lprocfs_write_helper(const char *buffer, unsigned long count,
1760                          int *val)
1761 {
1762         return lprocfs_write_frac_helper(buffer, count, val, 1);
1763 }
1764
1765 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1766                               int *val, int mult)
1767 {
1768         char kernbuf[20], *end, *pbuf;
1769
1770         if (count > (sizeof(kernbuf) - 1))
1771                 return -EINVAL;
1772
1773         if (copy_from_user(kernbuf, buffer, count))
1774                 return -EFAULT;
1775
1776         kernbuf[count] = '\0';
1777         pbuf = kernbuf;
1778         if (*pbuf == '-') {
1779                 mult = -mult;
1780                 pbuf++;
1781         }
1782
1783         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1784         if (pbuf == end)
1785                 return -EINVAL;
1786
1787         if (end != NULL && *end == '.') {
1788                 int temp_val, pow = 1;
1789                 int i;
1790
1791                 pbuf = end + 1;
1792                 if (strlen(pbuf) > 5)
1793                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1794
1795                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1796
1797                 if (pbuf < end) {
1798                         for (i = 0; i < (end - pbuf); i++)
1799                                 pow *= 10;
1800
1801                         *val += temp_val / pow;
1802                 }
1803         }
1804         return 0;
1805 }
1806
1807 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1808                              int mult)
1809 {
1810         long decimal_val, frac_val;
1811         int prtn;
1812
1813         if (count < 10)
1814                 return -EINVAL;
1815
1816         decimal_val = val / mult;
1817         prtn = snprintf(buffer, count, "%ld", decimal_val);
1818         frac_val = val % mult;
1819
1820         if (prtn < (count - 4) && frac_val > 0) {
1821                 long temp_frac;
1822                 int i, temp_mult = 1, frac_bits = 0;
1823
1824                 temp_frac = frac_val * 10;
1825                 buffer[prtn++] = '.';
1826                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1827                         /* only reserved 2 bits fraction */
1828                         buffer[prtn++] ='0';
1829                         temp_frac *= 10;
1830                         frac_bits++;
1831                 }
1832                 /*
1833                  * Need to think these cases :
1834                  *      1. #echo x.00 > /proc/xxx       output result : x
1835                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1836                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1837                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1838                  *      Only reserved 2 bits fraction.
1839                  */
1840                 for (i = 0; i < (5 - prtn); i++)
1841                         temp_mult *= 10;
1842
1843                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1844                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1845                                  frac_val * temp_mult / mult);
1846
1847                 prtn--;
1848                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1849                         prtn--;
1850                         if (buffer[prtn] == '.') {
1851                                 prtn--;
1852                                 break;
1853                         }
1854                 }
1855                 prtn++;
1856         }
1857         buffer[prtn++] ='\n';
1858         return prtn;
1859 }
1860
1861 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1862 {
1863         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1864 }
1865
1866 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1867                               __u64 *val, int mult)
1868 {
1869         char kernbuf[22], *end, *pbuf;
1870         __u64 whole, frac = 0, units;
1871         unsigned frac_d = 1;
1872
1873         if (count > (sizeof(kernbuf) - 1) )
1874                 return -EINVAL;
1875
1876         if (copy_from_user(kernbuf, buffer, count))
1877                 return -EFAULT;
1878
1879         kernbuf[count] = '\0';
1880         pbuf = kernbuf;
1881         if (*pbuf == '-') {
1882                 mult = -mult;
1883                 pbuf++;
1884         }
1885
1886         whole = simple_strtoull(pbuf, &end, 10);
1887         if (pbuf == end)
1888                 return -EINVAL;
1889
1890         if (end != NULL && *end == '.') {
1891                 int i;
1892                 pbuf = end + 1;
1893
1894                 /* need to limit frac_d to a __u32 */
1895                 if (strlen(pbuf) > 10)
1896                         pbuf[10] = '\0';
1897
1898                 frac = simple_strtoull(pbuf, &end, 10);
1899                 /* count decimal places */
1900                 for (i = 0; i < (end - pbuf); i++)
1901                         frac_d *= 10;
1902         }
1903
1904         units = 1;
1905         switch(*end) {
1906         case 'p': case 'P':
1907                 units <<= 10;
1908         case 't': case 'T':
1909                 units <<= 10;
1910         case 'g': case 'G':
1911                 units <<= 10;
1912         case 'm': case 'M':
1913                 units <<= 10;
1914         case 'k': case 'K':
1915                 units <<= 10;
1916         }
1917         /* Specified units override the multiplier */
1918         if (units)
1919                 mult = mult < 0 ? -units : units;
1920
1921         frac *= mult;
1922         do_div(frac, frac_d);
1923         *val = whole * mult + frac;
1924         return 0;
1925 }
1926
1927 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
1928                        struct file_operations *seq_fops, void *data)
1929 {
1930         struct proc_dir_entry *entry;
1931         ENTRY;
1932
1933         entry = create_proc_entry(name, mode, parent);
1934         if (entry == NULL)
1935                 RETURN(-ENOMEM);
1936         entry->proc_fops = seq_fops;
1937         entry->data = data;
1938
1939         RETURN(0);
1940 }
1941 EXPORT_SYMBOL(lprocfs_seq_create);
1942
1943 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1944                                       mode_t mode,
1945                                       struct file_operations *seq_fops,
1946                                       void *data)
1947 {
1948         return (lprocfs_seq_create(dev->obd_proc_entry, name,
1949                                    mode, seq_fops, data));
1950 }
1951 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1952
1953 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1954 {
1955         if (value >= OBD_HIST_MAX)
1956                 value = OBD_HIST_MAX - 1;
1957
1958         spin_lock(&oh->oh_lock);
1959         oh->oh_buckets[value]++;
1960         spin_unlock(&oh->oh_lock);
1961 }
1962 EXPORT_SYMBOL(lprocfs_oh_tally);
1963
1964 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1965 {
1966         unsigned int val;
1967
1968         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1969                 ;
1970
1971         lprocfs_oh_tally(oh, val);
1972 }
1973 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1974
1975 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1976 {
1977         unsigned long ret = 0;
1978         int i;
1979
1980         for (i = 0; i < OBD_HIST_MAX; i++)
1981                 ret +=  oh->oh_buckets[i];
1982         return ret;
1983 }
1984 EXPORT_SYMBOL(lprocfs_oh_sum);
1985
1986 void lprocfs_oh_clear(struct obd_histogram *oh)
1987 {
1988         spin_lock(&oh->oh_lock);
1989         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1990         spin_unlock(&oh->oh_lock);
1991 }
1992 EXPORT_SYMBOL(lprocfs_oh_clear);
1993
1994 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1995                         int count, int *eof, void *data)
1996 {
1997         struct obd_device *obd = data;
1998         int c = 0;
1999
2000         if (obd == NULL)
2001                 return 0;
2002
2003         c += lustre_hash_debug_header(page, count);
2004         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2005         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2006         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2007
2008         return c;
2009 }
2010 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2011
2012 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2013                                    int count, int *eof, void *data)
2014 {
2015         struct obd_device *obd = data;
2016         int len = 0, size;
2017
2018         LASSERT(obd != NULL);
2019         LASSERT(count >= 0);
2020
2021         /* Set start of user data returned to
2022            page + off since the user may have
2023            requested to read much smaller than
2024            what we need to read */
2025         *start = page + off;
2026
2027         /* We know we are allocated a page here.
2028            Also we know that this function will
2029            not need to write more than a page
2030            so we can truncate at CFS_PAGE_SIZE.  */
2031         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2032
2033         /* Initialize the page */
2034         memset(page, 0, size);
2035
2036         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2037                 goto out;
2038         if (obd->obd_max_recoverable_clients == 0) {
2039                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2040                         goto out;
2041
2042                 goto fclose;
2043         }
2044
2045         /* sampled unlocked, but really... */
2046         if (obd->obd_recovering == 0) {
2047                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2048                         goto out;
2049                 if (lprocfs_obd_snprintf(&page, size, &len,
2050                                          "recovery_start: %lu\n",
2051                                          obd->obd_recovery_start) <= 0)
2052                         goto out;
2053                 if (lprocfs_obd_snprintf(&page, size, &len,
2054                                          "recovery_duration: %lu\n",
2055                                          obd->obd_recovery_end -
2056                                          obd->obd_recovery_start) <= 0)
2057                         goto out;
2058                 /* Number of clients that have completed recovery */
2059                 if (lprocfs_obd_snprintf(&page, size, &len,
2060                                          "completed_clients: %d/%d\n",
2061                                          obd->obd_max_recoverable_clients -
2062                                          obd->obd_recoverable_clients,
2063                                          obd->obd_max_recoverable_clients) <= 0)
2064                         goto out;
2065                 if (lprocfs_obd_snprintf(&page, size, &len,
2066                                          "replayed_requests: %d\n",
2067                                          obd->obd_replayed_requests) <= 0)
2068                         goto out;
2069                 if (lprocfs_obd_snprintf(&page, size, &len,
2070                                          "last_transno: "LPD64"\n",
2071                                          obd->obd_next_recovery_transno - 1)<=0)
2072                         goto out;
2073                 goto fclose;
2074         }
2075
2076         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2077                 goto out;
2078         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2079                                  obd->obd_recovery_start) <= 0)
2080                 goto out;
2081         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2082                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2083                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2084                 goto out;
2085         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2086                                  obd->obd_connected_clients,
2087                                  obd->obd_max_recoverable_clients) <= 0)
2088                 goto out;
2089         /* Number of clients that have completed recovery */
2090         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2091                                  obd->obd_max_recoverable_clients -
2092                                  obd->obd_recoverable_clients,
2093                                  obd->obd_max_recoverable_clients) <= 0)
2094                 goto out;
2095         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2096                                  obd->obd_replayed_requests) <= 0)
2097                 goto out;
2098         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2099                                  obd->obd_requests_queued_for_recovery) <= 0)
2100                 goto out;
2101
2102         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2103                                  obd->obd_next_recovery_transno) <= 0)
2104                 goto out;
2105
2106 fclose:
2107         *eof = 1;
2108 out:
2109         return min(count, len - (int)off);
2110 }
2111 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2112
2113 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2114                                     int count, int *eof, void *data)
2115 {
2116         struct obd_device *obd = data;
2117         LASSERT(obd != NULL);
2118
2119         return snprintf(page, count, "%lu\n", obd->obd_recovery_max_time);
2120 }
2121 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2122
2123 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2124                                     unsigned long count, void *data)
2125 {
2126         struct obd_device *obd = data;
2127         int val, rc;
2128         LASSERT(obd != NULL);
2129
2130         rc = lprocfs_write_helper(buffer, count, &val);
2131         if (rc)
2132                 return rc;
2133
2134         obd->obd_recovery_max_time = val;
2135         return count;
2136 }
2137 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2138
2139 EXPORT_SYMBOL(lprocfs_register);
2140 EXPORT_SYMBOL(lprocfs_srch);
2141 EXPORT_SYMBOL(lprocfs_remove);
2142 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2143 EXPORT_SYMBOL(lprocfs_add_vars);
2144 EXPORT_SYMBOL(lprocfs_obd_setup);
2145 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2146 EXPORT_SYMBOL(lprocfs_add_simple);
2147 EXPORT_SYMBOL(lprocfs_add_symlink);
2148 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2149 EXPORT_SYMBOL(lprocfs_alloc_stats);
2150 EXPORT_SYMBOL(lprocfs_free_stats);
2151 EXPORT_SYMBOL(lprocfs_clear_stats);
2152 EXPORT_SYMBOL(lprocfs_register_stats);
2153 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2154 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2155 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2156 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2157 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2158 EXPORT_SYMBOL(lprocfs_exp_setup);
2159 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2160
2161 EXPORT_SYMBOL(lprocfs_rd_u64);
2162 EXPORT_SYMBOL(lprocfs_rd_atomic);
2163 EXPORT_SYMBOL(lprocfs_wr_atomic);
2164 EXPORT_SYMBOL(lprocfs_rd_uint);
2165 EXPORT_SYMBOL(lprocfs_wr_uint);
2166 EXPORT_SYMBOL(lprocfs_rd_uuid);
2167 EXPORT_SYMBOL(lprocfs_rd_name);
2168 EXPORT_SYMBOL(lprocfs_rd_fstype);
2169 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2170 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2171 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2172 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2173 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2174 EXPORT_SYMBOL(lprocfs_rd_import);
2175 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2176 EXPORT_SYMBOL(lprocfs_rd_blksize);
2177 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2178 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2179 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2180 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2181 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2182
2183 EXPORT_SYMBOL(lprocfs_write_helper);
2184 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2185 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2186 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2187 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2188 #endif /* LPROCFS*/