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