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