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