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