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