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