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, create);
858 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
859 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
860 LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
861 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
862 LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
863 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw);
864 LPROCFS_OBD_OP_INIT(num_private_stats, stats, brw_async);
865 LPROCFS_OBD_OP_INIT(num_private_stats, stats, prep_async_page);
866 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_async_io);
867 LPROCFS_OBD_OP_INIT(num_private_stats, stats, queue_group_io);
868 LPROCFS_OBD_OP_INIT(num_private_stats, stats, trigger_group_io);
869 LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_async_flags);
870 LPROCFS_OBD_OP_INIT(num_private_stats, stats, teardown_async_page);
871 LPROCFS_OBD_OP_INIT(num_private_stats, stats, merge_lvb);
872 LPROCFS_OBD_OP_INIT(num_private_stats, stats, adjust_kms);
873 LPROCFS_OBD_OP_INIT(num_private_stats, stats, punch);
874 LPROCFS_OBD_OP_INIT(num_private_stats, stats, sync);
875 LPROCFS_OBD_OP_INIT(num_private_stats, stats, migrate);
876 LPROCFS_OBD_OP_INIT(num_private_stats, stats, copy);
877 LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate);
878 LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
879 LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
880 LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue);
881 LPROCFS_OBD_OP_INIT(num_private_stats, stats, match);
882 LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
883 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel);
884 LPROCFS_OBD_OP_INIT(num_private_stats, stats, cancel_unused);
885 LPROCFS_OBD_OP_INIT(num_private_stats, stats, join_lru);
886 LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
887 LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
888 LPROCFS_OBD_OP_INIT(num_private_stats, stats, extent_calc);
889 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
890 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
891 LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
892 LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
893 LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
894 LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
895 LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
896 LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
897 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
898 LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
899 LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
902 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
904 struct lprocfs_stats *stats;
905 unsigned int num_stats;
908 LASSERT(obd->obd_stats == NULL);
909 LASSERT(obd->obd_proc_entry != NULL);
910 LASSERT(obd->obd_cntr_base == 0);
912 num_stats = ((int)sizeof(*obd->obd_type->typ_dt_ops) / sizeof(void *)) +
913 num_private_stats - 1 /* o_owner */;
914 stats = lprocfs_alloc_stats(num_stats);
918 lprocfs_init_ops_stats(num_private_stats, stats);
920 for (i = num_private_stats; i < num_stats; i++) {
921 /* If this LBUGs, it is likely that an obd
922 * operation was added to struct obd_ops in
923 * <obd.h>, and that the corresponding line item
924 * LPROCFS_OBD_OP_INIT(.., .., opname)
925 * is missing from the list above. */
926 LASSERTF(stats->ls_percpu[0]->lp_cntr[i].lc_name != NULL,
927 "Missing obd_stat initializer obd_op "
928 "operation at offset %d.\n", i - num_private_stats);
930 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
932 lprocfs_free_stats(&stats);
934 obd->obd_stats = stats;
935 obd->obd_cntr_base = num_private_stats;
940 void lprocfs_free_obd_stats(struct obd_device *obd)
943 lprocfs_free_stats(&obd->obd_stats);
946 #define LPROCFS_MD_OP_INIT(base, stats, op) \
948 unsigned int coffset = base + MD_COUNTER_OFFSET(op); \
949 LASSERT(coffset < stats->ls_num); \
950 lprocfs_counter_init(stats, coffset, 0, #op, "reqs"); \
953 int lprocfs_alloc_md_stats(struct obd_device *obd,
954 unsigned num_private_stats)
956 struct lprocfs_stats *stats;
957 unsigned int num_stats;
960 LASSERT(obd->md_stats == NULL);
961 LASSERT(obd->obd_proc_entry != NULL);
962 LASSERT(obd->md_cntr_base == 0);
964 num_stats = 1 + MD_COUNTER_OFFSET(get_remote_perm) +
966 stats = lprocfs_alloc_stats(num_stats);
970 LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus);
971 LPROCFS_MD_OP_INIT(num_private_stats, stats, change_cbdata);
972 LPROCFS_MD_OP_INIT(num_private_stats, stats, close);
973 LPROCFS_MD_OP_INIT(num_private_stats, stats, create);
974 LPROCFS_MD_OP_INIT(num_private_stats, stats, done_writing);
975 LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue);
976 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr);
977 LPROCFS_MD_OP_INIT(num_private_stats, stats, getattr_name);
978 LPROCFS_MD_OP_INIT(num_private_stats, stats, intent_lock);
979 LPROCFS_MD_OP_INIT(num_private_stats, stats, link);
980 LPROCFS_MD_OP_INIT(num_private_stats, stats, rename);
981 LPROCFS_MD_OP_INIT(num_private_stats, stats, is_subdir);
982 LPROCFS_MD_OP_INIT(num_private_stats, stats, setattr);
983 LPROCFS_MD_OP_INIT(num_private_stats, stats, sync);
984 LPROCFS_MD_OP_INIT(num_private_stats, stats, readpage);
985 LPROCFS_MD_OP_INIT(num_private_stats, stats, unlink);
986 LPROCFS_MD_OP_INIT(num_private_stats, stats, setxattr);
987 LPROCFS_MD_OP_INIT(num_private_stats, stats, getxattr);
988 LPROCFS_MD_OP_INIT(num_private_stats, stats, init_ea_size);
989 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_lustre_md);
990 LPROCFS_MD_OP_INIT(num_private_stats, stats, free_lustre_md);
991 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_open_replay_data);
992 LPROCFS_MD_OP_INIT(num_private_stats, stats, clear_open_replay_data);
993 LPROCFS_MD_OP_INIT(num_private_stats, stats, set_lock_data);
994 LPROCFS_MD_OP_INIT(num_private_stats, stats, lock_match);
995 LPROCFS_MD_OP_INIT(num_private_stats, stats, cancel_unused);
996 LPROCFS_MD_OP_INIT(num_private_stats, stats, renew_capa);
997 LPROCFS_MD_OP_INIT(num_private_stats, stats, get_remote_perm);
999 for (i = num_private_stats; i < num_stats; i++) {
1000 if (stats->ls_percpu[0]->lp_cntr[i].lc_name == NULL) {
1001 CERROR("Missing md_stat initializer md_op "
1002 "operation at offset %d. Aborting.\n",
1003 i - num_private_stats);
1007 rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
1009 lprocfs_free_stats(&stats);
1011 obd->md_stats = stats;
1012 obd->md_cntr_base = num_private_stats;
1017 void lprocfs_free_md_stats(struct obd_device *obd)
1019 struct lprocfs_stats *stats = obd->md_stats;
1021 if (stats != NULL) {
1022 obd->md_stats = NULL;
1023 lprocfs_free_stats(&stats);
1027 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
1028 int *eof, void *data)
1030 struct obd_export *exp = (struct obd_export*)data;
1031 LASSERT(exp != NULL);
1033 return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
1036 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
1037 int *eof, void *data)
1039 struct obd_export *exp = (struct obd_export*)data;
1040 LASSERT(exp != NULL);
1042 return snprintf(page, count, "%s\n",
1043 obd_uuid2str(&exp->exp_client_uuid));
1046 int lprocfs_exp_setup(struct obd_export *exp)
1048 char name[sizeof (exp->exp_client_uuid.uuid) + 3];
1051 if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
1053 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1054 sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
1055 while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
1056 /* We might add a new export before deleting the old one during
1057 an eviction (recovery-small 19a). Suckage. We
1058 could block, or come up with a new name, or just give up. */
1060 GOTO(out, rc = -EEXIST);
1061 sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
1064 /* Create a proc entry for this export */
1065 exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
1066 if (!exp->exp_proc) {
1067 CERROR("Error making export directory for %s\n", name);
1068 GOTO(out, rc = -ENOMEM);
1071 /* Always add nid and uuid */
1072 rc = lprocfs_add_simple(exp->exp_proc, "nid",
1073 lprocfs_exp_rd_nid, NULL, exp);
1076 rc = lprocfs_add_simple(exp->exp_proc, "uuid",
1077 lprocfs_exp_rd_uuid, NULL, exp);
1080 /* Always add ldlm stats */
1081 exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC
1083 if (exp->exp_ldlm_stats == NULL) {
1084 lprocfs_remove(&exp->exp_proc);
1085 GOTO(out, rc = -ENOMEM);
1088 lprocfs_counter_init(exp->exp_ldlm_stats,
1089 LDLM_ENQUEUE - LDLM_FIRST_OPC,
1090 0, "ldlm_enqueue", "reqs");
1091 lprocfs_counter_init(exp->exp_ldlm_stats,
1092 LDLM_CONVERT - LDLM_FIRST_OPC,
1093 0, "ldlm_convert", "reqs");
1094 lprocfs_counter_init(exp->exp_ldlm_stats,
1095 LDLM_CANCEL - LDLM_FIRST_OPC,
1096 0, "ldlm_cancel", "reqs");
1097 lprocfs_counter_init(exp->exp_ldlm_stats,
1098 LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
1099 0, "ldlm_bl_callback", "reqs");
1100 lprocfs_counter_init(exp->exp_ldlm_stats,
1101 LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
1102 0, "ldlm_cp_callback", "reqs");
1103 lprocfs_counter_init(exp->exp_ldlm_stats,
1104 LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
1105 0, "ldlm_gl_callback", "reqs");
1106 lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
1107 exp->exp_ldlm_stats);
1109 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1113 int lprocfs_exp_cleanup(struct obd_export *exp)
1115 mutex_down(&exp->exp_obd->obd_proc_exp_sem);
1116 lprocfs_remove(&exp->exp_proc);
1117 lprocfs_free_stats(&exp->exp_ops_stats);
1118 lprocfs_free_stats(&exp->exp_ldlm_stats);
1119 mutex_up(&exp->exp_obd->obd_proc_exp_sem);
1123 int lprocfs_write_helper(const char *buffer, unsigned long count,
1126 return lprocfs_write_frac_helper(buffer, count, val, 1);
1129 int lprocfs_write_frac_helper(const char *buffer, unsigned long count,
1132 char kernbuf[20], *end, *pbuf;
1134 if (count > (sizeof(kernbuf) - 1))
1137 if (copy_from_user(kernbuf, buffer, count))
1140 kernbuf[count] = '\0';
1147 *val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1151 if (end != NULL && *end == '.') {
1152 int temp_val, pow = 1;
1156 if (strlen(pbuf) > 5)
1157 pbuf[5] = '\0'; /*only allow 5bits fractional*/
1159 temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult;
1162 for (i = 0; i < (end - pbuf); i++)
1165 *val += temp_val / pow;
1171 int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, int mult)
1173 long decimal_val, frac_val;
1179 decimal_val = val / mult;
1180 prtn = snprintf(buffer, count, "%ld", decimal_val);
1181 frac_val = val % mult;
1183 if (prtn < (count - 4) && frac_val > 0) {
1185 int i, temp_mult = 1, frac_bits = 0;
1187 temp_frac = frac_val * 10;
1188 buffer[prtn++] = '.';
1189 while (frac_bits < 2 && (temp_frac / mult) < 1 ) { /*only reserved 2bits fraction*/
1190 buffer[prtn++] ='0';
1195 Need to think these cases :
1196 1. #echo x.00 > /proc/xxx output result : x
1197 2. #echo x.0x > /proc/xxx output result : x.0x
1198 3. #echo x.x0 > /proc/xxx output result : x.x
1199 4. #echo x.xx > /proc/xxx output result : x.xx
1200 Only reserved 2bits fraction.
1202 for (i = 0; i < (5 - prtn); i++)
1205 frac_bits = min((int)count - prtn, 3 - frac_bits);
1206 prtn += snprintf(buffer + prtn, frac_bits, "%ld", frac_val * temp_mult / mult);
1209 while(buffer[prtn] < '1' || buffer[prtn] > '9') {
1211 if (buffer[prtn] == '.') {
1218 buffer[prtn++] ='\n';
1222 int lprocfs_write_u64_helper(const char *buffer, unsigned long count,__u64 *val)
1224 return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
1227 int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
1228 __u64 *val, int mult)
1230 char kernbuf[22], *end, *pbuf;
1231 __u64 whole, frac = 0, units;
1232 unsigned frac_d = 1;
1234 if (count > (sizeof(kernbuf) - 1) )
1237 if (copy_from_user(kernbuf, buffer, count))
1240 kernbuf[count] = '\0';
1247 whole = simple_strtoull(pbuf, &end, 10);
1251 if (end != NULL && *end == '.') {
1255 /* need to limit frac_d to a __u32 */
1256 if (strlen(pbuf) > 10)
1259 frac = simple_strtoull(pbuf, &end, 10);
1260 /* count decimal places */
1261 for (i = 0; i < (end - pbuf); i++)
1278 /* Specified units override the multiplier */
1280 mult = mult < 0 ? -units : units;
1283 do_div(frac, frac_d);
1284 *val = whole * mult + frac;
1288 int lprocfs_seq_create(cfs_proc_dir_entry_t *parent,
1289 char *name, mode_t mode,
1290 struct file_operations *seq_fops, void *data)
1292 struct proc_dir_entry *entry;
1295 entry = create_proc_entry(name, mode, parent);
1298 entry->proc_fops = seq_fops;
1303 EXPORT_SYMBOL(lprocfs_seq_create);
1305 __inline__ int lprocfs_obd_seq_create(struct obd_device *dev, char *name,
1307 struct file_operations *seq_fops,
1310 return (lprocfs_seq_create(dev->obd_proc_entry, name,
1311 mode, seq_fops, data));
1313 EXPORT_SYMBOL(lprocfs_obd_seq_create);
1315 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
1317 if (value >= OBD_HIST_MAX)
1318 value = OBD_HIST_MAX - 1;
1320 spin_lock(&oh->oh_lock);
1321 oh->oh_buckets[value]++;
1322 spin_unlock(&oh->oh_lock);
1324 EXPORT_SYMBOL(lprocfs_oh_tally);
1326 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
1330 for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
1333 lprocfs_oh_tally(oh, val);
1335 EXPORT_SYMBOL(lprocfs_oh_tally_log2);
1337 unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
1339 unsigned long ret = 0;
1342 for (i = 0; i < OBD_HIST_MAX; i++)
1343 ret += oh->oh_buckets[i];
1346 EXPORT_SYMBOL(lprocfs_oh_sum);
1348 void lprocfs_oh_clear(struct obd_histogram *oh)
1350 spin_lock(&oh->oh_lock);
1351 memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
1352 spin_unlock(&oh->oh_lock);
1354 EXPORT_SYMBOL(lprocfs_oh_clear);
1356 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
1357 int count, int *eof, void *data)
1359 struct obd_device *obd = data;
1362 LASSERT(obd != NULL);
1363 LASSERT(count >= 0);
1365 /* Set start of user data returned to
1366 page + off since the user may have
1367 requested to read much smaller than
1368 what we need to read */
1369 *start = page + off;
1371 /* We know we are allocated a page here.
1372 Also we know that this function will
1373 not need to write more than a page
1374 so we can truncate at CFS_PAGE_SIZE. */
1375 size = min(count + (int)off + 1, (int)CFS_PAGE_SIZE);
1377 /* Initialize the page */
1378 memset(page, 0, size);
1380 if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
1383 if (obd->obd_max_recoverable_clients == 0) {
1384 lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n");
1388 /* sampled unlocked, but really... */
1389 if (obd->obd_recovering == 0) {
1390 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
1393 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1394 obd->obd_recovery_start) <= 0)
1397 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_end: %lu\n",
1398 obd->obd_recovery_end) <= 0)
1401 /* Number of clients have have completed recovery */
1402 if (lprocfs_obd_snprintf(&page, size, &len, "recovered_clients: %d\n",
1403 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients) <= 0)
1406 if (lprocfs_obd_snprintf(&page, size, &len, "unrecovered_clients: %d\n",
1407 obd->obd_recoverable_clients) <= 0)
1410 if (lprocfs_obd_snprintf(&page, size, &len, "last_transno: "LPD64"\n",
1411 obd->obd_next_recovery_transno - 1) <= 0)
1414 lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n", obd->obd_replayed_requests);
1418 if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
1421 if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
1422 obd->obd_recovery_start) <= 0)
1425 if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
1426 CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
1427 obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
1430 if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
1431 obd->obd_connected_clients,
1432 obd->obd_max_recoverable_clients) <= 0)
1435 /* Number of clients have have completed recovery */
1436 if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d/%d\n",
1437 obd->obd_max_recoverable_clients - obd->obd_recoverable_clients,
1438 obd->obd_max_recoverable_clients) <= 0)
1441 if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d/??\n",
1442 obd->obd_replayed_requests) <= 0)
1445 if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1446 obd->obd_requests_queued_for_recovery) <= 0)
1449 lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n", obd->obd_next_recovery_transno);
1454 return min(count, len - (int)off);
1456 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1458 EXPORT_SYMBOL(lprocfs_register);
1459 EXPORT_SYMBOL(lprocfs_srch);
1460 EXPORT_SYMBOL(lprocfs_remove);
1461 EXPORT_SYMBOL(lprocfs_add_vars);
1462 EXPORT_SYMBOL(lprocfs_obd_setup);
1463 EXPORT_SYMBOL(lprocfs_obd_cleanup);
1464 EXPORT_SYMBOL(lprocfs_alloc_stats);
1465 EXPORT_SYMBOL(lprocfs_free_stats);
1466 EXPORT_SYMBOL(lprocfs_clear_stats);
1467 EXPORT_SYMBOL(lprocfs_register_stats);
1468 EXPORT_SYMBOL(lprocfs_init_ops_stats);
1469 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
1470 EXPORT_SYMBOL(lprocfs_free_obd_stats);
1471 EXPORT_SYMBOL(lprocfs_exp_setup);
1472 EXPORT_SYMBOL(lprocfs_exp_cleanup);
1474 EXPORT_SYMBOL(lprocfs_rd_u64);
1475 EXPORT_SYMBOL(lprocfs_rd_atomic);
1476 EXPORT_SYMBOL(lprocfs_rd_uuid);
1477 EXPORT_SYMBOL(lprocfs_rd_name);
1478 EXPORT_SYMBOL(lprocfs_rd_fstype);
1479 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
1480 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
1481 EXPORT_SYMBOL(lprocfs_rd_num_exports);
1482 EXPORT_SYMBOL(lprocfs_rd_numrefs);
1484 EXPORT_SYMBOL(lprocfs_rd_blksize);
1485 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
1486 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
1487 EXPORT_SYMBOL(lprocfs_rd_kbytesavail);
1488 EXPORT_SYMBOL(lprocfs_rd_filestotal);
1489 EXPORT_SYMBOL(lprocfs_rd_filesfree);
1491 EXPORT_SYMBOL(lprocfs_write_helper);
1492 EXPORT_SYMBOL(lprocfs_write_frac_helper);
1493 EXPORT_SYMBOL(lprocfs_read_frac_helper);
1494 EXPORT_SYMBOL(lprocfs_write_u64_helper);
1495 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);