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