xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision 473c90ac04cec0abbb414978c53e9c259c9129e8)
13f6cab07SMatt Macy /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33f6cab07SMatt Macy  *
43f6cab07SMatt Macy  * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
53f6cab07SMatt Macy  *
63f6cab07SMatt Macy  * Redistribution and use in source and binary forms, with or without
73f6cab07SMatt Macy  * modification, are permitted provided that the following conditions
83f6cab07SMatt Macy  * are met:
93f6cab07SMatt Macy  * 1. Redistributions of source code must retain the above copyright
103f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer.
113f6cab07SMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
123f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer in the
133f6cab07SMatt Macy  *    documentation and/or other materials provided with the distribution.
143f6cab07SMatt Macy  *
153f6cab07SMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163f6cab07SMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173f6cab07SMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183f6cab07SMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193f6cab07SMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203f6cab07SMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213f6cab07SMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223f6cab07SMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233f6cab07SMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243f6cab07SMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253f6cab07SMatt Macy  * SUCH DAMAGE.
263f6cab07SMatt Macy  *
273f6cab07SMatt Macy  */
283f6cab07SMatt Macy 
293f6cab07SMatt Macy #include <sys/param.h>
303f6cab07SMatt Macy #include <sys/systm.h>
313f6cab07SMatt Macy #include <sys/queue.h>
323f6cab07SMatt Macy #include <sys/blist.h>
333f6cab07SMatt Macy #include <sys/conf.h>
343f6cab07SMatt Macy #include <sys/exec.h>
353f6cab07SMatt Macy #include <sys/filedesc.h>
363f6cab07SMatt Macy #include <sys/kernel.h>
373f6cab07SMatt Macy #include <sys/linker.h>
383f6cab07SMatt Macy #include <sys/malloc.h>
393f6cab07SMatt Macy #include <sys/mount.h>
403f6cab07SMatt Macy #include <sys/mutex.h>
413f6cab07SMatt Macy #include <sys/proc.h>
423f6cab07SMatt Macy #include <sys/resourcevar.h>
433f6cab07SMatt Macy #include <sys/sbuf.h>
443f6cab07SMatt Macy #include <sys/smp.h>
453f6cab07SMatt Macy #include <sys/socket.h>
463f6cab07SMatt Macy #include <sys/vnode.h>
473f6cab07SMatt Macy #include <sys/bus.h>
483f6cab07SMatt Macy #include <sys/pciio.h>
493f6cab07SMatt Macy 
503f6cab07SMatt Macy #include <dev/pci/pcivar.h>
513f6cab07SMatt Macy #include <dev/pci/pcireg.h>
523f6cab07SMatt Macy 
533f6cab07SMatt Macy #include <net/if.h>
543f6cab07SMatt Macy 
553f6cab07SMatt Macy #include <vm/vm.h>
563f6cab07SMatt Macy #include <vm/pmap.h>
573f6cab07SMatt Macy #include <vm/vm_map.h>
583f6cab07SMatt Macy #include <vm/vm_param.h>
593f6cab07SMatt Macy #include <vm/vm_object.h>
603f6cab07SMatt Macy #include <vm/swap_pager.h>
613f6cab07SMatt Macy 
623f6cab07SMatt Macy #include <machine/bus.h>
633f6cab07SMatt Macy 
643f6cab07SMatt Macy #include <compat/linux/linux_ioctl.h>
653f6cab07SMatt Macy #include <compat/linux/linux_mib.h>
663f6cab07SMatt Macy #include <compat/linux/linux_util.h>
673f6cab07SMatt Macy #include <fs/pseudofs/pseudofs.h>
683f6cab07SMatt Macy 
69f2044a30SJean-Sébastien Pédron #include <asm/atomic.h>
703f6cab07SMatt Macy #include <linux/compat.h>
71f697b943SJake Freeland #include <linux/debugfs.h>
72f697b943SJake Freeland #include <linux/fs.h>
733f6cab07SMatt Macy 
743f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
753f6cab07SMatt Macy 
763f6cab07SMatt Macy static struct pfs_node *debugfs_root;
773f6cab07SMatt Macy 
783f6cab07SMatt Macy #define DM_SYMLINK 0x1
793f6cab07SMatt Macy #define DM_DIR 0x2
803f6cab07SMatt Macy #define DM_FILE 0x3
813f6cab07SMatt Macy 
823f6cab07SMatt Macy struct dentry_meta {
833f6cab07SMatt Macy 	struct dentry dm_dnode;
843f6cab07SMatt Macy 	const struct file_operations *dm_fops;
853f6cab07SMatt Macy 	void *dm_data;
863f6cab07SMatt Macy 	umode_t dm_mode;
873f6cab07SMatt Macy 	int dm_type;
883f6cab07SMatt Macy };
893f6cab07SMatt Macy 
903f6cab07SMatt Macy static int
913f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
923f6cab07SMatt Macy {
933f6cab07SMatt Macy 	struct dentry_meta *dm;
943f6cab07SMatt Macy 
953f6cab07SMatt Macy 	dm = pn->pn_data;
963f6cab07SMatt Macy 
973f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
983f6cab07SMatt Macy 	return (0);
993f6cab07SMatt Macy }
1003f6cab07SMatt Macy 
1013f6cab07SMatt Macy static int
1023f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1033f6cab07SMatt Macy {
1043f6cab07SMatt Macy 	struct dentry_meta *dm;
1053f6cab07SMatt Macy 
1063f6cab07SMatt Macy 	dm = pn->pn_data;
1073f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1083f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1093f6cab07SMatt Macy 
1103f6cab07SMatt Macy 	free(dm, M_DFSINT);
1113f6cab07SMatt Macy 	return (0);
1123f6cab07SMatt Macy }
1133f6cab07SMatt Macy 
1143f6cab07SMatt Macy static int
1153f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1163f6cab07SMatt Macy {
1173f6cab07SMatt Macy 	struct dentry_meta *d;
11888a29d89SHans Petter Selasky 	struct linux_file lf = {};
1193f6cab07SMatt Macy 	struct vnode vn;
120f697b943SJake Freeland 	char *buf;
1213f6cab07SMatt Macy 	int rc;
122f697b943SJake Freeland 	off_t off = 0;
1233f6cab07SMatt Macy 
1243f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1253f6cab07SMatt Macy 		return (rc);
126f697b943SJake Freeland 
127f697b943SJake Freeland 	d = pn->pn_data;
1283f6cab07SMatt Macy 	vn.v_data = d->dm_data;
129f697b943SJake Freeland 
1303f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1313f6cab07SMatt Macy 	if (rc < 0) {
1323f6cab07SMatt Macy #ifdef INVARIANTS
1333f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1343f6cab07SMatt Macy #endif
1353f6cab07SMatt Macy 		return (-rc);
1363f6cab07SMatt Macy 	}
137f697b943SJake Freeland 
13868ec2949SHans Petter Selasky 	rc = -ENODEV;
139*473c90acSJohn Baldwin 	switch (uio->uio_rw) {
140*473c90acSJohn Baldwin 	case UIO_READ:
141*473c90acSJohn Baldwin 		if (d->dm_fops->read != NULL) {
142f697b943SJake Freeland 			rc = -ENOMEM;
143*473c90acSJohn Baldwin 			buf = malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
144f697b943SJake Freeland 			if (buf != NULL) {
145*473c90acSJohn Baldwin 				rc = d->dm_fops->read(&lf, buf, sb->s_size,
146*473c90acSJohn Baldwin 				    &off);
147f697b943SJake Freeland 				if (rc > 0)
148f697b943SJake Freeland 					sbuf_bcpy(sb, buf, strlen(buf));
149f697b943SJake Freeland 
150f697b943SJake Freeland 				free(buf, M_DFSINT);
15103f1cf9fSJohannes Lundberg 			}
152*473c90acSJohn Baldwin 		}
153*473c90acSJohn Baldwin 		break;
154*473c90acSJohn Baldwin 	case UIO_WRITE:
155*473c90acSJohn Baldwin 		if (d->dm_fops->write != NULL) {
156f697b943SJake Freeland 			sbuf_finish(sb);
157*473c90acSJohn Baldwin 			rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb),
158*473c90acSJohn Baldwin 			    &off);
159*473c90acSJohn Baldwin 		}
160*473c90acSJohn Baldwin 		break;
161f697b943SJake Freeland 	}
162f697b943SJake Freeland 
1633f6cab07SMatt Macy 	if (d->dm_fops->release)
1643f6cab07SMatt Macy 		d->dm_fops->release(&vn, &lf);
1653f6cab07SMatt Macy 	else
1663f6cab07SMatt Macy 		single_release(&vn, &lf);
1673f6cab07SMatt Macy 
1683f6cab07SMatt Macy 	if (rc < 0) {
1693f6cab07SMatt Macy #ifdef INVARIANTS
1703f6cab07SMatt Macy 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
1713f6cab07SMatt Macy #endif
1723f6cab07SMatt Macy 		return (-rc);
1733f6cab07SMatt Macy 	}
1743f6cab07SMatt Macy 	return (0);
1753f6cab07SMatt Macy }
1763f6cab07SMatt Macy 
1773f6cab07SMatt Macy static int
1783f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1793f6cab07SMatt Macy {
1803f6cab07SMatt Macy 	struct dentry_meta *dm;
1813f6cab07SMatt Macy 
1823f6cab07SMatt Macy 	dm = pn->pn_data;
1833f6cab07SMatt Macy 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
1843f6cab07SMatt Macy 	return (0);
1853f6cab07SMatt Macy }
1863f6cab07SMatt Macy 
1873f6cab07SMatt Macy struct dentry *
1883f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1893f6cab07SMatt Macy     struct dentry *parent, void *data,
1903f6cab07SMatt Macy     const struct file_operations *fops)
1913f6cab07SMatt Macy {
1923f6cab07SMatt Macy 	struct dentry_meta *dm;
1933f6cab07SMatt Macy 	struct dentry *dnode;
1943f6cab07SMatt Macy 	struct pfs_node *pnode;
1953f6cab07SMatt Macy 	int flags;
1963f6cab07SMatt Macy 
1973f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1983f6cab07SMatt Macy 	if (dm == NULL)
1993f6cab07SMatt Macy 		return (NULL);
2003f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2013f6cab07SMatt Macy 	dm->dm_fops = fops;
2023f6cab07SMatt Macy 	dm->dm_data = data;
2033f6cab07SMatt Macy 	dm->dm_mode = mode;
2043f6cab07SMatt Macy 	dm->dm_type = DM_FILE;
2053f6cab07SMatt Macy 	if (parent != NULL)
2063f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2073f6cab07SMatt Macy 	else
2083f6cab07SMatt Macy 		pnode = debugfs_root;
2093f6cab07SMatt Macy 
2103f6cab07SMatt Macy 	flags = fops->write ? PFS_RDWR : PFS_RD;
2113f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2123f6cab07SMatt Macy 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2133f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2143f6cab07SMatt Macy 		free(dm, M_DFSINT);
2153f6cab07SMatt Macy 		return (NULL);
2163f6cab07SMatt Macy 	}
2173f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2183f6cab07SMatt Macy 
2193f6cab07SMatt Macy 	return (dnode);
2203f6cab07SMatt Macy }
2213f6cab07SMatt Macy 
222a04aa80eSJean-Sébastien Pédron struct dentry *
223a04aa80eSJean-Sébastien Pédron debugfs_create_file_size(const char *name, umode_t mode,
224a04aa80eSJean-Sébastien Pédron     struct dentry *parent, void *data,
225a04aa80eSJean-Sébastien Pédron     const struct file_operations *fops,
226a04aa80eSJean-Sébastien Pédron     loff_t file_size __unused)
227a04aa80eSJean-Sébastien Pédron {
228a04aa80eSJean-Sébastien Pédron 
229a04aa80eSJean-Sébastien Pédron 	return debugfs_create_file(name, mode, parent, data, fops);
230a04aa80eSJean-Sébastien Pédron }
231a04aa80eSJean-Sébastien Pédron 
232f697b943SJake Freeland /*
233f697b943SJake Freeland  * NOTE: Files created with the _unsafe moniker will not be protected from
234f697b943SJake Freeland  * debugfs core file removals. It is the responsibility of @fops to protect
235f697b943SJake Freeland  * its file using debugfs_file_get() and debugfs_file_put().
236f697b943SJake Freeland  *
237f697b943SJake Freeland  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
238f697b943SJake Freeland  * of writing. Therefore there is no difference between functions with _unsafe
239f697b943SJake Freeland  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
240f697b943SJake Freeland  * exist only for Linux compatibility.
241f697b943SJake Freeland  */
242f697b943SJake Freeland struct dentry *
243f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
244f697b943SJake Freeland     struct dentry *parent, void *data,
245f697b943SJake Freeland     const struct file_operations *fops)
246f697b943SJake Freeland {
247a04aa80eSJean-Sébastien Pédron 
248f697b943SJake Freeland 	return (debugfs_create_file(name, mode, parent, data, fops));
249f697b943SJake Freeland }
250f697b943SJake Freeland 
251f697b943SJake Freeland struct dentry *
252f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
253f697b943SJake Freeland     struct dentry *parent, void *data,
254f697b943SJake Freeland     const struct file_operations *fops,
255f697b943SJake Freeland     const struct file_operations *fops_ro,
256f697b943SJake Freeland     const struct file_operations *fops_wo)
257f697b943SJake Freeland {
258f697b943SJake Freeland 	umode_t read = mode & S_IRUGO;
259f697b943SJake Freeland 	umode_t write = mode & S_IWUGO;
260f697b943SJake Freeland 
261f697b943SJake Freeland 	if (read && !write)
262f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
263f697b943SJake Freeland 
264f697b943SJake Freeland 	if (write && !read)
265f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
266f697b943SJake Freeland 
267f697b943SJake Freeland 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
268f697b943SJake Freeland }
269f697b943SJake Freeland 
2703f6cab07SMatt Macy struct dentry *
2713f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2723f6cab07SMatt Macy {
2733f6cab07SMatt Macy 	struct dentry_meta *dm;
2743f6cab07SMatt Macy 	struct dentry *dnode;
2753f6cab07SMatt Macy 	struct pfs_node *pnode;
2763f6cab07SMatt Macy 
2773f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2783f6cab07SMatt Macy 	if (dm == NULL)
2793f6cab07SMatt Macy 		return (NULL);
2803f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2813f6cab07SMatt Macy 	dm->dm_mode = 0700;
2823f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2833f6cab07SMatt Macy 	if (parent != NULL)
2843f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2853f6cab07SMatt Macy 	else
2863f6cab07SMatt Macy 		pnode = debugfs_root;
2873f6cab07SMatt Macy 
2883f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2893f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2903f6cab07SMatt Macy 		free(dm, M_DFSINT);
2913f6cab07SMatt Macy 		return (NULL);
2923f6cab07SMatt Macy 	}
2933f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2943f6cab07SMatt Macy 	return (dnode);
2953f6cab07SMatt Macy }
2963f6cab07SMatt Macy 
2973f6cab07SMatt Macy struct dentry *
2983f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2993f6cab07SMatt Macy     const char *dest)
3003f6cab07SMatt Macy {
3013f6cab07SMatt Macy 	struct dentry_meta *dm;
3023f6cab07SMatt Macy 	struct dentry *dnode;
3033f6cab07SMatt Macy 	struct pfs_node *pnode;
3043f6cab07SMatt Macy 	void *data;
3053f6cab07SMatt Macy 
3063f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
3073f6cab07SMatt Macy 	if (data == NULL)
3083f6cab07SMatt Macy 		return (NULL);
3093f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
3103f6cab07SMatt Macy 	if (dm == NULL)
3113f6cab07SMatt Macy 		goto fail1;
3123f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
3133f6cab07SMatt Macy 	dm->dm_mode = 0700;
3143f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
3153f6cab07SMatt Macy 	dm->dm_data = data;
3163f6cab07SMatt Macy 	if (parent != NULL)
3173f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
3183f6cab07SMatt Macy 	else
3193f6cab07SMatt Macy 		pnode = debugfs_root;
3203f6cab07SMatt Macy 
3213f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3223f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
3233f6cab07SMatt Macy 		goto fail;
3243f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
3253f6cab07SMatt Macy 	return (dnode);
3263f6cab07SMatt Macy  fail:
3273f6cab07SMatt Macy 	free(dm, M_DFSINT);
3283f6cab07SMatt Macy  fail1:
3293f6cab07SMatt Macy 	free(data, M_DFSINT);
3303f6cab07SMatt Macy 	return (NULL);
3313f6cab07SMatt Macy }
3323f6cab07SMatt Macy 
3333f6cab07SMatt Macy void
3343f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3353f6cab07SMatt Macy {
3363f6cab07SMatt Macy 	if (dnode == NULL)
3373f6cab07SMatt Macy 		return;
3383f6cab07SMatt Macy 
3393f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3403f6cab07SMatt Macy }
3413f6cab07SMatt Macy 
3423f6cab07SMatt Macy void
3433f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3443f6cab07SMatt Macy {
3453f6cab07SMatt Macy 	if (dnode == NULL)
3463f6cab07SMatt Macy 		return;
3473f6cab07SMatt Macy 
3483f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3493f6cab07SMatt Macy }
3503f6cab07SMatt Macy 
3513f6cab07SMatt Macy static int
352f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
353f697b943SJake Freeland {
354f697b943SJake Freeland 	bool *bval = data;
355f697b943SJake Freeland 
356f697b943SJake Freeland 	if (*bval)
357f697b943SJake Freeland 		*ullval = 1;
358f697b943SJake Freeland 	else
359f697b943SJake Freeland 		*ullval = 0;
360f697b943SJake Freeland 
361f697b943SJake Freeland 	return (0);
362f697b943SJake Freeland }
363f697b943SJake Freeland 
364f697b943SJake Freeland static int
365f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
366f697b943SJake Freeland {
367f697b943SJake Freeland 	bool *bval = data;
368f697b943SJake Freeland 
369f697b943SJake Freeland 	if (ullval)
370f697b943SJake Freeland 		*bval = 1;
371f697b943SJake Freeland 	else
372f697b943SJake Freeland 		*bval = 0;
373f697b943SJake Freeland 
374f697b943SJake Freeland 	return (0);
375f697b943SJake Freeland }
376f697b943SJake Freeland 
377f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
378f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
379f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
380f697b943SJake Freeland 
381f697b943SJake Freeland void
382f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
383f697b943SJake Freeland {
384976aa07aSJean-Sébastien Pédron 
385f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
386f697b943SJake Freeland 	    &fops_bool_ro, &fops_bool_wo);
387f697b943SJake Freeland }
388f697b943SJake Freeland 
3890fce2dc1SBjoern A. Zeeb 
3900fce2dc1SBjoern A. Zeeb static int
3910fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
3920fce2dc1SBjoern A. Zeeb {
3930fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3940fce2dc1SBjoern A. Zeeb 	*value = *u8data;
3950fce2dc1SBjoern A. Zeeb 	return (0);
3960fce2dc1SBjoern A. Zeeb }
3970fce2dc1SBjoern A. Zeeb 
3980fce2dc1SBjoern A. Zeeb static int
3990fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
4000fce2dc1SBjoern A. Zeeb {
4010fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
4020fce2dc1SBjoern A. Zeeb 	*u8data = (uint8_t)value;
4030fce2dc1SBjoern A. Zeeb 	return (0);
4040fce2dc1SBjoern A. Zeeb }
4050fce2dc1SBjoern A. Zeeb 
4060fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
4070fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
4080fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
4090fce2dc1SBjoern A. Zeeb 
4100fce2dc1SBjoern A. Zeeb void
4110fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
4120fce2dc1SBjoern A. Zeeb {
413976aa07aSJean-Sébastien Pédron 
4140fce2dc1SBjoern A. Zeeb 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
4150fce2dc1SBjoern A. Zeeb 	    &fops_u8_ro, &fops_u8_wo);
4160fce2dc1SBjoern A. Zeeb }
4170fce2dc1SBjoern A. Zeeb 
418976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
419976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
420976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
421976aa07aSJean-Sébastien Pédron 
422976aa07aSJean-Sébastien Pédron void
423976aa07aSJean-Sébastien Pédron debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
424976aa07aSJean-Sébastien Pédron {
425976aa07aSJean-Sébastien Pédron 
426976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
427976aa07aSJean-Sébastien Pédron 	    &fops_x8_ro, &fops_x8_wo);
428976aa07aSJean-Sébastien Pédron }
429976aa07aSJean-Sébastien Pédron 
430976aa07aSJean-Sébastien Pédron 
431976aa07aSJean-Sébastien Pédron static int
432976aa07aSJean-Sébastien Pédron debugfs_u16_get(void *data, uint64_t *value)
433976aa07aSJean-Sébastien Pédron {
434976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
435976aa07aSJean-Sébastien Pédron 	*value = *u16data;
436976aa07aSJean-Sébastien Pédron 	return (0);
437976aa07aSJean-Sébastien Pédron }
438976aa07aSJean-Sébastien Pédron 
439976aa07aSJean-Sébastien Pédron static int
440976aa07aSJean-Sébastien Pédron debugfs_u16_set(void *data, uint64_t value)
441976aa07aSJean-Sébastien Pédron {
442976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
443976aa07aSJean-Sébastien Pédron 	*u16data = (uint16_t)value;
444976aa07aSJean-Sébastien Pédron 	return (0);
445976aa07aSJean-Sébastien Pédron }
446976aa07aSJean-Sébastien Pédron 
447976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
448976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
449976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
450976aa07aSJean-Sébastien Pédron 
451976aa07aSJean-Sébastien Pédron void
452976aa07aSJean-Sébastien Pédron debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
453976aa07aSJean-Sébastien Pédron {
454976aa07aSJean-Sébastien Pédron 
455976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
456976aa07aSJean-Sébastien Pédron 	    &fops_u16_ro, &fops_u16_wo);
457976aa07aSJean-Sébastien Pédron }
458976aa07aSJean-Sébastien Pédron 
459976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
460976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
461976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
462976aa07aSJean-Sébastien Pédron 
463976aa07aSJean-Sébastien Pédron void
464976aa07aSJean-Sébastien Pédron debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
465976aa07aSJean-Sébastien Pédron {
466976aa07aSJean-Sébastien Pédron 
467976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
468976aa07aSJean-Sébastien Pédron 	    &fops_x16_ro, &fops_x16_wo);
469976aa07aSJean-Sébastien Pédron }
470976aa07aSJean-Sébastien Pédron 
471976aa07aSJean-Sébastien Pédron 
472976aa07aSJean-Sébastien Pédron static int
473976aa07aSJean-Sébastien Pédron debugfs_u32_get(void *data, uint64_t *value)
474976aa07aSJean-Sébastien Pédron {
475976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
476976aa07aSJean-Sébastien Pédron 	*value = *u32data;
477976aa07aSJean-Sébastien Pédron 	return (0);
478976aa07aSJean-Sébastien Pédron }
479976aa07aSJean-Sébastien Pédron 
480976aa07aSJean-Sébastien Pédron static int
481976aa07aSJean-Sébastien Pédron debugfs_u32_set(void *data, uint64_t value)
482976aa07aSJean-Sébastien Pédron {
483976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
484976aa07aSJean-Sébastien Pédron 	*u32data = (uint32_t)value;
485976aa07aSJean-Sébastien Pédron 	return (0);
486976aa07aSJean-Sébastien Pédron }
487976aa07aSJean-Sébastien Pédron 
488976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
489976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
490976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
491976aa07aSJean-Sébastien Pédron 
492976aa07aSJean-Sébastien Pédron void
493976aa07aSJean-Sébastien Pédron debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
494976aa07aSJean-Sébastien Pédron {
495976aa07aSJean-Sébastien Pédron 
496976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
497976aa07aSJean-Sébastien Pédron 	    &fops_u32_ro, &fops_u32_wo);
498976aa07aSJean-Sébastien Pédron }
499976aa07aSJean-Sébastien Pédron 
500976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
501976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
502976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
503976aa07aSJean-Sébastien Pédron 
504976aa07aSJean-Sébastien Pédron void
505976aa07aSJean-Sébastien Pédron debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
506976aa07aSJean-Sébastien Pédron {
507976aa07aSJean-Sébastien Pédron 
508976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
509976aa07aSJean-Sébastien Pédron 	    &fops_x32_ro, &fops_x32_wo);
510976aa07aSJean-Sébastien Pédron }
511976aa07aSJean-Sébastien Pédron 
512976aa07aSJean-Sébastien Pédron 
513976aa07aSJean-Sébastien Pédron static int
514976aa07aSJean-Sébastien Pédron debugfs_u64_get(void *data, uint64_t *value)
515976aa07aSJean-Sébastien Pédron {
516976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
517976aa07aSJean-Sébastien Pédron 	*value = *u64data;
518976aa07aSJean-Sébastien Pédron 	return (0);
519976aa07aSJean-Sébastien Pédron }
520976aa07aSJean-Sébastien Pédron 
521976aa07aSJean-Sébastien Pédron static int
522976aa07aSJean-Sébastien Pédron debugfs_u64_set(void *data, uint64_t value)
523976aa07aSJean-Sébastien Pédron {
524976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
525976aa07aSJean-Sébastien Pédron 	*u64data = (uint64_t)value;
526976aa07aSJean-Sébastien Pédron 	return (0);
527976aa07aSJean-Sébastien Pédron }
528976aa07aSJean-Sébastien Pédron 
529976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
530976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
531976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
532976aa07aSJean-Sébastien Pédron 
533976aa07aSJean-Sébastien Pédron void
534976aa07aSJean-Sébastien Pédron debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
535976aa07aSJean-Sébastien Pédron {
536976aa07aSJean-Sébastien Pédron 
537976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
538976aa07aSJean-Sébastien Pédron 	    &fops_u64_ro, &fops_u64_wo);
539976aa07aSJean-Sébastien Pédron }
540976aa07aSJean-Sébastien Pédron 
541976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
542976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
543976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
544976aa07aSJean-Sébastien Pédron 
545976aa07aSJean-Sébastien Pédron void
546976aa07aSJean-Sébastien Pédron debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
547976aa07aSJean-Sébastien Pédron {
548976aa07aSJean-Sébastien Pédron 
549976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
550976aa07aSJean-Sébastien Pédron 	    &fops_x64_ro, &fops_x64_wo);
551976aa07aSJean-Sébastien Pédron }
552976aa07aSJean-Sébastien Pédron 
5530fce2dc1SBjoern A. Zeeb 
554f697b943SJake Freeland static int
555f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
556f697b943SJake Freeland {
557f697b943SJake Freeland 	uint64_t *uldata = data;
558f697b943SJake Freeland 	*value = *uldata;
559f697b943SJake Freeland 	return (0);
560f697b943SJake Freeland }
561f697b943SJake Freeland 
562f697b943SJake Freeland static int
563f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
564f697b943SJake Freeland {
565f697b943SJake Freeland 	uint64_t *uldata = data;
566f697b943SJake Freeland 	*uldata = value;
567f697b943SJake Freeland 	return (0);
568f697b943SJake Freeland }
569f697b943SJake Freeland 
570f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
571f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
572f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
573f697b943SJake Freeland 
574f697b943SJake Freeland void
575f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
576f697b943SJake Freeland {
577976aa07aSJean-Sébastien Pédron 
578f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
579f697b943SJake Freeland 	    &fops_ulong_ro, &fops_ulong_wo);
580f697b943SJake Freeland }
581f697b943SJake Freeland 
5820fce2dc1SBjoern A. Zeeb 
583f2044a30SJean-Sébastien Pédron static int
584f2044a30SJean-Sébastien Pédron debugfs_atomic_t_get(void *data, uint64_t *value)
585f2044a30SJean-Sébastien Pédron {
586f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
587f2044a30SJean-Sébastien Pédron 	*value = atomic_read(atomic_data);
588f2044a30SJean-Sébastien Pédron 	return (0);
589f2044a30SJean-Sébastien Pédron }
590f2044a30SJean-Sébastien Pédron 
591f2044a30SJean-Sébastien Pédron static int
592f2044a30SJean-Sébastien Pédron debugfs_atomic_t_set(void *data, uint64_t value)
593f2044a30SJean-Sébastien Pédron {
594f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
595f2044a30SJean-Sébastien Pédron 	atomic_set(atomic_data, (int)value);
596f2044a30SJean-Sébastien Pédron 	return (0);
597f2044a30SJean-Sébastien Pédron }
598f2044a30SJean-Sébastien Pédron 
599f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
600f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
601f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
602f2044a30SJean-Sébastien Pédron 
603f2044a30SJean-Sébastien Pédron void
604f2044a30SJean-Sébastien Pédron debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
605f2044a30SJean-Sébastien Pédron {
606f2044a30SJean-Sébastien Pédron 
607f2044a30SJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
608f2044a30SJean-Sébastien Pédron 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
609f2044a30SJean-Sébastien Pédron }
610f2044a30SJean-Sébastien Pédron 
611f2044a30SJean-Sébastien Pédron 
6120fce2dc1SBjoern A. Zeeb static ssize_t
6130fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
6140fce2dc1SBjoern A. Zeeb {
6150fce2dc1SBjoern A. Zeeb 	struct debugfs_blob_wrapper *blob;
6160fce2dc1SBjoern A. Zeeb 
6170fce2dc1SBjoern A. Zeeb 	blob = filp->private_data;
6180fce2dc1SBjoern A. Zeeb 	if (blob == NULL)
6190fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6200fce2dc1SBjoern A. Zeeb 	if (blob->size == 0 || blob->data == NULL)
6210fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6220fce2dc1SBjoern A. Zeeb 
6230fce2dc1SBjoern A. Zeeb 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
6240fce2dc1SBjoern A. Zeeb }
6250fce2dc1SBjoern A. Zeeb 
6260fce2dc1SBjoern A. Zeeb static int
6270fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
6280fce2dc1SBjoern A. Zeeb {
629976aa07aSJean-Sébastien Pédron 
6300fce2dc1SBjoern A. Zeeb 	return (simple_open(inode, filp));
6310fce2dc1SBjoern A. Zeeb }
6320fce2dc1SBjoern A. Zeeb 
6330fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
6340fce2dc1SBjoern A. Zeeb 	.owner = THIS_MODULE,
6350fce2dc1SBjoern A. Zeeb 	.open = fops_blob_open,
6360fce2dc1SBjoern A. Zeeb 	.read = fops_blob_read,
6370fce2dc1SBjoern A. Zeeb 	.llseek = no_llseek
6380fce2dc1SBjoern A. Zeeb };
6390fce2dc1SBjoern A. Zeeb 
6400fce2dc1SBjoern A. Zeeb struct dentry *
6410fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
6420fce2dc1SBjoern A. Zeeb     struct debugfs_blob_wrapper *value)
6430fce2dc1SBjoern A. Zeeb {
6440fce2dc1SBjoern A. Zeeb 	/* Blobs are read-only. */
6450fce2dc1SBjoern A. Zeeb 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
6460fce2dc1SBjoern A. Zeeb }
6470fce2dc1SBjoern A. Zeeb 
6480fce2dc1SBjoern A. Zeeb 
649f697b943SJake Freeland static int
650f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
6513f6cab07SMatt Macy {
6523f6cab07SMatt Macy 
6533f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
65446888dedSMark Johnston 
65546888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
65646888dedSMark Johnston 
6573f6cab07SMatt Macy 	return (0);
6583f6cab07SMatt Macy }
6593f6cab07SMatt Macy 
6603f6cab07SMatt Macy static int
661f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
6623f6cab07SMatt Macy {
663976aa07aSJean-Sébastien Pédron 
6643f6cab07SMatt Macy 	return (0);
6653f6cab07SMatt Macy }
6663f6cab07SMatt Macy 
667f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
66803f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
669