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