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