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