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