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