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