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