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