Whamcloud - gitweb
88488e9952d3ef4764cc17f20f1de23b231ec439
[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  *  Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Hariharan Thantry <thantry@users.sourceforge.net>
6  *
7  *   This file is part of the Lustre file system, http://www.lustre.org
8  *   Lustre is a trademark of Cluster File Systems, Inc.
9  *
10  *   You may have signed or agreed to another license before downloading
11  *   this software.  If so, you are bound by the terms and conditions
12  *   of that agreement, and the following does not apply to you.  See the
13  *   LICENSE file included with this distribution for more information.
14  *
15  *   If you did not agree to a different license, then this copy of Lustre
16  *   is open source software; you can redistribute it and/or modify it
17  *   under the terms of version 2 of the GNU General Public License as
18  *   published by the Free Software Foundation.
19  *
20  *   In either case, Lustre is distributed in the hope that it will be
21  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
22  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *   license text for more details.
24  */
25
26 #ifndef EXPORT_SYMTAB
27 # define EXPORT_SYMTAB
28 #endif
29 #define DEBUG_SUBSYSTEM S_CLASS
30
31 #ifndef __KERNEL__
32 # include <liblustre.h>
33 #endif
34
35 #include <obd_class.h>
36 #include <lprocfs_status.h>
37 #include <lustre_fsfilt.h>
38
39 #if defined(LPROCFS)
40
41 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
42                                     const char *name)
43 {
44         struct proc_dir_entry *temp;
45
46         if (head == NULL)
47                 return NULL;
48
49         temp = head->subdir;
50         while (temp != NULL) {
51                 if (strcmp(temp->name, name) == 0)
52                         return temp;
53
54                 temp = temp->next;
55         }
56         return NULL;
57 }
58
59 /* lprocfs API calls */
60
61 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
62                      void *data)
63 {
64         if (root == NULL || list == NULL)
65                 return -EINVAL;
66
67         while (list->name != NULL) {
68                 struct proc_dir_entry *cur_root, *proc;
69                 char *pathcopy, *cur, *next, pathbuf[64];
70                 int pathsize = strlen(list->name) + 1;
71
72                 proc = NULL;
73                 cur_root = root;
74
75                 /* need copy of path for strsep */
76                 if (strlen(list->name) > sizeof(pathbuf) - 1) {
77                         OBD_ALLOC(pathcopy, pathsize);
78                         if (pathcopy == NULL)
79                                 return -ENOMEM;
80                 } else {
81                         pathcopy = pathbuf;
82                 }
83
84                 next = pathcopy;
85                 strcpy(pathcopy, list->name);
86
87                 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
88                         if (*cur =='\0') /* skip double/trailing "/" */
89                                 continue;
90
91                         proc = lprocfs_srch(cur_root, cur);
92                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
93                                cur_root->name, cur, next,
94                                (proc ? "exists" : "new"));
95                         if (next != NULL) {
96                                 cur_root = (proc ? proc :
97                                             proc_mkdir(cur, cur_root));
98                         } else if (proc == NULL) {
99                                 mode_t mode = 0;
100                                 if (list->read_fptr)
101                                         mode = 0444;
102                                 if (list->write_fptr)
103                                         mode |= 0200;
104                                 proc = create_proc_entry(cur, mode, cur_root);
105                         }
106                 }
107
108                 if (pathcopy != pathbuf)
109                         OBD_FREE(pathcopy, pathsize);
110
111                 if (cur_root == NULL || proc == NULL) {
112                         CERROR("LprocFS: No memory to create /proc entry %s",
113                                list->name);
114                         return -ENOMEM;
115                 }
116
117                 proc->read_proc = list->read_fptr;
118                 proc->write_proc = list->write_fptr;
119                 proc->data = (list->data ? list->data : data);
120                 list++;
121         }
122         return 0;
123 }
124
125 void lprocfs_remove(struct proc_dir_entry *root)
126 {
127         struct proc_dir_entry *temp = root;
128         struct proc_dir_entry *rm_entry;
129         struct proc_dir_entry *parent;
130
131         LASSERT(root != NULL);
132         parent = root->parent;
133         LASSERT(parent != NULL);
134  
135         while (1) {
136                 while (temp->subdir != NULL)
137                         temp = temp->subdir;
138
139                 rm_entry = temp;
140                 temp = temp->parent;
141
142                 /* Memory corruption once caused this to fail, and
143                    without this LASSERT we would loop here forever. */
144                 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
145                          "0x%p  %s/%s len %d\n", rm_entry, temp->name,
146                          rm_entry->name, (int)strlen(rm_entry->name));
147
148                 remove_proc_entry(rm_entry->name, rm_entry->parent);
149                 if (temp == parent)
150                         break;
151         }
152 }
153
154 struct proc_dir_entry *lprocfs_register(const char *name,
155                                         struct proc_dir_entry *parent,
156                                         struct lprocfs_vars *list, void *data)
157 {
158         struct proc_dir_entry *newchild;
159
160         newchild = lprocfs_srch(parent, name);
161         if (newchild != NULL) {
162                 CERROR(" Lproc: Attempting to register %s more than once \n",
163                        name);
164                 return ERR_PTR(-EALREADY);
165         }
166
167         newchild = proc_mkdir(name, parent);
168         if (newchild != NULL && list != NULL) {
169                 int rc = lprocfs_add_vars(newchild, list, data);
170                 if (rc) {
171                         lprocfs_remove(newchild);
172                         return ERR_PTR(rc);
173                 }
174         }
175         return newchild;
176 }
177
178 /* Generic callbacks */
179
180 int lprocfs_rd_u64(char *page, char **start, off_t off,
181                    int count, int *eof, void *data)
182 {
183         LASSERT(data != NULL);
184         *eof = 1;
185         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
186 }
187
188 int lprocfs_rd_atomic(char *page, char **start, off_t off,
189                    int count, int *eof, void *data)
190 {
191         atomic_t *atom = (atomic_t *)data;
192         LASSERT(atom != NULL);
193         *eof = 1;
194         return snprintf(page, count, "%d\n", atomic_read(atom));
195 }
196
197 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
198                     int *eof, void *data)
199 {
200         struct obd_device *obd = (struct obd_device*)data;
201
202         LASSERT(obd != NULL);
203         *eof = 1;
204         return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
205 }
206
207 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
208                     int *eof, void* data)
209 {
210         struct obd_device *dev = (struct obd_device *)data;
211
212         LASSERT(dev != NULL);
213         LASSERT(dev->obd_name != NULL);
214         *eof = 1;
215         return snprintf(page, count, "%s\n", dev->obd_name);
216 }
217
218 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
219                       void *data)
220 {
221         struct obd_device *obd = (struct obd_device *)data;
222
223         LASSERT(obd != NULL);
224         LASSERT(obd->obd_fsops != NULL);
225         LASSERT(obd->obd_fsops->fs_type != NULL);
226         return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
227 }
228
229 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
230                        int *eof, void *data)
231 {
232         struct obd_statfs osfs;
233         int rc = obd_statfs(data, &osfs, jiffies - HZ);
234         if (!rc) {
235                 *eof = 1;
236                 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
237         }
238         return rc;
239 }
240
241 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
242                            int *eof, void *data)
243 {
244         struct obd_statfs osfs;
245         int rc = obd_statfs(data, &osfs, jiffies - HZ);
246         if (!rc) {
247                 __u32 blk_size = osfs.os_bsize >> 10;
248                 __u64 result = osfs.os_blocks;
249
250                 while (blk_size >>= 1)
251                         result <<= 1;
252
253                 *eof = 1;
254                 rc = snprintf(page, count, LPU64"\n", result);
255         }
256         return rc;
257 }
258
259 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
260                           int *eof, void *data)
261 {
262         struct obd_statfs osfs;
263         int rc = obd_statfs(data, &osfs, jiffies - HZ);
264         if (!rc) {
265                 __u32 blk_size = osfs.os_bsize >> 10;
266                 __u64 result = osfs.os_bfree;
267
268                 while (blk_size >>= 1)
269                         result <<= 1;
270
271                 *eof = 1;
272                 rc = snprintf(page, count, LPU64"\n", result);
273         }
274         return rc;
275 }
276
277 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
278                            int *eof, void *data)
279 {
280         struct obd_statfs osfs;
281         int rc = obd_statfs(data, &osfs, jiffies - HZ);
282         if (!rc) {
283                 __u32 blk_size = osfs.os_bsize >> 10;
284                 __u64 result = osfs.os_bavail;
285
286                 while (blk_size >>= 1)
287                         result <<= 1;
288
289                 *eof = 1;
290                 rc = snprintf(page, count, LPU64"\n", result);
291         }
292         return rc;
293 }
294
295 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
296                           int *eof, void *data)
297 {
298         struct obd_statfs osfs;
299         int rc = obd_statfs(data, &osfs, jiffies - HZ);
300         if (!rc) {
301                 *eof = 1;
302                 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
303         }
304
305         return rc;
306 }
307
308 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
309                          int *eof, void *data)
310 {
311         struct obd_statfs osfs;
312         int rc = obd_statfs(data, &osfs, jiffies - HZ);
313         if (!rc) {
314                 *eof = 1;
315                 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
316         }
317         return rc;
318 }
319
320 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
321                            int *eof, void *data)
322 {
323         struct obd_device *obd = (struct obd_device *)data;
324         struct obd_import *imp;
325         char *imp_state_name = NULL;
326
327         LASSERT(obd != NULL);
328         imp = obd->u.cli.cl_import;
329         imp_state_name = ptlrpc_import_state_name(imp->imp_state);
330         *eof = 1;
331         return snprintf(page, count, "%s\t%s%s\n",
332                         obd2cli_tgt(obd), imp_state_name,
333                         imp->imp_deactive ? "\tDEACTIVATED" : "");
334 }
335
336 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
337                          int *eof,  void *data)
338 {
339         struct obd_device *obd = (struct obd_device*)data;
340         struct ptlrpc_connection *conn;
341
342         LASSERT(obd != NULL);
343         conn = obd->u.cli.cl_import->imp_connection;
344         LASSERT(conn != NULL);
345         *eof = 1;
346         return snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
347 }
348
349 static const char *obd_connect_names[] = {
350         "read_only",
351         "lov_index",
352         "unused",
353         "write_grant",
354         "server_lock",
355         "version",
356         "request_portal",
357         "acl",
358         "xattr",
359         "create_on_write",
360         "truncate_lock",
361         "initial_transno",
362         "inode_bit_locks",
363         "join_file",
364         "",
365         "no_oh_for_devices",
366         NULL
367 };
368
369 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
370                              int count, int *eof, void *data)
371 {
372         struct obd_device *obd = data;
373         __u64 mask = 1, flags;
374         int i, ret;
375
376         if (obd == NULL)
377                 return 0;
378
379         flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
380         ret = snprintf(page, count, "flags="LPX64"\n", flags);
381         for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
382                 if (flags & mask)
383                         ret += snprintf(page + ret, count - ret, "%s\n",
384                                         obd_connect_names[i]);
385         }
386         if (flags & ~(mask - 1))
387                 ret += snprintf(page + ret, count - ret,
388                                 "unknown flags "LPX64"\n", flags & ~(mask - 1));
389
390         return ret;
391 }
392 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
393
394 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
395                            int *eof,  void *data)
396 {
397         struct obd_device *obd = (struct obd_device*)data;
398
399         LASSERT(obd != NULL);
400         *eof = 1;
401         return snprintf(page, count, "%u\n", obd->obd_num_exports);
402 }
403
404 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
405                        int *eof, void *data)
406 {
407         struct obd_type *class = (struct obd_type*) data;
408
409         LASSERT(class != NULL);
410         *eof = 1;
411         return snprintf(page, count, "%d\n", class->typ_refcnt);
412 }
413
414 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
415 {
416         int rc = 0;
417
418         LASSERT(obd != NULL);
419         LASSERT(obd->obd_type != NULL);
420         LASSERT(obd->obd_type->typ_procroot != NULL);
421
422         obd->obd_proc_entry = lprocfs_register(obd->obd_name,
423                                                obd->obd_type->typ_procroot,
424                                                list, obd);
425         if (IS_ERR(obd->obd_proc_entry)) {
426                 rc = PTR_ERR(obd->obd_proc_entry);
427                 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
428                 obd->obd_proc_entry = NULL;
429         }
430         return rc;
431 }
432
433 int lprocfs_obd_cleanup(struct obd_device *obd)
434 {
435         if (obd && obd->obd_proc_entry) {
436                 lprocfs_remove(obd->obd_proc_entry);
437                 obd->obd_proc_entry = NULL;
438         }
439         return 0;
440 }
441
442 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
443 {
444         struct lprocfs_stats *stats;
445         struct lprocfs_percpu *percpu;
446         unsigned int percpusize;
447         unsigned int i;
448
449         if (num == 0)
450                 return NULL;
451
452         OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
453         if (stats == NULL)
454                 return NULL;
455
456         percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
457         stats->ls_percpu_size = num_online_cpus() * percpusize;
458         OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
459         if (stats->ls_percpu[0] == NULL) {
460                 OBD_FREE(stats, offsetof(typeof(*stats),
461                                          ls_percpu[num_online_cpus()]));
462                 return NULL;
463         }
464
465         stats->ls_num = num;
466         for (i = 1; i < num_online_cpus(); i++)
467                 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
468                         percpusize;
469
470         return stats;
471 }
472
473 void lprocfs_free_stats(struct lprocfs_stats *stats)
474 {
475         if (stats->ls_num == 0)
476                 return;
477
478         OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
479         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
480 }
481
482 /* Reset counter under lock */
483 int lprocfs_counter_write(struct file *file, const char *buffer,
484                           unsigned long count, void *data)
485 {
486         /* not supported */
487         return 0;
488 }
489
490 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
491 {
492         struct lprocfs_stats *stats = p->private;
493         /* return 1st cpu location */
494         return (*pos >= stats->ls_num) ? NULL :
495                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
496 }
497
498 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
499 {
500 }
501
502 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
503 {
504         struct lprocfs_stats *stats = p->private;
505         ++*pos;
506         return (*pos >= stats->ls_num) ? NULL :
507                 &(stats->ls_percpu[0]->lp_cntr[*pos]);
508 }
509
510 /* seq file export of one lprocfs counter */
511 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
512 {
513        struct lprocfs_stats *stats = p->private;
514        struct lprocfs_counter  *cntr = v;
515        struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
516        int i, idx, rc;
517
518        if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
519                struct timeval now;
520                do_gettimeofday(&now);
521                rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
522                                "snapshot_time", now.tv_sec, now.tv_usec);
523                if (rc < 0)
524                        return rc;
525        }
526        idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
527
528        for (i = 0; i < num_online_cpus(); i++) {
529                struct lprocfs_counter *percpu_cntr =
530                        &(stats->ls_percpu[i])->lp_cntr[idx];
531                int centry;
532
533                do {
534                        centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
535                        t.lc_count = percpu_cntr->lc_count;
536                        t.lc_sum = percpu_cntr->lc_sum;
537                        t.lc_min = percpu_cntr->lc_min;
538                        t.lc_max = percpu_cntr->lc_max;
539                        t.lc_sumsquare = percpu_cntr->lc_sumsquare;
540                } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
541                         centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
542                ret.lc_count += t.lc_count;
543                ret.lc_sum += t.lc_sum;
544                if (t.lc_min < ret.lc_min)
545                        ret.lc_min = t.lc_min;
546                if (t.lc_max > ret.lc_max)
547                        ret.lc_max = t.lc_max;
548                ret.lc_sumsquare += t.lc_sumsquare;
549        }
550
551        rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
552                        ret.lc_count, cntr->lc_units);
553        if (rc < 0)
554                goto out;
555
556        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
557                rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
558                                ret.lc_min, ret.lc_max, ret.lc_sum);
559                if (rc < 0)
560                        goto out;
561                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
562                        rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
563                if (rc < 0)
564                        goto out;
565        }
566        rc = seq_printf(p, "\n");
567  out:
568        return (rc < 0) ? rc : 0;
569 }
570
571 struct seq_operations lprocfs_stats_seq_sops = {
572         start: lprocfs_stats_seq_start,
573         stop:  lprocfs_stats_seq_stop,
574         next:  lprocfs_stats_seq_next,
575         show:  lprocfs_stats_seq_show,
576 };
577
578 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
579 {
580         struct proc_dir_entry *dp = PDE(inode);
581         struct seq_file *seq;
582         int rc;
583
584         rc = seq_open(file, &lprocfs_stats_seq_sops);
585         if (rc)
586                 return rc;
587         seq = file->private_data;
588         seq->private = dp->data;
589         return 0;
590 }
591
592 struct file_operations lprocfs_stats_seq_fops = {
593         .owner   = THIS_MODULE,
594         .open    = lprocfs_stats_seq_open,
595         .read    = seq_read,
596         .llseek  = seq_lseek,
597         .release = seq_release,
598 };
599
600 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
601                            struct lprocfs_stats *stats)
602 {
603         struct proc_dir_entry *entry;
604         LASSERT(root != NULL);
605
606         entry = create_proc_entry(name, 0444, root);
607         if (entry == NULL)
608                 return -ENOMEM;
609         entry->proc_fops = &lprocfs_stats_seq_fops;
610         entry->data = (void *)stats;
611         entry->write_proc = lprocfs_counter_write;
612         return 0;
613 }
614
615 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
616                           unsigned conf, const char *name, const char *units)
617 {
618         struct lprocfs_counter *c;
619         int i;
620
621         LASSERT(stats != NULL);
622         for (i = 0; i < num_online_cpus(); i++) {
623                 c = &(stats->ls_percpu[i]->lp_cntr[index]);
624                 c->lc_config = conf;
625                 c->lc_min = ~(__u64)0;
626                 c->lc_name = name;
627                 c->lc_units = units;
628         }
629 }
630 EXPORT_SYMBOL(lprocfs_counter_init);
631
632 #define LPROCFS_OBD_OP_INIT(base, stats, op)                               \
633 do {                                                                       \
634         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);              \
635         LASSERT(coffset < stats->ls_num);                                  \
636         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");              \
637 } while (0)
638
639 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
640 {
641         struct lprocfs_stats *stats;
642         unsigned int num_stats;
643         int rc, i;
644
645         LASSERT(obd->obd_stats == NULL);
646         LASSERT(obd->obd_proc_entry != NULL);
647         LASSERT(obd->obd_cntr_base == 0);
648
649         num_stats = 1 + OBD_COUNTER_OFFSET(quotactl) +
650                 num_private_stats;
651         stats = lprocfs_alloc_stats(num_stats);
652         if (stats == NULL)
653                 return -ENOMEM;
654
655         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
656         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
657         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
658         LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
659         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
671         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
672         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
673         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
674         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
675         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
676         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
677         LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
678         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
679         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
680         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
681         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
682         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
683         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
684         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
685         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
686         LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
687         LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
688         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
689         LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
690         LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
691         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
692         LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
693         LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
694         LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
695         LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
696         LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
697         LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
698         LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
699         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
700         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
701         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
702         LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
703         LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
704         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
705         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
706         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
707         LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
708         LPROCFS_OBD_OP_INIT(num_private_stats, stats, san_preprw);
709         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
710         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
711         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
712         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
713         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
714         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
715         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
716         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
717         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
718         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
719         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
720
721         for (i = num_private_stats; i < num_stats; i++) {
722                 /* If this LBUGs, it is likely that an obd
723                  * operation was added to struct obd_ops in
724                  * <obd.h>, and that the corresponding line item
725                  * LPROCFS_OBD_OP_INIT(.., .., opname)
726                  * is missing from the list above. */
727                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
728                         CERROR("Missing obd_stat initializer obd_op "
729                                "operation at offset %d. Aborting.\n",
730                                i - num_private_stats);
731                         LBUG();
732                 }
733         }
734         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
735         if (rc < 0) {
736                 lprocfs_free_stats(stats);
737         } else {
738                 obd->obd_stats  = stats;
739                 obd->obd_cntr_base = num_private_stats;
740         }
741         return rc;
742 }
743
744 void lprocfs_free_obd_stats(struct obd_device *obd)
745 {
746         struct lprocfs_stats *stats = obd->obd_stats;
747
748         if (stats != NULL) {
749                 obd->obd_stats = NULL;
750                 lprocfs_free_stats(stats);
751         }
752 }
753
754 #define LPROCFS_MD_OP_INIT(base, stats, op)                             \
755 do {                                                                    \
756         unsigned int coffset = base + MD_COUNTER_OFFSET(op);            \
757         LASSERT(coffset < stats->ls_num);                               \
758         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");           \
759 } while (0)
760
761 int lprocfs_alloc_md_stats(struct obd_device *obd,
762                            unsigned num_private_stats)
763 {
764         struct lprocfs_stats *stats;
765         unsigned int num_stats;
766         int rc, i;
767
768         LASSERT(obd->md_stats == NULL);
769         LASSERT(obd->obd_proc_entry != NULL);
770         LASSERT(obd->md_cntr_base == 0);
771
772         num_stats = 1 + MD_COUNTER_OFFSET(cancel_unused) +
773                 num_private_stats;
774         stats = lprocfs_alloc_stats(num_stats);
775         if (stats == NULL)
776                 return -ENOMEM;
777
778         LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
779         LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
780         LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
781         LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
782         LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
783         LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
784         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
785         LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
786         LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
787         LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
788         LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
789         LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
790         LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
791         LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
792         LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
793         LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
794         LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
795         LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
796         LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
797         LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
798         LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
799         LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
800         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
801         LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
802         LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
803
804         for (i = num_private_stats; i < num_stats; i++) {
805                 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
806                         CERROR("Missing md_stat initializer md_op "
807                                "operation at offset %d. Aborting.\n",
808                                i - num_private_stats);
809                         LBUG();
810                 }
811         }
812         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
813         if (rc < 0) {
814                 lprocfs_free_stats(stats);
815         } else {
816                 obd->md_stats  = stats;
817                 obd->md_cntr_base = num_private_stats;
818         }
819         return rc;
820 }
821
822 void lprocfs_free_md_stats(struct obd_device *obd)
823 {
824         struct lprocfs_stats *stats = obd->md_stats;
825
826         if (stats != NULL) {
827                 obd->md_stats = NULL;
828                 lprocfs_free_stats(stats);
829         }
830 }
831
832 int lprocfs_write_helper(const char *buffer, unsigned long count,
833                          int *val)
834 {
835         char kernbuf[20], *end;
836
837         if (count > (sizeof(kernbuf) - 1))
838                 return -EINVAL;
839
840         if (copy_from_user(kernbuf, buffer, count))
841                 return -EFAULT;
842
843         kernbuf[count] = '\0';
844
845         *val = simple_strtol(kernbuf, &end, 0);
846         if (kernbuf == end)
847                 return -EINVAL;
848
849         return 0;
850 }
851
852 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
853 {
854         char kernbuf[22], *end;
855
856         if (count > (sizeof(kernbuf) - 1))
857                 return -EINVAL;
858
859         if (copy_from_user(kernbuf, buffer, count))
860                 return -EFAULT;
861
862         kernbuf[count] = '\0';
863
864         if (kernbuf[0] == '-')
865                 *val = -simple_strtoull(kernbuf + 1, &end, 0);
866         else
867                 *val = simple_strtoull(kernbuf, &end, 0);
868         if (kernbuf == end)
869                 return -EINVAL;
870
871         return 0;
872 }
873
874 int lprocfs_obd_seq_create(struct obd_device *dev, char *name, mode_t mode,
875                            struct file_operations *seq_fops, void *data)
876 {
877         struct proc_dir_entry *entry;
878         ENTRY;
879
880         entry = create_proc_entry(name, mode, dev->obd_proc_entry);
881         if (entry == NULL)
882                 RETURN(-ENOMEM);
883         entry->proc_fops = seq_fops;
884         entry->data = data;
885
886         RETURN(0);
887 }
888 EXPORT_SYMBOL(lprocfs_obd_seq_create);
889
890 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
891 {
892         unsigned long flags;
893
894         if (value >= OBD_HIST_MAX)
895                 value = OBD_HIST_MAX - 1;
896
897         spin_lock_irqsave(&oh->oh_lock, flags);
898         oh->oh_buckets[value]++;
899         spin_unlock_irqrestore(&oh->oh_lock, flags);
900 }
901 EXPORT_SYMBOL(lprocfs_oh_tally);
902
903 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
904 {
905         unsigned int val;
906
907         for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
908                 ;
909
910         lprocfs_oh_tally(oh, val);
911 }
912 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
913
914 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
915 {
916         unsigned long ret = 0;
917         int i;
918
919         for (i = 0; i < OBD_HIST_MAX; i++)
920                 ret +=  oh->oh_buckets[i];
921         return ret;
922 }
923 EXPORT_SYMBOL(lprocfs_oh_sum);
924
925 void lprocfs_oh_clear(struct obd_histogram *oh)
926 {
927         unsigned long flags;
928         spin_lock_irqsave(&oh->oh_lock, flags);
929         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
930         spin_unlock_irqrestore(&oh->oh_lock, flags);
931 }
932 EXPORT_SYMBOL(lprocfs_oh_clear);
933
934 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
935                                           int count, int *eof, void *data)
936 {
937         struct obd_device *obd = data;
938         int len = 0, n,
939                 connected = obd->obd_connected_clients,
940                 max_recoverable = obd->obd_max_recoverable_clients,
941                 recoverable = obd->obd_recoverable_clients,
942                 completed = max_recoverable - recoverable,
943                 queue_len = obd->obd_requests_queued_for_recovery,
944                 replayed = obd->obd_replayed_requests;
945         __u64 next_transno = obd->obd_next_recovery_transno;
946
947         LASSERT(obd != NULL);
948         *eof = 1;
949
950         n = snprintf(page, count, "status: ");
951         page += n; len += n; count -= n;
952         if (obd->obd_max_recoverable_clients == 0) {
953                 n = snprintf(page, count, "INACTIVE\n");
954                 return len + n;
955         }
956
957         /* sampled unlocked, but really... */
958         if (obd->obd_recovering == 0) {
959                 n = snprintf(page, count, "COMPLETE\n");
960                 page += n; len += n; count -= n;
961
962                 n = snprintf(page, count, "recovery_start: %lu\n",
963                              obd->obd_recovery_start);
964                 page += n; len += n; count -= n;
965                 n = snprintf(page, count, "recovery_end: %lu\n",
966                              obd->obd_recovery_end);
967                 page += n; len += n; count -= n;
968                 n = snprintf(page, count, "recovered_clients: %d\n",
969                              completed);
970                 page += n; len += n; count -= n;
971                 n = snprintf(page, count, "unrecovered_clients: %d\n",
972                              obd->obd_recoverable_clients);
973                 page += n; len += n; count -= n;
974                 n = snprintf(page, count, "last_transno: "LPD64"\n",
975                              next_transno - 1);
976                 page += n; len += n; count -= n;
977                 n = snprintf(page, count, "replayed_requests: %d\n", replayed);
978                 return len + n;
979         }
980
981         n = snprintf(page, count, "RECOVERING\n");
982         page += n; len += n; count -= n;
983         n = snprintf(page, count, "recovery_start: %lu\n",
984                      obd->obd_recovery_start);
985         page += n; len += n; count -= n;
986         n = snprintf(page, count, "time remaining: %lu\n",
987                      CURRENT_SECONDS >= obd->obd_recovery_end ? 0 : 
988                      obd->obd_recovery_end - CURRENT_SECONDS);
989         page += n; len += n; count -= n;
990         n = snprintf(page, count, "connected_clients: %d/%d\n",
991                      connected, max_recoverable);
992         page += n; len += n; count -= n;
993         n = snprintf(page, count, "completed_clients: %d/%d\n",
994                      completed, max_recoverable);
995         page += n; len += n; count -= n;
996         n = snprintf(page, count, "replayed_requests: %d/??\n", replayed);
997         page += n; len += n; count -= n;
998         n = snprintf(page, count, "queued_requests: %d\n", queue_len);
999         page += n; len += n; count -= n;
1000         n = snprintf(page, count, "next_transno: "LPD64"\n", next_transno);
1001         return len + n;
1002 }
1003 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1004
1005 EXPORT_SYMBOL(lprocfs_register);
1006 EXPORT_SYMBOL(lprocfs_srch);
1007 EXPORT_SYMBOL(lprocfs_remove);
1008 EXPORT_SYMBOL(lprocfs_add_vars);
1009 EXPORT_SYMBOL(lprocfs_obd_setup);
1010 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1011 EXPORT_SYMBOL(lprocfs_alloc_stats);
1012 EXPORT_SYMBOL(lprocfs_free_stats);
1013 EXPORT_SYMBOL(lprocfs_register_stats);
1014 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1015 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1016
1017 EXPORT_SYMBOL(lprocfs_rd_u64);
1018 EXPORT_SYMBOL(lprocfs_rd_atomic);
1019 EXPORT_SYMBOL(lprocfs_rd_uuid);
1020 EXPORT_SYMBOL(lprocfs_rd_name);
1021 EXPORT_SYMBOL(lprocfs_rd_fstype);
1022 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1023 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1024 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1025 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1026
1027 EXPORT_SYMBOL(lprocfs_rd_blksize);
1028 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1029 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1030 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1031 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1032 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1033
1034 EXPORT_SYMBOL(lprocfs_write_helper);
1035 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1036 #endif /* LPROCFS*/