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