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