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