1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
7 * This file is part of the Lustre file system, http://www.lustre.org
8 * Lustre is a trademark of Cluster File Systems, Inc.
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.
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.
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.
27 # define EXPORT_SYMTAB
29 #define DEBUG_SUBSYSTEM S_CLASS
32 # include <liblustre.h>
35 #include <obd_class.h>
36 #include <lprocfs_status.h>
37 #include <lustre_fsfilt.h>
41 /* for bug 10866, global variable */
42 DECLARE_RWSEM(_lprocfs_lock);
43 EXPORT_SYMBOL(_lprocfs_lock);
45 int lprocfs_seq_release(struct inode *inode, struct file *file)
48 return seq_release(inode, file);
50 EXPORT_SYMBOL(lprocfs_seq_release);
52 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
55 struct proc_dir_entry *temp;
61 while (temp != NULL) {
62 if (strcmp(temp->name, name) == 0)
70 /* lprocfs API calls */
72 /* Function that emulates snprintf but also has the side effect of advancing
73 the page pointer for the next write into the buffer, incrementing the total
74 length written to the buffer, and decrementing the size left in the
76 static int lprocfs_obd_snprintf(char **page, int end, int *len,
77 const char *format, ...)
85 va_start(list, format);
86 n = vsnprintf(*page, end - *len, format, list);
89 *page += n; *len += n;
93 int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
94 read_proc_t *read_proc, write_proc_t *write_proc,
97 struct proc_dir_entry *proc;
100 if (root == NULL || name == NULL)
106 proc = create_proc_entry(name, mode, root);
108 CERROR("LprocFS: No memory to create /proc entry %s", name);
111 proc->read_proc = read_proc;
112 proc->write_proc = write_proc;
117 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
118 size_t size, loff_t *ppos)
120 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
121 char *page, *start = NULL;
122 int rc = 0, eof = 1, count;
124 if (*ppos >= CFS_PAGE_SIZE)
127 page = (char *)__get_free_page(GFP_KERNEL);
132 OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);
133 if (!dp->deleted && dp->read_proc)
134 rc = dp->read_proc(page, &start, *ppos, CFS_PAGE_SIZE,
140 /* for lustre proc read, the read count must be less than PAGE_SIZE */
149 start = page + *ppos;
150 } else if (start < page) {
154 count = (rc < size) ? rc : size;
155 if (copy_to_user(buf, start, count)) {
162 free_page((unsigned long)page);
166 static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos)
168 struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);
172 if (!dp->deleted && dp->write_proc)
173 rc = dp->write_proc(f, buf, size, dp->data);
178 static struct file_operations lprocfs_generic_fops = {
179 .owner = THIS_MODULE,
180 .read = lprocfs_fops_read,
181 .write = lprocfs_fops_write,
184 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
187 if (root == NULL || list == NULL)
190 while (list->name != NULL) {
191 struct proc_dir_entry *cur_root, *proc;
192 char *pathcopy, *cur, *next, pathbuf[64];
193 int pathsize = strlen(list->name) + 1;
198 /* need copy of path for strsep */
199 if (strlen(list->name) > sizeof(pathbuf) - 1) {
200 OBD_ALLOC(pathcopy, pathsize);
201 if (pathcopy == NULL)
208 strcpy(pathcopy, list->name);
210 while (cur_root != NULL && (cur = strsep(&next, "/"))) {
211 if (*cur =='\0') /* skip double/trailing "/" */
214 proc = lprocfs_srch(cur_root, cur);
215 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
216 cur_root->name, cur, next,
217 (proc ? "exists" : "new"));
219 cur_root = (proc ? proc :
220 proc_mkdir(cur, cur_root));
221 } else if (proc == NULL) {
225 if (list->write_fptr)
227 proc = create_proc_entry(cur, mode, cur_root);
231 if (pathcopy != pathbuf)
232 OBD_FREE(pathcopy, pathsize);
234 if (cur_root == NULL || proc == NULL) {
235 CERROR("LprocFS: No memory to create /proc entry %s",
240 proc->proc_fops = &lprocfs_generic_fops;
241 proc->read_proc = list->read_fptr;
242 proc->write_proc = list->write_fptr;
243 proc->data = (list->data ? list->data : data);
249 void lprocfs_remove(struct proc_dir_entry **rooth)
251 struct proc_dir_entry *root = *rooth;
252 struct proc_dir_entry *temp = root;
253 struct proc_dir_entry *rm_entry;
254 struct proc_dir_entry *parent;
260 parent = root->parent;
261 LASSERT(parent != NULL);
264 while (temp->subdir != NULL)
270 /* Memory corruption once caused this to fail, and
271 without this LASSERT we would loop here forever. */
272 LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,
273 "0x%p %s/%s len %d\n", rm_entry, temp->name,
274 rm_entry->name, (int)strlen(rm_entry->name));
276 /* Now, the rm_entry->deleted flags is protected
277 * by _lprocfs_lock. */
278 down_write(&_lprocfs_lock);
279 rm_entry->data = NULL;
280 remove_proc_entry(rm_entry->name, rm_entry->parent);
281 up_write(&_lprocfs_lock);
287 struct proc_dir_entry *lprocfs_register(const char *name,
288 struct proc_dir_entry *parent,
289 struct lprocfs_vars *list, void *data)
291 struct proc_dir_entry *newchild;
293 newchild = lprocfs_srch(parent, name);
294 if (newchild != NULL) {
295 CERROR(" Lproc: Attempting to register %s more than once \n",
297 return ERR_PTR(-EALREADY);
300 newchild = proc_mkdir(name, parent);
301 if (newchild != NULL && list != NULL) {
302 int rc = lprocfs_add_vars(newchild, list, data);
304 lprocfs_remove(&newchild);
311 /* Generic callbacks */
313 int lprocfs_rd_u64(char *page, char **start, off_t off,
314 int count, int *eof, void *data)
316 LASSERT(data != NULL);
318 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
321 int lprocfs_rd_atomic(char *page, char **start, off_t off,
322 int count, int *eof, void *data)
324 atomic_t *atom = (atomic_t *)data;
325 LASSERT(atom != NULL);
327 return snprintf(page, count, "%d\n", atomic_read(atom));
330 int lprocfs_rd_uuid(char *page, char **start, off_t off, int count,
331 int *eof, void *data)
333 struct obd_device *obd = (struct obd_device*)data;
335 LASSERT(obd != NULL);
337 return snprintf(page, count, "%s\n", obd->obd_uuid.uuid);
340 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
341 int *eof, void* data)
343 struct obd_device *dev = (struct obd_device *)data;
345 LASSERT(dev != NULL);
346 LASSERT(dev->obd_name != NULL);
348 return snprintf(page, count, "%s\n", dev->obd_name);
351 int lprocfs_rd_fstype(char *page, char **start, off_t off, int count, int *eof,
354 struct obd_device *obd = (struct obd_device *)data;
356 LASSERT(obd != NULL);
357 LASSERT(obd->obd_fsops != NULL);
358 LASSERT(obd->obd_fsops->fs_type != NULL);
359 return snprintf(page, count, "%s\n", obd->obd_fsops->fs_type);
362 int lprocfs_rd_blksize(char *page, char **start, off_t off, int count,
363 int *eof, void *data)
365 struct obd_statfs osfs;
366 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
369 rc = snprintf(page, count, "%u\n", osfs.os_bsize);
374 int lprocfs_rd_kbytestotal(char *page, char **start, off_t off, int count,
375 int *eof, void *data)
377 struct obd_statfs osfs;
378 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
380 __u32 blk_size = osfs.os_bsize >> 10;
381 __u64 result = osfs.os_blocks;
383 while (blk_size >>= 1)
387 rc = snprintf(page, count, LPU64"\n", result);
392 int lprocfs_rd_kbytesfree(char *page, char **start, off_t off, int count,
393 int *eof, void *data)
395 struct obd_statfs osfs;
396 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
398 __u32 blk_size = osfs.os_bsize >> 10;
399 __u64 result = osfs.os_bfree;
401 while (blk_size >>= 1)
405 rc = snprintf(page, count, LPU64"\n", result);
410 int lprocfs_rd_kbytesavail(char *page, char **start, off_t off, int count,
411 int *eof, void *data)
413 struct obd_statfs osfs;
414 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
416 __u32 blk_size = osfs.os_bsize >> 10;
417 __u64 result = osfs.os_bavail;
419 while (blk_size >>= 1)
423 rc = snprintf(page, count, LPU64"\n", result);
428 int lprocfs_rd_filestotal(char *page, char **start, off_t off, int count,
429 int *eof, void *data)
431 struct obd_statfs osfs;
432 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
435 rc = snprintf(page, count, LPU64"\n", osfs.os_files);
441 int lprocfs_rd_filesfree(char *page, char **start, off_t off, int count,
442 int *eof, void *data)
444 struct obd_statfs osfs;
445 int rc = obd_statfs(data, &osfs, cfs_time_current_64() - HZ);
448 rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
453 int lprocfs_rd_server_uuid(char *page, char **start, off_t off, int count,
454 int *eof, void *data)
456 struct obd_device *obd = (struct obd_device *)data;
457 struct obd_import *imp;
458 char *imp_state_name = NULL;
461 LASSERT(obd != NULL);
462 LPROCFS_CLIMP_CHECK(obd);
463 imp = obd->u.cli.cl_import;
464 imp_state_name = ptlrpc_import_state_name(imp->imp_state);
466 rc = snprintf(page, count, "%s\t%s%s\n",
467 obd2cli_tgt(obd), imp_state_name,
468 imp->imp_deactive ? "\tDEACTIVATED" : "");
470 LPROCFS_CLIMP_EXIT(obd);
474 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
475 int *eof, void *data)
477 struct obd_device *obd = (struct obd_device*)data;
478 struct ptlrpc_connection *conn;
481 LASSERT(obd != NULL);
483 LPROCFS_CLIMP_CHECK(obd);
484 conn = obd->u.cli.cl_import->imp_connection;
485 LASSERT(conn != NULL);
487 if (obd->u.cli.cl_import) {
488 rc = snprintf(page, count, "%s\n",
489 conn->c_remote_uuid.uuid);
491 rc = snprintf(page, count, "%s\n", "<none>");
494 LPROCFS_CLIMP_EXIT(obd);
498 static const char *obd_connect_names[] = {
521 "mds_mds_connection",
526 int lprocfs_rd_connect_flags(char *page, char **start, off_t off,
527 int count, int *eof, void *data)
529 struct obd_device *obd = data;
530 __u64 mask = 1, flags;
533 LPROCFS_CLIMP_CHECK(obd);
534 flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags;
535 ret = snprintf(page, count, "flags="LPX64"\n", flags);
536 for (i = 0; obd_connect_names[i] != NULL; i++, mask <<= 1) {
538 ret += snprintf(page + ret, count - ret, "%s\n",
539 obd_connect_names[i]);
541 if (flags & ~(mask - 1))
542 ret += snprintf(page + ret, count - ret,
543 "unknown flags "LPX64"\n", flags & ~(mask - 1));
545 LPROCFS_CLIMP_EXIT(obd);
548 EXPORT_SYMBOL(lprocfs_rd_connect_flags);
550 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
551 int *eof, void *data)
553 struct obd_device *obd = (struct obd_device*)data;
555 LASSERT(obd != NULL);
557 return snprintf(page, count, "%u\n", obd->obd_num_exports);
560 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
561 int *eof, void *data)
563 struct obd_type *class = (struct obd_type*) data;
565 LASSERT(class != NULL);
567 return snprintf(page, count, "%d\n", class->typ_refcnt);
570 int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list)
574 LASSERT(obd != NULL);
575 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
576 LASSERT(obd->obd_type->typ_procroot != NULL);
578 obd->obd_proc_entry = lprocfs_register(obd->obd_name,
579 obd->obd_type->typ_procroot,
581 if (IS_ERR(obd->obd_proc_entry)) {
582 rc = PTR_ERR(obd->obd_proc_entry);
583 CERROR("error %d setting up lprocfs for %s\n",rc,obd->obd_name);
584 obd->obd_proc_entry = NULL;
589 int lprocfs_obd_cleanup(struct obd_device *obd)
593 if (obd->obd_proc_exports) {
594 /* Should be no exports left */
595 LASSERT(obd->obd_proc_exports->subdir == NULL);
596 lprocfs_remove(&obd->obd_proc_exports);
598 lprocfs_remove(&obd->obd_proc_entry);
602 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num)
604 struct lprocfs_stats *stats;
605 struct lprocfs_percpu *percpu;
606 unsigned int percpusize;
612 OBD_ALLOC(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
616 percpusize = L1_CACHE_ALIGN(offsetof(typeof(*percpu), lp_cntr[num]));
617 stats->ls_percpu_size = num_online_cpus() * percpusize;
618 OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
619 if (stats->ls_percpu[0] == NULL) {
620 OBD_FREE(stats, offsetof(typeof(*stats),
621 ls_percpu[num_online_cpus()]));
626 for (i = 1; i < num_online_cpus(); i++)
627 stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
633 void lprocfs_free_stats(struct lprocfs_stats **statsh)
635 struct lprocfs_stats *stats = *statsh;
637 if (stats == NULL || stats->ls_num == 0)
641 OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
642 OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_online_cpus()]));
645 void lprocfs_clear_stats(struct lprocfs_stats *stats)
647 struct lprocfs_counter *percpu_cntr;
650 for (i = 0; i < num_online_cpus(); i++) {
651 for (j = 0; j < stats->ls_num; j++) {
652 percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
653 atomic_inc(&percpu_cntr->lc_cntl.la_entry);
654 percpu_cntr->lc_count = 0;
655 percpu_cntr->lc_sum = 0;
656 percpu_cntr->lc_min = ~(__u64)0;
657 percpu_cntr->lc_max = 0;
658 percpu_cntr->lc_sumsquare = 0;
659 atomic_inc(&percpu_cntr->lc_cntl.la_exit);
664 static ssize_t lprocfs_stats_seq_write(struct file *file, const char *buf,
665 size_t len, loff_t *off)
667 struct seq_file *seq = file->private_data;
668 struct lprocfs_stats *stats = seq->private;
670 lprocfs_clear_stats(stats);
675 static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos)
677 struct lprocfs_stats *stats = p->private;
678 /* return 1st cpu location */
679 return (*pos >= stats->ls_num) ? NULL :
680 &(stats->ls_percpu[0]->lp_cntr[*pos]);
683 static void lprocfs_stats_seq_stop(struct seq_file *p, void *v)
687 static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
689 struct lprocfs_stats *stats = p->private;
691 return (*pos >= stats->ls_num) ? NULL :
692 &(stats->ls_percpu[0]->lp_cntr[*pos]);
695 /* seq file export of one lprocfs counter */
696 static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
698 struct lprocfs_stats *stats = p->private;
699 struct lprocfs_counter *cntr = v;
700 struct lprocfs_counter t, ret = { .lc_min = ~(__u64)0 };
703 if (cntr == &(stats->ls_percpu[0])->lp_cntr[0]) {
705 do_gettimeofday(&now);
706 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
707 "snapshot_time", now.tv_sec, now.tv_usec);
711 idx = cntr - &(stats->ls_percpu[0])->lp_cntr[0];
713 for (i = 0; i < num_online_cpus(); i++) {
714 struct lprocfs_counter *percpu_cntr =
715 &(stats->ls_percpu[i])->lp_cntr[idx];
719 centry = atomic_read(&percpu_cntr->lc_cntl.la_entry);
720 t.lc_count = percpu_cntr->lc_count;
721 t.lc_sum = percpu_cntr->lc_sum;
722 t.lc_min = percpu_cntr->lc_min;
723 t.lc_max = percpu_cntr->lc_max;
724 t.lc_sumsquare = percpu_cntr->lc_sumsquare;
725 } while (centry != atomic_read(&percpu_cntr->lc_cntl.la_entry) &&
726 centry != atomic_read(&percpu_cntr->lc_cntl.la_exit));
727 ret.lc_count += t.lc_count;
728 ret.lc_sum += t.lc_sum;
729 if (t.lc_min < ret.lc_min)
730 ret.lc_min = t.lc_min;
731 if (t.lc_max > ret.lc_max)
732 ret.lc_max = t.lc_max;
733 ret.lc_sumsquare += t.lc_sumsquare;
736 rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
737 ret.lc_count, cntr->lc_units);
741 if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
742 rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
743 ret.lc_min, ret.lc_max, ret.lc_sum);
746 if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
747 rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
751 rc = seq_printf(p, "\n");
753 return (rc < 0) ? rc : 0;
756 struct seq_operations lprocfs_stats_seq_sops = {
757 start: lprocfs_stats_seq_start,
758 stop: lprocfs_stats_seq_stop,
759 next: lprocfs_stats_seq_next,
760 show: lprocfs_stats_seq_show,
763 static int lprocfs_stats_seq_open(struct inode *inode, struct file *file)
765 struct proc_dir_entry *dp = PDE(inode);
766 struct seq_file *seq;
769 LPROCFS_ENTRY_AND_CHECK(dp);
770 rc = seq_open(file, &lprocfs_stats_seq_sops);
775 seq = file->private_data;
776 seq->private = dp->data;
780 struct file_operations lprocfs_stats_seq_fops = {
781 .owner = THIS_MODULE,
782 .open = lprocfs_stats_seq_open,
784 .write = lprocfs_stats_seq_write,
786 .release = lprocfs_seq_release,
789 int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
790 struct lprocfs_stats *stats)
792 struct proc_dir_entry *entry;
793 LASSERT(root != NULL);
795 entry = create_proc_entry(name, 0644, root);
798 entry->proc_fops = &lprocfs_stats_seq_fops;
799 entry->data = (void *)stats;
803 void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
804 unsigned conf, const char *name, const char *units)
806 struct lprocfs_counter *c;
809 LASSERT(stats != NULL);
810 for (i = 0; i < num_online_cpus(); i++) {
811 c = &(stats->ls_percpu[i]->lp_cntr[index]);
815 c->lc_min = ~(__u64)0;
821 EXPORT_SYMBOL(lprocfs_counter_init);
823 #define LPROCFS_OBD_OP_INIT(base, stats, op) \
825 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
826 LASSERT(coffset < stats->ls_num); \
827 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
830 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
832 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
833 LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
834 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
835 LPROCFS_OBD_OP_INIT(num_private_stats, stats, attach);
836 LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
837 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
838 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
839 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
840 LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
841 LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
842 LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
843 LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
844 LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
845 LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
846 LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
847 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
848 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
849 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
850 LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_delete);
851 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
852 LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
853 LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
854 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
855 LPROCFS_OBD_OP_INIT(num_private_stats, stats, checkmd);
856 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preallocate);
857 LPROCFS_OBD_OP_INIT(num_private_stats, stats, precreate);
858 LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
859 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
860 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
861 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
862 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
863 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
864 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
865 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
866 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
867 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
868 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
869 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
870 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
871 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
872 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
873 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
874 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
875 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
876 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
877 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
878 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
879 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
880 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
881 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
882 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
883 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
884 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
885 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
886 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
887 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
888 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
889 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
890 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
891 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
892 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
893 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
894 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
895 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
896 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
897 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
898 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
899 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
900 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
903 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
905 struct lprocfs_stats *stats;
906 unsigned int num_stats;
909 LASSERT(obd->obd_stats == NULL);
910 LASSERT(obd->obd_proc_entry != NULL);
911 LASSERT(obd->obd_cntr_base == 0);
913 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
914 num_private_stats - 1 /* o_owner */;
915 stats = lprocfs_alloc_stats(num_stats);
919 lprocfs_init_ops_stats(num_private_stats, stats);
921 for (i = num_private_stats; i < num_stats; i++) {
922 /* If this LBUGs, it is likely that an obd
923 * operation was added to struct obd_ops in
924 * <obd.h>, and that the corresponding line item
925 * LPROCFS_OBD_OP_INIT(.., .., opname)
926 * is missing from the list above. */
927 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
928 "Missing obd_stat initializer obd_op "
929 "operation at offset %d.\n", i - num_private_stats);
931 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
933 lprocfs_free_stats(&stats);
935 obd->obd_stats = stats;
936 obd->obd_cntr_base = num_private_stats;
941 void lprocfs_free_obd_stats(struct obd_device *obd)
944 lprocfs_free_stats(&obd->obd_stats);
947 #define LPROCFS_MD_OP_INIT(base, stats, op) \
949 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
950 LASSERT(coffset < stats->ls_num); \
951 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
954 int lprocfs_alloc_md_stats(struct obd_device *obd,
955 unsigned num_private_stats)
957 struct lprocfs_stats *stats;
958 unsigned int num_stats;
961 LASSERT(obd->md_stats == NULL);
962 LASSERT(obd->obd_proc_entry != NULL);
963 LASSERT(obd->md_cntr_base == 0);
965 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
967 stats = lprocfs_alloc_stats(num_stats);
971 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
972 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
973 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
974 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
975 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
976 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
977 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
978 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
979 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
980 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
981 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
982 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
983 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
984 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
985 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
986 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
987 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
988 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
989 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
990 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
991 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
992 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
993 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
994 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
995 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
996 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
997 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
998 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
1000 for (i = num_private_stats; i < num_stats; i++) {
1001 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1002 CERROR("Missing md_stat initializer md_op "
1003 "operation at offset %d. Aborting.\n",
1004 i - num_private_stats);
1008 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1010 lprocfs_free_stats(&stats);
1012 obd->md_stats = stats;
1013 obd->md_cntr_base = num_private_stats;
1018 void lprocfs_free_md_stats(struct obd_device *obd)
1020 struct lprocfs_stats *stats = obd->md_stats;
1022 if (stats != NULL) {
1023 obd->md_stats = NULL;
1024 lprocfs_free_stats(&stats);
1028 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1029 int *eof, void *data)
1031 struct obd_export *exp = (struct obd_export*)data;
1032 LASSERT(exp != NULL);
1034 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1037 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1038 int *eof, void *data)
1040 struct obd_export *exp = (struct obd_export*)data;
1041 LASSERT(exp != NULL);
1043 return snprintf(page, count, "%s\n",
1044 obd_uuid2str(&exp->exp_client_uuid));
1047 int lprocfs_exp_setup(struct obd_export *exp)
1049 char name[sizeof (exp->exp_client_uuid.uuid) + 3];
1052 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
1054 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1055 sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
1056 while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
1057 /* We might add a new export before deleting the old one during
1058 an eviction (recovery-small 19a). Suckage. We
1059 could block, or come up with a new name, or just give up. */
1061 GOTO(out, rc = -EEXIST);
1062 sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
1065 /* Create a proc entry for this export */
1066 exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
1067 if (!exp->exp_proc) {
1068 CERROR("Error making export directory for %s\n", name);
1069 GOTO(out, rc = -ENOMEM);
1072 /* Always add nid and uuid */
1073 rc = lprocfs_add_simple(exp->exp_proc, "nid",
1074 lprocfs_exp_rd_nid, NULL, exp);
1077 rc = lprocfs_add_simple(exp->exp_proc, "uuid",
1078 lprocfs_exp_rd_uuid, NULL, exp);
1081 /* Always add ldlm stats */
1082 exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC
1084 if (exp->exp_ldlm_stats == NULL) {
1085 lprocfs_remove(&exp->exp_proc);
1086 GOTO(out, rc = -ENOMEM);
1089 lprocfs_counter_init(exp->exp_ldlm_stats,
1090 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1091 0, "ldlm_enqueue", "reqs");
1092 lprocfs_counter_init(exp->exp_ldlm_stats,
1093 LDLM_CONVERT - LDLM_FIRST_OPC,
1094 0, "ldlm_convert", "reqs");
1095 lprocfs_counter_init(exp->exp_ldlm_stats,
1096 LDLM_CANCEL - LDLM_FIRST_OPC,
1097 0, "ldlm_cancel", "reqs");
1098 lprocfs_counter_init(exp->exp_ldlm_stats,
1099 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1100 0, "ldlm_bl_callback", "reqs");
1101 lprocfs_counter_init(exp->exp_ldlm_stats,
1102 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1103 0, "ldlm_cp_callback", "reqs");
1104 lprocfs_counter_init(exp->exp_ldlm_stats,
1105 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1106 0, "ldlm_gl_callback", "reqs");
1107 lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
1108 exp->exp_ldlm_stats);
1110 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1114 int lprocfs_exp_cleanup(struct obd_export *exp)
1116 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1117 lprocfs_remove(&exp->exp_proc);
1118 lprocfs_free_stats(&exp->exp_ops_stats);
1119 lprocfs_free_stats(&exp->exp_ldlm_stats);
1120 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1124 int lprocfs_write_helper(const char *buffer, unsigned long count,
1127 return lprocfs_write_frac_helper(buffer, count, val, 1);
1130 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1133 char kernbuf[20], *end, *pbuf;
1135 if (count > (sizeof(kernbuf) - 1))
1138 if (copy_from_user(kernbuf, buffer, count))
1141 kernbuf[count] = '\0';
1148 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1152 if (end != NULL && *end == '.') {
1153 int temp_val, pow = 1;
1157 if (strlen(pbuf) > 5)
1158 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1160 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1163 for (i = 0; i < (end - pbuf); i++)
1166 *val += temp_val / pow;
1172 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1174 long decimal_val, frac_val;
1180 decimal_val = val / mult;
1181 prtn = snprintf(buffer, count, "%ld", decimal_val);
1182 frac_val = val % mult;
1184 if (prtn < (count - 4) && frac_val > 0) {
1186 int i, temp_mult = 1, frac_bits = 0;
1188 temp_frac = frac_val * 10;
1189 buffer[prtn++] = '.';
1190 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1191 buffer[prtn++] ='0';
1196 Need to think these cases :
1197 1. #echo x.00 > /proc/xxx output result : x
1198 2. #echo x.0x > /proc/xxx output result : x.0x
1199 3. #echo x.x0 > /proc/xxx output result : x.x
1200 4. #echo x.xx > /proc/xxx output result : x.xx
1201 Only reserved 2bits fraction.
1203 for (i = 0; i < (5 - prtn); i++)
1206 frac_bits = min((int)count - prtn, 3 - frac_bits);
1207 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1210 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1212 if (buffer[prtn] == '.') {
1219 buffer[prtn++] ='\n';
1223 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1225 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1228 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1229 __u64 *val, int mult)
1231 char kernbuf[22], *end, *pbuf;
1232 __u64 whole, frac = 0, units;
1233 unsigned frac_d = 1;
1235 if (count > (sizeof(kernbuf) - 1) )
1238 if (copy_from_user(kernbuf, buffer, count))
1241 kernbuf[count] = '\0';
1248 whole = simple_strtoull(pbuf, &end, 10);
1252 if (end != NULL && *end == '.') {
1256 /* need to limit frac_d to a __u32 */
1257 if (strlen(pbuf) > 10)
1260 frac = simple_strtoull(pbuf, &end, 10);
1261 /* count decimal places */
1262 for (i = 0; i < (end - pbuf); i++)
1279 /* Specified units override the multiplier */
1281 mult = mult < 0 ? -units : units;
1284 do_div(frac, frac_d);
1285 *val = whole * mult + frac;
1289 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1290 char *name, mode_t mode,
1291 struct file_operations *seq_fops, void *data)
1293 struct proc_dir_entry *entry;
1296 entry = create_proc_entry(name, mode, parent);
1299 entry->proc_fops = seq_fops;
1304 EXPORT_SYMBOL(lprocfs_seq_create);
1306 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1308 struct file_operations *seq_fops,
1311 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1312 mode, seq_fops, data));
1314 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1316 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1318 if (value >= OBD_HIST_MAX)
1319 value = OBD_HIST_MAX - 1;
1321 spin_lock(&oh->oh_lock);
1322 oh->oh_buckets[value]++;
1323 spin_unlock(&oh->oh_lock);
1325 EXPORT_SYMBOL(lprocfs_oh_tally);
1327 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1331 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1334 lprocfs_oh_tally(oh, val);
1336 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1338 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1340 unsigned long ret = 0;
1343 for (i = 0; i < OBD_HIST_MAX; i++)
1344 ret += oh->oh_buckets[i];
1347 EXPORT_SYMBOL(lprocfs_oh_sum);
1349 void lprocfs_oh_clear(struct obd_histogram *oh)
1351 spin_lock(&oh->oh_lock);
1352 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1353 spin_unlock(&oh->oh_lock);
1355 EXPORT_SYMBOL(lprocfs_oh_clear);
1357 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1358 int count, int *eof, void *data)
1360 struct obd_device *obd = data;
1363 LASSERT(obd != NULL);
1364 LASSERT(count >= 0);
1366 /* Set start of user data returned to
1367 page + off since the user may have
1368 requested to read much smaller than
1369 what we need to read */
1370 *start = page + off;
1372 /* We know we are allocated a page here.
1373 Also we know that this function will
1374 not need to write more than a page
1375 so we can truncate at CFS_PAGE_SIZE. */
1376 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1378 /* Initialize the page */
1379 memset(page, 0, size);
1381 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1384 if (obd->obd_max_recoverable_clients == 0) {
1385 lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n");
1389 /* sampled unlocked, but really... */
1390 if (obd->obd_recovering == 0) {
1391 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1394 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1395 obd->obd_recovery_start) <= 0)
1398 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1399 obd->obd_recovery_end) <= 0)
1402 /* Number of clients have have completed recovery */
1403 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1404 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1407 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1408 obd->obd_recoverable_clients) <= 0)
1411 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1412 obd->obd_next_recovery_transno - 1) <= 0)
1415 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1419 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1422 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1423 obd->obd_recovery_start) <= 0)
1426 if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1427 CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
1428 obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
1431 if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1432 obd->obd_connected_clients,
1433 obd->obd_max_recoverable_clients) <= 0)
1436 /* Number of clients have have completed recovery */
1437 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1438 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1439 obd->obd_max_recoverable_clients) <= 0)
1442 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1443 obd->obd_replayed_requests) <= 0)
1446 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1447 obd->obd_requests_queued_for_recovery) <= 0)
1450 lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", obd->obd_next_recovery_transno);
1455 return min(count, len - (int)off);
1457 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1459 EXPORT_SYMBOL(lprocfs_register);
1460 EXPORT_SYMBOL(lprocfs_srch);
1461 EXPORT_SYMBOL(lprocfs_remove);
1462 EXPORT_SYMBOL(lprocfs_add_vars);
1463 EXPORT_SYMBOL(lprocfs_obd_setup);
1464 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1465 EXPORT_SYMBOL(lprocfs_alloc_stats);
1466 EXPORT_SYMBOL(lprocfs_free_stats);
1467 EXPORT_SYMBOL(lprocfs_clear_stats);
1468 EXPORT_SYMBOL(lprocfs_register_stats);
1469 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1470 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1471 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1472 EXPORT_SYMBOL(lprocfs_exp_setup);
1473 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1475 EXPORT_SYMBOL(lprocfs_rd_u64);
1476 EXPORT_SYMBOL(lprocfs_rd_atomic);
1477 EXPORT_SYMBOL(lprocfs_rd_uuid);
1478 EXPORT_SYMBOL(lprocfs_rd_name);
1479 EXPORT_SYMBOL(lprocfs_rd_fstype);
1480 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1481 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1482 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1483 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1485 EXPORT_SYMBOL(lprocfs_rd_blksize);
1486 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1487 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1488 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1489 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1490 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1492 EXPORT_SYMBOL(lprocfs_write_helper);
1493 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1494 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1495 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1496 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);