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