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