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