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