Whamcloud - gitweb
76e91ba200b8838cfd14b41691ff1b6232fb2263
[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 entrys.
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(client_stat->nid_brw_stats, sizeof(struct brw_stats));
840
841         if (client_stat->nid_ldlm_stats)
842                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
843
844         OBD_FREE(client_stat, sizeof(*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(new_stat, sizeof(struct nid_stat));
1552         if (new_stat == NULL)
1553                 RETURN(-ENOMEM);
1554
1555         OBD_ALLOC(new_ns_uuid, sizeof(struct nid_stat_uuid));
1556         if (new_ns_uuid == NULL) {
1557                 OBD_FREE(new_stat, sizeof(struct nid_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(new_ns_uuid, sizeof(struct nid_stat));
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                 lustre_hash_del(obd->obd_nid_stats_hash, nid,
1617                                 &new_stat->nid_hash);
1618                 GOTO(destroy_new, rc = -ENOMEM);
1619         }
1620
1621         /* Add in uuid to our nid_stats list */
1622         spin_lock(&obd->obd_nid_lock);
1623         list_add(&new_ns_uuid->ns_uuid_list, &new_stat->nid_uuid_list);
1624         spin_unlock(&obd->obd_nid_lock);
1625
1626         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1627                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1628         if (IS_ERR(entry)) {
1629                 CWARN("Error adding the NID stats file\n");
1630                 rc = PTR_ERR(entry);
1631         }
1632
1633         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1634                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1635         if (IS_ERR(entry)) {
1636                 CWARN("Error adding the hash file\n");
1637                 rc = PTR_ERR(entry);
1638         }
1639
1640         exp->exp_nid_stats = new_stat;
1641         *newnid = 1;
1642         RETURN(rc);
1643
1644 destroy_new:
1645         spin_lock(&obd->obd_nid_lock);
1646         list_del(&new_stat->nid_list);
1647         spin_unlock(&obd->obd_nid_lock);
1648         OBD_FREE(new_stat, sizeof(struct nid_stat));
1649         RETURN(rc);
1650 }
1651
1652 int lprocfs_exp_cleanup(struct obd_export *exp)
1653 {
1654         struct nid_stat *stat = exp->exp_nid_stats;
1655         struct nid_stat_uuid *cursor, *tmp;
1656         int found = 0;
1657
1658         if(!stat || !exp->exp_obd)
1659                 RETURN(0);
1660
1661         spin_lock(&exp->exp_obd->obd_nid_lock);
1662         list_for_each_entry_safe(cursor, tmp,
1663                                  &stat->nid_uuid_list,
1664                                  ns_uuid_list) {
1665                 if (cursor && obd_uuid_equals(&cursor->ns_uuid,
1666                                               &exp->exp_client_uuid)) {
1667                         found = 1;
1668                         list_del(&cursor->ns_uuid_list);
1669                         OBD_FREE(cursor, sizeof(struct nid_stat_uuid));
1670                         break;
1671                 }
1672         }
1673         spin_unlock(&exp->exp_obd->obd_nid_lock);
1674         if (!found)
1675                 CERROR("obd_export's client uuid %s are not found in its "
1676                        "nid_stats list\n", exp->exp_client_uuid.uuid);
1677
1678         stat->nid_exp_ref_count--;
1679         CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
1680
1681         exp->exp_nid_stats = NULL;
1682         lprocfs_free_md_stats(exp->exp_obd);
1683
1684         return 0;
1685 }
1686
1687 int lprocfs_write_helper(const char *buffer, unsigned long count,
1688                          int *val)
1689 {
1690         return lprocfs_write_frac_helper(buffer, count, val, 1);
1691 }
1692
1693 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1694                               int *val, int mult)
1695 {
1696         char kernbuf[20], *end, *pbuf;
1697
1698         if (count > (sizeof(kernbuf) - 1))
1699                 return -EINVAL;
1700
1701         if (copy_from_user(kernbuf, buffer, count))
1702                 return -EFAULT;
1703
1704         kernbuf[count] = '\0';
1705         pbuf = kernbuf;
1706         if (*pbuf == '-') {
1707                 mult = -mult;
1708                 pbuf++;
1709         }
1710
1711         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1712         if (pbuf == end)
1713                 return -EINVAL;
1714
1715         if (end != NULL && *end == '.') {
1716                 int temp_val, pow = 1;
1717                 int i;
1718
1719                 pbuf = end + 1;
1720                 if (strlen(pbuf) > 5)
1721                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1722
1723                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1724
1725                 if (pbuf < end) {
1726                         for (i = 0; i < (end - pbuf); i++)
1727                                 pow *= 10;
1728
1729                         *val += temp_val / pow;
1730                 }
1731         }
1732         return 0;
1733 }
1734
1735 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1736 {
1737         long decimal_val, frac_val;
1738         int prtn;
1739
1740         if (count < 10)
1741                 return -EINVAL;
1742
1743         decimal_val = val / mult;
1744         prtn = snprintf(buffer, count, "%ld", decimal_val);
1745         frac_val = val % mult;
1746
1747         if (prtn < (count - 4) && frac_val > 0) {
1748                 long temp_frac;
1749                 int i, temp_mult = 1, frac_bits = 0;
1750
1751                 temp_frac = frac_val * 10;
1752                 buffer[prtn++] = '.';
1753                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1754                         buffer[prtn++] ='0';
1755                         temp_frac *= 10;
1756                         frac_bits++;
1757                 }
1758                 /*
1759                   Need to think these cases :
1760                         1. #echo x.00 > /proc/xxx       output result : x
1761                         2. #echo x.0x > /proc/xxx       output result : x.0x
1762                         3. #echo x.x0 > /proc/xxx       output result : x.x
1763                         4. #echo x.xx > /proc/xxx       output result : x.xx
1764                         Only reserved 2bits fraction.
1765                  */
1766                 for (i = 0; i < (5 - prtn); i++)
1767                         temp_mult *= 10;
1768
1769                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1770                 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1771
1772                 prtn--;
1773                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1774                         prtn--;
1775                         if (buffer[prtn] == '.') {
1776                                 prtn--;
1777                                 break;
1778                         }
1779                 }
1780                 prtn++;
1781         }
1782         buffer[prtn++] ='\n';
1783         return prtn;
1784 }
1785
1786 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1787 {
1788         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1789 }
1790
1791 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1792                               __u64 *val, int mult)
1793 {
1794         char kernbuf[22], *end, *pbuf;
1795         __u64 whole, frac = 0, units;
1796         unsigned frac_d = 1;
1797
1798         if (count > (sizeof(kernbuf) - 1) )
1799                 return -EINVAL;
1800
1801         if (copy_from_user(kernbuf, buffer, count))
1802                 return -EFAULT;
1803
1804         kernbuf[count] = '\0';
1805         pbuf = kernbuf;
1806         if (*pbuf == '-') {
1807                 mult = -mult;
1808                 pbuf++;
1809         }
1810
1811         whole = simple_strtoull(pbuf, &end, 10);
1812         if (pbuf == end)
1813                 return -EINVAL;
1814
1815         if (end != NULL && *end == '.') {
1816                 int i;
1817                 pbuf = end + 1;
1818
1819                 /* need to limit frac_d to a __u32 */
1820                 if (strlen(pbuf) > 10)
1821                         pbuf[10] = '\0';
1822
1823                 frac = simple_strtoull(pbuf, &end, 10);
1824                 /* count decimal places */
1825                 for (i = 0; i < (end - pbuf); i++)
1826                         frac_d *= 10;
1827         }
1828
1829         units = 1;
1830         switch(*end) {
1831         case 'p': case 'P':
1832                 units <<= 10;
1833         case 't': case 'T':
1834                 units <<= 10;
1835         case 'g': case 'G':
1836                 units <<= 10;
1837         case 'm': case 'M':
1838                 units <<= 10;
1839         case 'k': case 'K':
1840                 units <<= 10;
1841         }
1842         /* Specified units override the multiplier */
1843         if (units)
1844                 mult = mult < 0 ? -units : units;
1845
1846         frac *= mult;
1847         do_div(frac, frac_d);
1848         *val = whole * mult + frac;
1849         return 0;
1850 }
1851
1852 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1853                        char *name, mode_t mode,
1854                        struct file_operations *seq_fops, void *data)
1855 {
1856         struct proc_dir_entry *entry;
1857         ENTRY;
1858
1859         entry = create_proc_entry(name, mode, parent);
1860         if (entry == NULL)
1861                 RETURN(-ENOMEM);
1862         entry->proc_fops = seq_fops;
1863         entry->data = data;
1864
1865         RETURN(0);
1866 }
1867 EXPORT_SYMBOL(lprocfs_seq_create);
1868
1869 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1870                                       mode_t mode,
1871                                       struct file_operations *seq_fops,
1872                                       void *data)
1873 {
1874         return (lprocfs_seq_create(dev->obd_proc_entry, name,
1875                                    mode, seq_fops, data));
1876 }
1877 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1878
1879 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1880 {
1881         if (value >= OBD_HIST_MAX)
1882                 value = OBD_HIST_MAX - 1;
1883
1884         spin_lock(&oh->oh_lock);
1885         oh->oh_buckets[value]++;
1886         spin_unlock(&oh->oh_lock);
1887 }
1888 EXPORT_SYMBOL(lprocfs_oh_tally);
1889
1890 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1891 {
1892         unsigned int val;
1893
1894         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1895                 ;
1896
1897         lprocfs_oh_tally(oh, val);
1898 }
1899 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1900
1901 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1902 {
1903         unsigned long ret = 0;
1904         int i;
1905
1906         for (i = 0; i < OBD_HIST_MAX; i++)
1907                 ret +=  oh->oh_buckets[i];
1908         return ret;
1909 }
1910 EXPORT_SYMBOL(lprocfs_oh_sum);
1911
1912 void lprocfs_oh_clear(struct obd_histogram *oh)
1913 {
1914         spin_lock(&oh->oh_lock);
1915         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1916         spin_unlock(&oh->oh_lock);
1917 }
1918 EXPORT_SYMBOL(lprocfs_oh_clear);
1919
1920 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
1921                         int count, int *eof, void *data)
1922 {
1923         struct obd_device *obd = data;
1924         int c = 0;
1925
1926         if (obd == NULL)
1927                 return 0;
1928
1929         c += lustre_hash_debug_header(page, count);
1930         c += lustre_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
1931         c += lustre_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
1932         c += lustre_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
1933
1934         return c;
1935 }
1936 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
1937
1938 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1939                                    int count, int *eof, void *data)
1940 {
1941         struct obd_device *obd = data;
1942         int len = 0, size;
1943
1944         LASSERT(obd != NULL);
1945         LASSERT(count >= 0);
1946
1947         /* Set start of user data returned to
1948            page + off since the user may have
1949            requested to read much smaller than
1950            what we need to read */
1951         *start = page + off;
1952
1953         /* We know we are allocated a page here.
1954            Also we know that this function will
1955            not need to write more than a page
1956            so we can truncate at CFS_PAGE_SIZE.  */
1957         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1958
1959         /* Initialize the page */
1960         memset(page, 0, size);
1961
1962         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1963                 goto out;
1964         if (obd->obd_max_recoverable_clients == 0) {
1965                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
1966                         goto out;
1967
1968                 goto fclose;
1969         }
1970
1971         /* sampled unlocked, but really... */
1972         if (obd->obd_recovering == 0) {
1973                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1974                         goto out;
1975                 if (lprocfs_obd_snprintf(&page, size, &len,
1976                                          "recovery_start: %lu\n",
1977                                          obd->obd_recovery_start) <= 0)
1978                         goto out;
1979                 if (lprocfs_obd_snprintf(&page, size, &len,
1980                                          "recovery_duration: %lu\n",
1981                                          obd->obd_recovery_end -
1982                                          obd->obd_recovery_start) <= 0)
1983                         goto out;
1984                 /* Number of clients that have completed recovery */
1985                 if (lprocfs_obd_snprintf(&page, size, &len,
1986                                          "completed_clients: %d/%d\n",
1987                                          obd->obd_max_recoverable_clients -
1988                                          obd->obd_recoverable_clients,
1989                                          obd->obd_max_recoverable_clients) <= 0)
1990                         goto out;
1991                 if (lprocfs_obd_snprintf(&page, size, &len,
1992                                          "replayed_requests: %d\n",
1993                                          obd->obd_replayed_requests) <= 0)
1994                         goto out;
1995                 if (lprocfs_obd_snprintf(&page, size, &len,
1996                                          "last_transno: "LPD64"\n",
1997                                          obd->obd_next_recovery_transno - 1)<=0)
1998                         goto out;
1999                 goto fclose;
2000         }
2001
2002         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2003                 goto out;
2004         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2005                                  obd->obd_recovery_start) <= 0)
2006                 goto out;
2007         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2008                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2009                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2010                 goto out;
2011         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2012                                  obd->obd_connected_clients,
2013                                  obd->obd_max_recoverable_clients) <= 0)
2014                 goto out;
2015         /* Number of clients that have completed recovery */
2016         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d/%d\n",
2017                                  obd->obd_max_recoverable_clients -
2018                                  obd->obd_recoverable_clients,
2019                                  obd->obd_max_recoverable_clients) <= 0)
2020                 goto out;
2021         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d/??\n",
2022                                  obd->obd_replayed_requests) <= 0)
2023                 goto out;
2024         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2025                                  obd->obd_requests_queued_for_recovery) <= 0)
2026                 goto out;
2027
2028         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2029                                  obd->obd_next_recovery_transno) <= 0)
2030                 goto out;
2031
2032 fclose:
2033         *eof = 1;
2034 out:
2035         return min(count, len - (int)off);
2036 }
2037 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2038
2039 int lprocfs_obd_rd_recovery_maxtime(char *page, char **start, off_t off,
2040                                     int count, int *eof, void *data)
2041 {
2042         struct obd_device *obd = (struct obd_device *)data;
2043         LASSERT(obd != NULL);
2044
2045         return snprintf(page, count, "%lu\n",
2046                         obd->obd_recovery_max_time);
2047 }
2048 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_maxtime);
2049
2050 int lprocfs_obd_wr_recovery_maxtime(struct file *file, const char *buffer,
2051                                     unsigned long count, void *data)
2052 {
2053         struct obd_device *obd = (struct obd_device *)data;
2054         int val, rc;
2055         LASSERT(obd != NULL);
2056
2057         rc = lprocfs_write_helper(buffer, count, &val);
2058         if (rc)
2059                 return rc;
2060
2061         obd->obd_recovery_max_time = val;
2062         return count;
2063 }
2064 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
2065
2066 EXPORT_SYMBOL(lprocfs_register);
2067 EXPORT_SYMBOL(lprocfs_srch);
2068 EXPORT_SYMBOL(lprocfs_remove);
2069 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2070 EXPORT_SYMBOL(lprocfs_add_vars);
2071 EXPORT_SYMBOL(lprocfs_obd_setup);
2072 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2073 EXPORT_SYMBOL(lprocfs_add_simple);
2074 EXPORT_SYMBOL(lprocfs_add_symlink);
2075 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2076 EXPORT_SYMBOL(lprocfs_alloc_stats);
2077 EXPORT_SYMBOL(lprocfs_free_stats);
2078 EXPORT_SYMBOL(lprocfs_clear_stats);
2079 EXPORT_SYMBOL(lprocfs_register_stats);
2080 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2081 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2082 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2083 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2084 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2085 EXPORT_SYMBOL(lprocfs_exp_setup);
2086 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2087
2088 EXPORT_SYMBOL(lprocfs_rd_u64);
2089 EXPORT_SYMBOL(lprocfs_rd_atomic);
2090 EXPORT_SYMBOL(lprocfs_wr_atomic);
2091 EXPORT_SYMBOL(lprocfs_rd_uint);
2092 EXPORT_SYMBOL(lprocfs_wr_uint);
2093 EXPORT_SYMBOL(lprocfs_rd_uuid);
2094 EXPORT_SYMBOL(lprocfs_rd_name);
2095 EXPORT_SYMBOL(lprocfs_rd_fstype);
2096 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2097 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2098 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2099 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2100 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2101 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2102 EXPORT_SYMBOL(lprocfs_rd_blksize);
2103 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2104 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2105 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2106 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2107 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2108
2109 EXPORT_SYMBOL(lprocfs_write_helper);
2110 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2111 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2112 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2113 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2114 #endif /* LPROCFS*/