Whamcloud - gitweb
b=22176 Add .sync_fs super block handler
[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         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync_fs);
1477 }
1478
1479 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
1480 {
1481         struct lprocfs_stats *stats;
1482         unsigned int num_stats;
1483         int rc, i;
1484
1485         LASSERT(obd->obd_stats == NULL);
1486         LASSERT(obd->obd_proc_entry != NULL);
1487         LASSERT(obd->obd_cntr_base == 0);
1488
1489         num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
1490                 num_private_stats - 1 /* o_owner */;
1491         stats = lprocfs_alloc_stats(num_stats, 0);
1492         if (stats == NULL)
1493                 return -ENOMEM;
1494
1495         lprocfs_init_ops_stats(num_private_stats, stats);
1496
1497         for (i = num_private_stats; i < num_stats; i++) {
1498                 /* If this LBUGs, it is likely that an obd
1499                  * operation was added to struct obd_ops in
1500                  * <obd.h>, and that the corresponding line item
1501                  * LPROCFS_OBD_OP_INIT(.., .., opname)
1502                  * is missing from the list above. */
1503                 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
1504                          "Missing obd_stat initializer obd_op "
1505                          "operation at offset %d.\n", i - num_private_stats);
1506         }
1507         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1508         if (rc < 0) {
1509                 lprocfs_free_stats(&stats);
1510         } else {
1511                 obd->obd_stats  = stats;
1512                 obd->obd_cntr_base = num_private_stats;
1513         }
1514         return rc;
1515 }
1516
1517 void lprocfs_free_obd_stats(struct obd_device *obd)
1518 {
1519         if (obd->obd_stats)
1520                 lprocfs_free_stats(&obd->obd_stats);
1521 }
1522
1523 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
1524 do {                                                                    \
1525         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
1526         LASSERT(coffset < stats->ls_num);                               \
1527         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
1528 } while (0)
1529
1530 int lprocfs_alloc_md_stats(struct obd_device *obd,
1531                            unsigned num_private_stats)
1532 {
1533         struct lprocfs_stats *stats;
1534         unsigned int num_stats;
1535         int rc, i;
1536
1537         LASSERT(obd->md_stats == NULL);
1538         LASSERT(obd->obd_proc_entry != NULL);
1539         LASSERT(obd->md_cntr_base == 0);
1540
1541         num_stats = 1 + MD_COUNTER_OFFSET(revalidate_lock) +
1542                     num_private_stats;
1543         stats = lprocfs_alloc_stats(num_stats, 0);
1544         if (stats == NULL)
1545                 return -ENOMEM;
1546
1547         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
1548         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
1549         LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata);
1550         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
1551         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
1552         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
1553         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
1554         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
1555         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
1556         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
1557         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
1558         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
1559         LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
1560         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
1561         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
1562         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
1563         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
1564         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
1565         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
1566         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
1567         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
1568         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
1569         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
1570         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
1571         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
1572         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
1573         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
1574         LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
1575         LPROCFS_MD_OP_INIT(num_private_stats, stats, unpack_capa);
1576         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1577         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_getattr_async);
1578         LPROCFS_MD_OP_INIT(num_private_stats, stats, revalidate_lock);
1579
1580         for (i = num_private_stats; i < num_stats; i++) {
1581                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1582                         CERROR("Missing md_stat initializer md_op "
1583                                "operation at offset %d. Aborting.\n",
1584                                i - num_private_stats);
1585                         LBUG();
1586                 }
1587         }
1588         rc = lprocfs_register_stats(obd->obd_proc_entry, "md_stats", stats);
1589         if (rc < 0) {
1590                 lprocfs_free_stats(&stats);
1591         } else {
1592                 obd->md_stats  = stats;
1593                 obd->md_cntr_base = num_private_stats;
1594         }
1595         return rc;
1596 }
1597
1598 void lprocfs_free_md_stats(struct obd_device *obd)
1599 {
1600         struct lprocfs_stats *stats = obd->md_stats;
1601
1602         if (stats != NULL) {
1603                 obd->md_stats = NULL;
1604                 obd->md_cntr_base = 0;
1605                 lprocfs_free_stats(&stats);
1606         }
1607 }
1608
1609 void lprocfs_init_ldlm_stats(struct lprocfs_stats *ldlm_stats)
1610 {
1611         lprocfs_counter_init(ldlm_stats,
1612                              LDLM_ENQUEUE - LDLM_FIRST_OPC,
1613                              0, "ldlm_enqueue", "reqs");
1614         lprocfs_counter_init(ldlm_stats,
1615                              LDLM_CONVERT - LDLM_FIRST_OPC,
1616                              0, "ldlm_convert", "reqs");
1617         lprocfs_counter_init(ldlm_stats,
1618                              LDLM_CANCEL - LDLM_FIRST_OPC,
1619                              0, "ldlm_cancel", "reqs");
1620         lprocfs_counter_init(ldlm_stats,
1621                              LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1622                              0, "ldlm_bl_callback", "reqs");
1623         lprocfs_counter_init(ldlm_stats,
1624                              LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1625                              0, "ldlm_cp_callback", "reqs");
1626         lprocfs_counter_init(ldlm_stats,
1627                              LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1628                              0, "ldlm_gl_callback", "reqs");
1629 }
1630
1631 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1632                          int *eof,  void *data)
1633 {
1634         struct obd_export *exp = data;
1635         LASSERT(exp != NULL);
1636         *eof = 1;
1637         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1638 }
1639
1640 struct exp_uuid_cb_data {
1641         char                   *page;
1642         int                     count;
1643         int                    *eof;
1644         int                    *len;
1645 };
1646
1647 static void
1648 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
1649                             int count, int *eof, int *len)
1650 {
1651         cb_data->page = page;
1652         cb_data->count = count;
1653         cb_data->eof = eof;
1654         cb_data->len = len;
1655 }
1656
1657 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1658                            cfs_hlist_node_t *hnode, void *cb_data)
1659
1660 {
1661         struct obd_export *exp = cfs_hash_object(hs, hnode);
1662         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
1663
1664         if (exp->exp_nid_stats)
1665                 *data->len += snprintf((data->page + *data->len),
1666                                        data->count, "%s\n",
1667                                        obd_uuid2str(&exp->exp_client_uuid));
1668         return 0;
1669 }
1670
1671 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1672                         int *eof,  void *data)
1673 {
1674         struct nid_stat *stats = (struct nid_stat *)data;
1675         struct exp_uuid_cb_data cb_data;
1676         struct obd_device *obd = stats->nid_obd;
1677         int len = 0;
1678
1679         *eof = 1;
1680         page[0] = '\0';
1681         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1682         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1683                               lprocfs_exp_print_uuid, &cb_data);
1684         return (*cb_data.len);
1685 }
1686
1687 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
1688                            cfs_hlist_node_t *hnode, void *cb_data)
1689
1690 {
1691         struct exp_uuid_cb_data *data = cb_data;
1692         struct obd_export       *exp = cfs_hash_object(hs, hnode);
1693
1694         LASSERT(hs == exp->exp_lock_hash);
1695         if (!*data->len) {
1696                 *data->len += cfs_hash_debug_header(data->page,
1697                                                     data->count);
1698         }
1699         *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
1700                                          data->count);
1701         return 0;
1702 }
1703
1704 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
1705                         int *eof,  void *data)
1706 {
1707         struct nid_stat *stats = (struct nid_stat *)data;
1708         struct exp_uuid_cb_data cb_data;
1709         struct obd_device *obd = stats->nid_obd;
1710         int len = 0;
1711
1712         *eof = 1;
1713         page[0] = '\0';
1714         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
1715
1716         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
1717                               lprocfs_exp_print_hash, &cb_data);
1718         return (*cb_data.len);
1719 }
1720
1721 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
1722                                         int count, int *eof,  void *data)
1723 {
1724         *eof = 1;
1725         return snprintf(page, count, "%s\n",
1726                         "Write into this file to clear all nid stats and "
1727                         "stale nid entries");
1728 }
1729 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
1730
1731 int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
1732 {
1733         struct nid_stat *stat = obj;
1734         int i;
1735         ENTRY;
1736         /* object has only hash + iterate_all references.
1737          * add/delete blocked by hash bucket lock */
1738         CDEBUG(D_INFO,"refcnt %d\n", cfs_atomic_read(&stat->nid_exp_ref_count));
1739         if (cfs_atomic_read(&stat->nid_exp_ref_count) == 2) {
1740                 cfs_spin_lock(&stat->nid_obd->obd_nid_lock);
1741                 cfs_list_move(&stat->nid_list, data);
1742                 cfs_spin_unlock(&stat->nid_obd->obd_nid_lock);
1743                 RETURN(1);
1744         }
1745         /* we has reference to object - only clear data*/
1746         if (stat->nid_stats)
1747                 lprocfs_clear_stats(stat->nid_stats);
1748
1749         if (stat->nid_brw_stats) {
1750                 for (i = 0; i < BRW_LAST; i++)
1751                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
1752         }
1753         RETURN(0);
1754 }
1755
1756 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
1757                                   unsigned long count, void *data)
1758 {
1759         struct obd_device *obd = (struct obd_device *)data;
1760         struct nid_stat *client_stat;
1761         CFS_LIST_HEAD(free_list);
1762
1763         cfs_hash_cond_del(obd->obd_nid_stats_hash,
1764                           lprocfs_nid_stats_clear_write_cb, &free_list);
1765
1766         while (!cfs_list_empty(&free_list)) {
1767                 client_stat = cfs_list_entry(free_list.next, struct nid_stat,
1768                                              nid_list);
1769                 cfs_list_del_init(&client_stat->nid_list);
1770                 lprocfs_free_client_stats(client_stat);
1771         }
1772
1773         return count;
1774 }
1775 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
1776
1777 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int reconnect,
1778                       int *newnid)
1779 {
1780         struct nid_stat *new_stat, *old_stat;
1781         struct obd_device *obd = NULL;
1782         cfs_proc_dir_entry_t *entry;
1783         char *buffer = NULL;
1784         int rc = 0;
1785         ENTRY;
1786
1787         *newnid = 0;
1788
1789         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
1790             !exp->exp_obd->obd_nid_stats_hash)
1791                 RETURN(-EINVAL);
1792
1793         /* not test against zero because eric say:
1794          * You may only test nid against another nid, or LNET_NID_ANY.
1795          * Anything else is nonsense.*/
1796         if (!nid || *nid == LNET_NID_ANY)
1797                 RETURN(0);
1798
1799         obd = exp->exp_obd;
1800
1801         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
1802
1803         OBD_ALLOC_PTR(new_stat);
1804         if (new_stat == NULL)
1805                 RETURN(-ENOMEM);
1806
1807         new_stat->nid               = *nid;
1808         new_stat->nid_obd           = exp->exp_obd;
1809         /* we need set default refcount to 1 to balance obd_disconnect */
1810         cfs_atomic_set(&new_stat->nid_exp_ref_count, 1);
1811
1812         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
1813                                            nid, &new_stat->nid_hash);
1814         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
1815                old_stat, libcfs_nid2str(*nid),
1816                cfs_atomic_read(&new_stat->nid_exp_ref_count));
1817
1818         /* Return -EALREADY here so that we know that the /proc
1819          * entry already has been created */
1820         if (old_stat != new_stat) {
1821                 /* if this connects to the existing export of same nid,
1822                  * we need to release old stats for obd_disconnect won't
1823                  * balance the reference gotten in "cfs_hash_findadd_uinque" */
1824                 if (reconnect && exp->exp_nid_stats)
1825                         nidstat_putref(old_stat);
1826
1827                 exp->exp_nid_stats = old_stat;
1828                 GOTO(destroy_new, rc = -EALREADY);
1829         }
1830         /* not found - create */
1831         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
1832         if (buffer == NULL)
1833                 GOTO(destroy_new, rc = -ENOMEM);
1834
1835         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
1836         new_stat->nid_proc = lprocfs_register(buffer,
1837                                               obd->obd_proc_exports_entry,
1838                                               NULL, NULL);
1839         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
1840
1841         if (new_stat->nid_proc == NULL) {
1842                 CERROR("Error making export directory for nid %s\n",
1843                        libcfs_nid2str(*nid));
1844                 GOTO(destroy_new_ns, rc = -ENOMEM);
1845         }
1846
1847         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
1848                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
1849         if (IS_ERR(entry)) {
1850                 CWARN("Error adding the NID stats file\n");
1851                 rc = PTR_ERR(entry);
1852                 GOTO(destroy_new_ns, rc);
1853         }
1854
1855         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
1856                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
1857         if (IS_ERR(entry)) {
1858                 CWARN("Error adding the hash file\n");
1859                 rc = PTR_ERR(entry);
1860                 GOTO(destroy_new_ns, rc);
1861         }
1862
1863         exp->exp_nid_stats = new_stat;
1864         *newnid = 1;
1865         /* protect competitive add to list, not need locking on destroy */
1866         cfs_spin_lock(&obd->obd_nid_lock);
1867         cfs_list_add(&new_stat->nid_list, &obd->obd_nid_stats);
1868         cfs_spin_unlock(&obd->obd_nid_lock);
1869
1870         RETURN(rc);
1871
1872 destroy_new_ns:
1873         if (new_stat->nid_proc != NULL)
1874                 lprocfs_remove(&new_stat->nid_proc);
1875         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
1876
1877 destroy_new:
1878         nidstat_putref(new_stat);
1879         OBD_FREE_PTR(new_stat);
1880         RETURN(rc);
1881 }
1882
1883 int lprocfs_exp_cleanup(struct obd_export *exp)
1884 {
1885         struct nid_stat *stat = exp->exp_nid_stats;
1886
1887         if(!stat || !exp->exp_obd)
1888                 RETURN(0);
1889
1890         nidstat_putref(exp->exp_nid_stats);
1891         exp->exp_nid_stats = NULL;
1892
1893         return 0;
1894 }
1895
1896 int lprocfs_write_helper(const char *buffer, unsigned long count,
1897                          int *val)
1898 {
1899         return lprocfs_write_frac_helper(buffer, count, val, 1);
1900 }
1901
1902 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1903                               int *val, int mult)
1904 {
1905         char kernbuf[20], *end, *pbuf;
1906
1907         if (count > (sizeof(kernbuf) - 1))
1908                 return -EINVAL;
1909
1910         if (cfs_copy_from_user(kernbuf, buffer, count))
1911                 return -EFAULT;
1912
1913         kernbuf[count] = '\0';
1914         pbuf = kernbuf;
1915         if (*pbuf == '-') {
1916                 mult = -mult;
1917                 pbuf++;
1918         }
1919
1920         *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1921         if (pbuf == end)
1922                 return -EINVAL;
1923
1924         if (end != NULL && *end == '.') {
1925                 int temp_val, pow = 1;
1926                 int i;
1927
1928                 pbuf = end + 1;
1929                 if (strlen(pbuf) > 5)
1930                         pbuf[5] = '\0'; /*only allow 5bits fractional*/
1931
1932                 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1933
1934                 if (pbuf < end) {
1935                         for (i = 0; i < (end - pbuf); i++)
1936                                 pow *= 10;
1937
1938                         *val += temp_val / pow;
1939                 }
1940         }
1941         return 0;
1942 }
1943
1944 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val,
1945                              int mult)
1946 {
1947         long decimal_val, frac_val;
1948         int prtn;
1949
1950         if (count < 10)
1951                 return -EINVAL;
1952
1953         decimal_val = val / mult;
1954         prtn = snprintf(buffer, count, "%ld", decimal_val);
1955         frac_val = val % mult;
1956
1957         if (prtn < (count - 4) && frac_val > 0) {
1958                 long temp_frac;
1959                 int i, temp_mult = 1, frac_bits = 0;
1960
1961                 temp_frac = frac_val * 10;
1962                 buffer[prtn++] = '.';
1963                 while (frac_bits < 2 && (temp_frac / mult) < 1 ) {
1964                         /* only reserved 2 bits fraction */
1965                         buffer[prtn++] ='0';
1966                         temp_frac *= 10;
1967                         frac_bits++;
1968                 }
1969                 /*
1970                  * Need to think these cases :
1971                  *      1. #echo x.00 > /proc/xxx       output result : x
1972                  *      2. #echo x.0x > /proc/xxx       output result : x.0x
1973                  *      3. #echo x.x0 > /proc/xxx       output result : x.x
1974                  *      4. #echo x.xx > /proc/xxx       output result : x.xx
1975                  *      Only reserved 2 bits fraction.
1976                  */
1977                 for (i = 0; i < (5 - prtn); i++)
1978                         temp_mult *= 10;
1979
1980                 frac_bits = min((int)count - prtn, 3 - frac_bits);
1981                 prtn += snprintf(buffer + prtn, frac_bits, "%ld",
1982                                  frac_val * temp_mult / mult);
1983
1984                 prtn--;
1985                 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1986                         prtn--;
1987                         if (buffer[prtn] == '.') {
1988                                 prtn--;
1989                                 break;
1990                         }
1991                 }
1992                 prtn++;
1993         }
1994         buffer[prtn++] ='\n';
1995         return prtn;
1996 }
1997
1998 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1999 {
2000         return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
2001 }
2002
2003 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
2004                               __u64 *val, int mult)
2005 {
2006         char kernbuf[22], *end, *pbuf;
2007         __u64 whole, frac = 0, units;
2008         unsigned frac_d = 1;
2009
2010         if (count > (sizeof(kernbuf) - 1))
2011                 return -EINVAL;
2012
2013         if (cfs_copy_from_user(kernbuf, buffer, count))
2014                 return -EFAULT;
2015
2016         kernbuf[count] = '\0';
2017         pbuf = kernbuf;
2018         if (*pbuf == '-') {
2019                 mult = -mult;
2020                 pbuf++;
2021         }
2022
2023         whole = simple_strtoull(pbuf, &end, 10);
2024         if (pbuf == end)
2025                 return -EINVAL;
2026
2027         if (end != NULL && *end == '.') {
2028                 int i;
2029                 pbuf = end + 1;
2030
2031                 /* need to limit frac_d to a __u32 */
2032                 if (strlen(pbuf) > 10)
2033                         pbuf[10] = '\0';
2034
2035                 frac = simple_strtoull(pbuf, &end, 10);
2036                 /* count decimal places */
2037                 for (i = 0; i < (end - pbuf); i++)
2038                         frac_d *= 10;
2039         }
2040
2041         units = 1;
2042         switch(*end) {
2043         case 'p': case 'P':
2044                 units <<= 10;
2045         case 't': case 'T':
2046                 units <<= 10;
2047         case 'g': case 'G':
2048                 units <<= 10;
2049         case 'm': case 'M':
2050                 units <<= 10;
2051         case 'k': case 'K':
2052                 units <<= 10;
2053         }
2054         /* Specified units override the multiplier */
2055         if (units)
2056                 mult = mult < 0 ? -units : units;
2057
2058         frac *= mult;
2059         do_div(frac, frac_d);
2060         *val = whole * mult + frac;
2061         return 0;
2062 }
2063
2064 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent, char *name, mode_t mode,
2065                        struct file_operations *seq_fops, void *data)
2066 {
2067         struct proc_dir_entry *entry;
2068         ENTRY;
2069
2070         entry = create_proc_entry(name, mode, parent);
2071         if (entry == NULL)
2072                 RETURN(-ENOMEM);
2073         entry->proc_fops = seq_fops;
2074         entry->data = data;
2075
2076         RETURN(0);
2077 }
2078 EXPORT_SYMBOL(lprocfs_seq_create);
2079
2080 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
2081                                       mode_t mode,
2082                                       struct file_operations *seq_fops,
2083                                       void *data)
2084 {
2085         return (lprocfs_seq_create(dev->obd_proc_entry, name,
2086                                    mode, seq_fops, data));
2087 }
2088 EXPORT_SYMBOL(lprocfs_obd_seq_create);
2089
2090 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
2091 {
2092         if (value >= OBD_HIST_MAX)
2093                 value = OBD_HIST_MAX - 1;
2094
2095         cfs_spin_lock(&oh->oh_lock);
2096         oh->oh_buckets[value]++;
2097         cfs_spin_unlock(&oh->oh_lock);
2098 }
2099 EXPORT_SYMBOL(lprocfs_oh_tally);
2100
2101 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
2102 {
2103         unsigned int val;
2104
2105         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
2106                 ;
2107
2108         lprocfs_oh_tally(oh, val);
2109 }
2110 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
2111
2112 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
2113 {
2114         unsigned long ret = 0;
2115         int i;
2116
2117         for (i = 0; i < OBD_HIST_MAX; i++)
2118                 ret +=  oh->oh_buckets[i];
2119         return ret;
2120 }
2121 EXPORT_SYMBOL(lprocfs_oh_sum);
2122
2123 void lprocfs_oh_clear(struct obd_histogram *oh)
2124 {
2125         cfs_spin_lock(&oh->oh_lock);
2126         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
2127         cfs_spin_unlock(&oh->oh_lock);
2128 }
2129 EXPORT_SYMBOL(lprocfs_oh_clear);
2130
2131 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
2132                         int count, int *eof, void *data)
2133 {
2134         struct obd_device *obd = data;
2135         int c = 0;
2136
2137         if (obd == NULL)
2138                 return 0;
2139
2140         c += cfs_hash_debug_header(page, count);
2141         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
2142         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
2143         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
2144 #ifdef HAVE_QUOTA_SUPPORT
2145         if (obd->u.obt.obt_qctxt.lqc_lqs_hash)
2146                 c += cfs_hash_debug_str(obd->u.obt.obt_qctxt.lqc_lqs_hash,
2147                                         page + c, count - c);
2148 #endif
2149
2150         return c;
2151 }
2152 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
2153
2154 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
2155                                    int count, int *eof, void *data)
2156 {
2157         struct obd_device *obd = data;
2158         int len = 0, size;
2159
2160         LASSERT(obd != NULL);
2161         LASSERT(count >= 0);
2162
2163         /* Set start of user data returned to
2164            page + off since the user may have
2165            requested to read much smaller than
2166            what we need to read */
2167         *start = page + off;
2168
2169         /* We know we are allocated a page here.
2170            Also we know that this function will
2171            not need to write more than a page
2172            so we can truncate at CFS_PAGE_SIZE.  */
2173         size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
2174
2175         /* Initialize the page */
2176         memset(page, 0, size);
2177
2178         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
2179                 goto out;
2180         if (obd->obd_max_recoverable_clients == 0) {
2181                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
2182                         goto out;
2183
2184                 goto fclose;
2185         }
2186
2187         /* sampled unlocked, but really... */
2188         if (obd->obd_recovering == 0) {
2189                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
2190                         goto out;
2191                 if (lprocfs_obd_snprintf(&page, size, &len,
2192                                          "recovery_start: %lu\n",
2193                                          obd->obd_recovery_start) <= 0)
2194                         goto out;
2195                 if (lprocfs_obd_snprintf(&page, size, &len,
2196                                          "recovery_duration: %lu\n",
2197                                          obd->obd_recovery_end -
2198                                          obd->obd_recovery_start) <= 0)
2199                         goto out;
2200                 /* Number of clients that have completed recovery */
2201                 if (lprocfs_obd_snprintf(&page, size, &len,
2202                                          "completed_clients: %d/%d\n",
2203                                          obd->obd_max_recoverable_clients -
2204                                          obd->obd_stale_clients,
2205                                          obd->obd_max_recoverable_clients) <= 0)
2206                         goto out;
2207                 if (lprocfs_obd_snprintf(&page, size, &len,
2208                                          "replayed_requests: %d\n",
2209                                          obd->obd_replayed_requests) <= 0)
2210                         goto out;
2211                 if (lprocfs_obd_snprintf(&page, size, &len,
2212                                          "last_transno: "LPD64"\n",
2213                                          obd->obd_next_recovery_transno - 1)<=0)
2214                         goto out;
2215                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
2216                                          obd->obd_version_recov ? "ON" : "OFF")<=0)
2217                         goto out;
2218                 goto fclose;
2219         }
2220
2221         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
2222                 goto out;
2223         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
2224                                  obd->obd_recovery_start) <= 0)
2225                 goto out;
2226         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
2227                            cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
2228                            obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
2229                 goto out;
2230         if (lprocfs_obd_snprintf(&page, size, &len,"connected_clients: %d/%d\n",
2231                                  obd->obd_connected_clients,
2232                                  obd->obd_max_recoverable_clients) <= 0)
2233                 goto out;
2234         /* Number of clients that have completed recovery */
2235         if (lprocfs_obd_snprintf(&page, size, &len,"req_replay_clients: %d\n",
2236                                  cfs_atomic_read(&obd->obd_req_replay_clients))
2237                 <= 0)
2238                 goto out;
2239         if (lprocfs_obd_snprintf(&page, size, &len,"lock_repay_clients: %d\n",
2240                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2241                 <=0)
2242                 goto out;
2243         if (lprocfs_obd_snprintf(&page, size, &len,"completed_clients: %d\n",
2244                                  obd->obd_connected_clients -
2245                                  cfs_atomic_read(&obd->obd_lock_replay_clients))
2246                 <=0)
2247                 goto out;
2248         if (lprocfs_obd_snprintf(&page, size, &len,"evicted_clients: %d\n",
2249                                  obd->obd_stale_clients) <= 0)
2250                 goto out;
2251         if (lprocfs_obd_snprintf(&page, size, &len,"replayed_requests: %d\n",
2252                                  obd->obd_replayed_requests) <= 0)
2253                 goto out;
2254         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
2255                                  obd->obd_requests_queued_for_recovery) <= 0)
2256                 goto out;
2257
2258         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
2259                                  obd->obd_next_recovery_transno) <= 0)
2260                 goto out;
2261
2262 fclose:
2263         *eof = 1;
2264 out:
2265         return min(count, len - (int)off);
2266 }
2267 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
2268
2269 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
2270                                       int count, int *eof, void *data)
2271 {
2272         struct obd_device *obd = (struct obd_device *)data;
2273         LASSERT(obd != NULL);
2274
2275         return snprintf(page, count, "%d\n",
2276                         obd->obd_recovery_timeout);
2277 }
2278 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
2279
2280 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
2281                                       unsigned long count, void *data)
2282 {
2283         struct obd_device *obd = (struct obd_device *)data;
2284         int val, rc;
2285         LASSERT(obd != NULL);
2286
2287         rc = lprocfs_write_helper(buffer, count, &val);
2288         if (rc)
2289                 return rc;
2290
2291         obd->obd_recovery_timeout = val;
2292         return count;
2293 }
2294 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
2295
2296 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
2297                                       int count, int *eof, void *data)
2298 {
2299         struct obd_device *obd = data;
2300         LASSERT(obd != NULL);
2301
2302         return snprintf(page, count, "%lu\n", obd->obd_recovery_time_hard);
2303 }
2304 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
2305
2306 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
2307                                       unsigned long count, void *data)
2308 {
2309         struct obd_device *obd = data;
2310         int val, rc;
2311         LASSERT(obd != NULL);
2312
2313         rc = lprocfs_write_helper(buffer, count, &val);
2314         if (rc)
2315                 return rc;
2316
2317         obd->obd_recovery_time_hard = val;
2318         return count;
2319 }
2320 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
2321
2322 int lprocfs_obd_rd_mntdev(char *page, char **start, off_t off,
2323                           int count, int *eof, void *data)
2324 {
2325         struct obd_device *obd = (struct obd_device *)data;
2326
2327         LASSERT(obd != NULL);
2328         LASSERT(obd->u.obt.obt_vfsmnt->mnt_devname);
2329         *eof = 1;
2330         return snprintf(page, count, "%s\n",
2331                         obd->u.obt.obt_vfsmnt->mnt_devname);
2332 }
2333 EXPORT_SYMBOL(lprocfs_obd_rd_mntdev);
2334
2335 EXPORT_SYMBOL(lprocfs_register);
2336 EXPORT_SYMBOL(lprocfs_srch);
2337 EXPORT_SYMBOL(lprocfs_remove);
2338 EXPORT_SYMBOL(lprocfs_remove_proc_entry);
2339 EXPORT_SYMBOL(lprocfs_add_vars);
2340 EXPORT_SYMBOL(lprocfs_obd_setup);
2341 EXPORT_SYMBOL(lprocfs_obd_cleanup);
2342 EXPORT_SYMBOL(lprocfs_add_simple);
2343 EXPORT_SYMBOL(lprocfs_add_symlink);
2344 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
2345 EXPORT_SYMBOL(lprocfs_alloc_stats);
2346 EXPORT_SYMBOL(lprocfs_free_stats);
2347 EXPORT_SYMBOL(lprocfs_clear_stats);
2348 EXPORT_SYMBOL(lprocfs_register_stats);
2349 EXPORT_SYMBOL(lprocfs_init_ops_stats);
2350 EXPORT_SYMBOL(lprocfs_init_ldlm_stats);
2351 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
2352 EXPORT_SYMBOL(lprocfs_alloc_md_stats);
2353 EXPORT_SYMBOL(lprocfs_free_obd_stats);
2354 EXPORT_SYMBOL(lprocfs_free_md_stats);
2355 EXPORT_SYMBOL(lprocfs_exp_setup);
2356 EXPORT_SYMBOL(lprocfs_exp_cleanup);
2357
2358 EXPORT_SYMBOL(lprocfs_rd_u64);
2359 EXPORT_SYMBOL(lprocfs_rd_atomic);
2360 EXPORT_SYMBOL(lprocfs_wr_atomic);
2361 EXPORT_SYMBOL(lprocfs_rd_uint);
2362 EXPORT_SYMBOL(lprocfs_wr_uint);
2363 EXPORT_SYMBOL(lprocfs_rd_uuid);
2364 EXPORT_SYMBOL(lprocfs_rd_name);
2365 EXPORT_SYMBOL(lprocfs_rd_fstype);
2366 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
2367 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
2368 EXPORT_SYMBOL(lprocfs_rd_num_exports);
2369 EXPORT_SYMBOL(lprocfs_rd_numrefs);
2370 EXPORT_SYMBOL(lprocfs_at_hist_helper);
2371 EXPORT_SYMBOL(lprocfs_rd_import);
2372 EXPORT_SYMBOL(lprocfs_rd_state);
2373 EXPORT_SYMBOL(lprocfs_rd_timeouts);
2374 EXPORT_SYMBOL(lprocfs_rd_blksize);
2375 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
2376 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
2377 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
2378 EXPORT_SYMBOL(lprocfs_rd_filestotal);
2379 EXPORT_SYMBOL(lprocfs_rd_filesfree);
2380
2381 EXPORT_SYMBOL(lprocfs_write_helper);
2382 EXPORT_SYMBOL(lprocfs_write_frac_helper);
2383 EXPORT_SYMBOL(lprocfs_read_frac_helper);
2384 EXPORT_SYMBOL(lprocfs_write_u64_helper);
2385 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
2386 EXPORT_SYMBOL(lprocfs_stats_collect);
2387 #endif /* LPROCFS*/