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