xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision a04aa80e773a4bfdc4e72bab85d6e16f0083745e)
13f6cab07SMatt Macy /*-
23f6cab07SMatt Macy  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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/cdefs.h>
303f6cab07SMatt Macy __FBSDID("$FreeBSD$");
313f6cab07SMatt Macy 
323f6cab07SMatt Macy #include <sys/param.h>
333f6cab07SMatt Macy #include <sys/systm.h>
343f6cab07SMatt Macy #include <sys/queue.h>
353f6cab07SMatt Macy #include <sys/blist.h>
363f6cab07SMatt Macy #include <sys/conf.h>
373f6cab07SMatt Macy #include <sys/exec.h>
383f6cab07SMatt Macy #include <sys/filedesc.h>
393f6cab07SMatt Macy #include <sys/kernel.h>
403f6cab07SMatt Macy #include <sys/linker.h>
413f6cab07SMatt Macy #include <sys/malloc.h>
423f6cab07SMatt Macy #include <sys/mount.h>
433f6cab07SMatt Macy #include <sys/mutex.h>
443f6cab07SMatt Macy #include <sys/proc.h>
453f6cab07SMatt Macy #include <sys/resourcevar.h>
463f6cab07SMatt Macy #include <sys/sbuf.h>
473f6cab07SMatt Macy #include <sys/smp.h>
483f6cab07SMatt Macy #include <sys/socket.h>
493f6cab07SMatt Macy #include <sys/vnode.h>
503f6cab07SMatt Macy #include <sys/bus.h>
513f6cab07SMatt Macy #include <sys/pciio.h>
523f6cab07SMatt Macy 
533f6cab07SMatt Macy #include <dev/pci/pcivar.h>
543f6cab07SMatt Macy #include <dev/pci/pcireg.h>
553f6cab07SMatt Macy 
563f6cab07SMatt Macy #include <net/if.h>
573f6cab07SMatt Macy 
583f6cab07SMatt Macy #include <vm/vm.h>
593f6cab07SMatt Macy #include <vm/pmap.h>
603f6cab07SMatt Macy #include <vm/vm_map.h>
613f6cab07SMatt Macy #include <vm/vm_param.h>
623f6cab07SMatt Macy #include <vm/vm_object.h>
633f6cab07SMatt Macy #include <vm/swap_pager.h>
643f6cab07SMatt Macy 
653f6cab07SMatt Macy #include <machine/bus.h>
663f6cab07SMatt Macy 
673f6cab07SMatt Macy #include <compat/linux/linux_ioctl.h>
683f6cab07SMatt Macy #include <compat/linux/linux_mib.h>
693f6cab07SMatt Macy #include <compat/linux/linux_util.h>
703f6cab07SMatt Macy #include <fs/pseudofs/pseudofs.h>
713f6cab07SMatt Macy 
72f2044a30SJean-Sébastien Pédron #include <asm/atomic.h>
733f6cab07SMatt Macy #include <linux/compat.h>
74f697b943SJake Freeland #include <linux/debugfs.h>
75f697b943SJake Freeland #include <linux/fs.h>
763f6cab07SMatt Macy 
773f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
783f6cab07SMatt Macy 
793f6cab07SMatt Macy static struct pfs_node *debugfs_root;
803f6cab07SMatt Macy 
813f6cab07SMatt Macy #define DM_SYMLINK 0x1
823f6cab07SMatt Macy #define DM_DIR 0x2
833f6cab07SMatt Macy #define DM_FILE 0x3
843f6cab07SMatt Macy 
853f6cab07SMatt Macy struct dentry_meta {
863f6cab07SMatt Macy 	struct dentry dm_dnode;
873f6cab07SMatt Macy 	const struct file_operations *dm_fops;
883f6cab07SMatt Macy 	void *dm_data;
893f6cab07SMatt Macy 	umode_t dm_mode;
903f6cab07SMatt Macy 	int dm_type;
913f6cab07SMatt Macy };
923f6cab07SMatt Macy 
933f6cab07SMatt Macy static int
943f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
953f6cab07SMatt Macy {
963f6cab07SMatt Macy 	struct dentry_meta *dm;
973f6cab07SMatt Macy 
983f6cab07SMatt Macy 	dm = pn->pn_data;
993f6cab07SMatt Macy 
1003f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
1013f6cab07SMatt Macy 	return (0);
1023f6cab07SMatt Macy }
1033f6cab07SMatt Macy 
1043f6cab07SMatt Macy static int
1053f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1063f6cab07SMatt Macy {
1073f6cab07SMatt Macy 	struct dentry_meta *dm;
1083f6cab07SMatt Macy 
1093f6cab07SMatt Macy 	dm = pn->pn_data;
1103f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1113f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1123f6cab07SMatt Macy 
1133f6cab07SMatt Macy 	free(dm, M_DFSINT);
1143f6cab07SMatt Macy 	return (0);
1153f6cab07SMatt Macy }
1163f6cab07SMatt Macy 
1173f6cab07SMatt Macy static int
1183f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1193f6cab07SMatt Macy {
1203f6cab07SMatt Macy 	struct dentry_meta *d;
12188a29d89SHans Petter Selasky 	struct linux_file lf = {};
1223f6cab07SMatt Macy 	struct vnode vn;
123f697b943SJake Freeland 	char *buf;
1243f6cab07SMatt Macy 	int rc;
125f697b943SJake Freeland 	off_t off = 0;
1263f6cab07SMatt Macy 
1273f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1283f6cab07SMatt Macy 		return (rc);
129f697b943SJake Freeland 
130f697b943SJake Freeland 	d = pn->pn_data;
1313f6cab07SMatt Macy 	vn.v_data = d->dm_data;
132f697b943SJake Freeland 
1333f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1343f6cab07SMatt Macy 	if (rc < 0) {
1353f6cab07SMatt Macy #ifdef INVARIANTS
1363f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1373f6cab07SMatt Macy #endif
1383f6cab07SMatt Macy 		return (-rc);
1393f6cab07SMatt Macy 	}
140f697b943SJake Freeland 
14168ec2949SHans Petter Selasky 	rc = -ENODEV;
142f697b943SJake Freeland 	if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
143f697b943SJake Freeland 		rc = -ENOMEM;
144f697b943SJake Freeland 		buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
145f697b943SJake Freeland 		if (buf != NULL) {
146f697b943SJake Freeland 			rc = d->dm_fops->read(&lf, buf, sb->s_size, &off);
147f697b943SJake Freeland 			if (rc > 0)
148f697b943SJake Freeland 				sbuf_bcpy(sb, buf, strlen(buf));
149f697b943SJake Freeland 
150f697b943SJake Freeland 			free(buf, M_DFSINT);
15103f1cf9fSJohannes Lundberg 		}
152f697b943SJake Freeland 	} else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
153f697b943SJake Freeland 		sbuf_finish(sb);
154f697b943SJake Freeland 		rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
155f697b943SJake Freeland 	}
156f697b943SJake Freeland 
1573f6cab07SMatt Macy 	if (d->dm_fops->release)
1583f6cab07SMatt Macy 		d->dm_fops->release(&vn, &lf);
1593f6cab07SMatt Macy 	else
1603f6cab07SMatt Macy 		single_release(&vn, &lf);
1613f6cab07SMatt Macy 
1623f6cab07SMatt Macy 	if (rc < 0) {
1633f6cab07SMatt Macy #ifdef INVARIANTS
1643f6cab07SMatt Macy 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
1653f6cab07SMatt Macy #endif
1663f6cab07SMatt Macy 		return (-rc);
1673f6cab07SMatt Macy 	}
1683f6cab07SMatt Macy 	return (0);
1693f6cab07SMatt Macy }
1703f6cab07SMatt Macy 
1713f6cab07SMatt Macy static int
1723f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1733f6cab07SMatt Macy {
1743f6cab07SMatt Macy 	struct dentry_meta *dm;
1753f6cab07SMatt Macy 
1763f6cab07SMatt Macy 	dm = pn->pn_data;
1773f6cab07SMatt Macy 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
1783f6cab07SMatt Macy 	return (0);
1793f6cab07SMatt Macy }
1803f6cab07SMatt Macy 
1813f6cab07SMatt Macy struct dentry *
1823f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1833f6cab07SMatt Macy     struct dentry *parent, void *data,
1843f6cab07SMatt Macy     const struct file_operations *fops)
1853f6cab07SMatt Macy {
1863f6cab07SMatt Macy 	struct dentry_meta *dm;
1873f6cab07SMatt Macy 	struct dentry *dnode;
1883f6cab07SMatt Macy 	struct pfs_node *pnode;
1893f6cab07SMatt Macy 	int flags;
1903f6cab07SMatt Macy 
1913f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1923f6cab07SMatt Macy 	if (dm == NULL)
1933f6cab07SMatt Macy 		return (NULL);
1943f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
1953f6cab07SMatt Macy 	dm->dm_fops = fops;
1963f6cab07SMatt Macy 	dm->dm_data = data;
1973f6cab07SMatt Macy 	dm->dm_mode = mode;
1983f6cab07SMatt Macy 	dm->dm_type = DM_FILE;
1993f6cab07SMatt Macy 	if (parent != NULL)
2003f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2013f6cab07SMatt Macy 	else
2023f6cab07SMatt Macy 		pnode = debugfs_root;
2033f6cab07SMatt Macy 
2043f6cab07SMatt Macy 	flags = fops->write ? PFS_RDWR : PFS_RD;
2053f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2063f6cab07SMatt Macy 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2073f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2083f6cab07SMatt Macy 		free(dm, M_DFSINT);
2093f6cab07SMatt Macy 		return (NULL);
2103f6cab07SMatt Macy 	}
2113f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2123f6cab07SMatt Macy 
2133f6cab07SMatt Macy 	return (dnode);
2143f6cab07SMatt Macy }
2153f6cab07SMatt Macy 
216*a04aa80eSJean-Sébastien Pédron struct dentry *
217*a04aa80eSJean-Sébastien Pédron debugfs_create_file_size(const char *name, umode_t mode,
218*a04aa80eSJean-Sébastien Pédron     struct dentry *parent, void *data,
219*a04aa80eSJean-Sébastien Pédron     const struct file_operations *fops,
220*a04aa80eSJean-Sébastien Pédron     loff_t file_size __unused)
221*a04aa80eSJean-Sébastien Pédron {
222*a04aa80eSJean-Sébastien Pédron 
223*a04aa80eSJean-Sébastien Pédron 	return debugfs_create_file(name, mode, parent, data, fops);
224*a04aa80eSJean-Sébastien Pédron }
225*a04aa80eSJean-Sébastien Pédron 
226f697b943SJake Freeland /*
227f697b943SJake Freeland  * NOTE: Files created with the _unsafe moniker will not be protected from
228f697b943SJake Freeland  * debugfs core file removals. It is the responsibility of @fops to protect
229f697b943SJake Freeland  * its file using debugfs_file_get() and debugfs_file_put().
230f697b943SJake Freeland  *
231f697b943SJake Freeland  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
232f697b943SJake Freeland  * of writing. Therefore there is no difference between functions with _unsafe
233f697b943SJake Freeland  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
234f697b943SJake Freeland  * exist only for Linux compatibility.
235f697b943SJake Freeland  */
236f697b943SJake Freeland struct dentry *
237f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
238f697b943SJake Freeland     struct dentry *parent, void *data,
239f697b943SJake Freeland     const struct file_operations *fops)
240f697b943SJake Freeland {
241*a04aa80eSJean-Sébastien Pédron 
242f697b943SJake Freeland 	return (debugfs_create_file(name, mode, parent, data, fops));
243f697b943SJake Freeland }
244f697b943SJake Freeland 
245f697b943SJake Freeland struct dentry *
246f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
247f697b943SJake Freeland     struct dentry *parent, void *data,
248f697b943SJake Freeland     const struct file_operations *fops,
249f697b943SJake Freeland     const struct file_operations *fops_ro,
250f697b943SJake Freeland     const struct file_operations *fops_wo)
251f697b943SJake Freeland {
252f697b943SJake Freeland 	umode_t read = mode & S_IRUGO;
253f697b943SJake Freeland 	umode_t write = mode & S_IWUGO;
254f697b943SJake Freeland 
255f697b943SJake Freeland 	if (read && !write)
256f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
257f697b943SJake Freeland 
258f697b943SJake Freeland 	if (write && !read)
259f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
260f697b943SJake Freeland 
261f697b943SJake Freeland 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
262f697b943SJake Freeland }
263f697b943SJake Freeland 
2643f6cab07SMatt Macy struct dentry *
2653f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2663f6cab07SMatt Macy {
2673f6cab07SMatt Macy 	struct dentry_meta *dm;
2683f6cab07SMatt Macy 	struct dentry *dnode;
2693f6cab07SMatt Macy 	struct pfs_node *pnode;
2703f6cab07SMatt Macy 
2713f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2723f6cab07SMatt Macy 	if (dm == NULL)
2733f6cab07SMatt Macy 		return (NULL);
2743f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2753f6cab07SMatt Macy 	dm->dm_mode = 0700;
2763f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2773f6cab07SMatt Macy 	if (parent != NULL)
2783f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2793f6cab07SMatt Macy 	else
2803f6cab07SMatt Macy 		pnode = debugfs_root;
2813f6cab07SMatt Macy 
2823f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2833f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2843f6cab07SMatt Macy 		free(dm, M_DFSINT);
2853f6cab07SMatt Macy 		return (NULL);
2863f6cab07SMatt Macy 	}
2873f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2883f6cab07SMatt Macy 	return (dnode);
2893f6cab07SMatt Macy }
2903f6cab07SMatt Macy 
2913f6cab07SMatt Macy struct dentry *
2923f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2933f6cab07SMatt Macy     const char *dest)
2943f6cab07SMatt Macy {
2953f6cab07SMatt Macy 	struct dentry_meta *dm;
2963f6cab07SMatt Macy 	struct dentry *dnode;
2973f6cab07SMatt Macy 	struct pfs_node *pnode;
2983f6cab07SMatt Macy 	void *data;
2993f6cab07SMatt Macy 
3003f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
3013f6cab07SMatt Macy 	if (data == NULL)
3023f6cab07SMatt Macy 		return (NULL);
3033f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
3043f6cab07SMatt Macy 	if (dm == NULL)
3053f6cab07SMatt Macy 		goto fail1;
3063f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
3073f6cab07SMatt Macy 	dm->dm_mode = 0700;
3083f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
3093f6cab07SMatt Macy 	dm->dm_data = data;
3103f6cab07SMatt Macy 	if (parent != NULL)
3113f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
3123f6cab07SMatt Macy 	else
3133f6cab07SMatt Macy 		pnode = debugfs_root;
3143f6cab07SMatt Macy 
3153f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3163f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
3173f6cab07SMatt Macy 		goto fail;
3183f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
3193f6cab07SMatt Macy 	return (dnode);
3203f6cab07SMatt Macy  fail:
3213f6cab07SMatt Macy 	free(dm, M_DFSINT);
3223f6cab07SMatt Macy  fail1:
3233f6cab07SMatt Macy 	free(data, M_DFSINT);
3243f6cab07SMatt Macy 	return (NULL);
3253f6cab07SMatt Macy }
3263f6cab07SMatt Macy 
3273f6cab07SMatt Macy void
3283f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3293f6cab07SMatt Macy {
3303f6cab07SMatt Macy 	if (dnode == NULL)
3313f6cab07SMatt Macy 		return;
3323f6cab07SMatt Macy 
3333f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3343f6cab07SMatt Macy }
3353f6cab07SMatt Macy 
3363f6cab07SMatt Macy void
3373f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3383f6cab07SMatt Macy {
3393f6cab07SMatt Macy 	if (dnode == NULL)
3403f6cab07SMatt Macy 		return;
3413f6cab07SMatt Macy 
3423f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3433f6cab07SMatt Macy }
3443f6cab07SMatt Macy 
3453f6cab07SMatt Macy static int
346f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
347f697b943SJake Freeland {
348f697b943SJake Freeland 	bool *bval = data;
349f697b943SJake Freeland 
350f697b943SJake Freeland 	if (*bval)
351f697b943SJake Freeland 		*ullval = 1;
352f697b943SJake Freeland 	else
353f697b943SJake Freeland 		*ullval = 0;
354f697b943SJake Freeland 
355f697b943SJake Freeland 	return (0);
356f697b943SJake Freeland }
357f697b943SJake Freeland 
358f697b943SJake Freeland static int
359f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
360f697b943SJake Freeland {
361f697b943SJake Freeland 	bool *bval = data;
362f697b943SJake Freeland 
363f697b943SJake Freeland 	if (ullval)
364f697b943SJake Freeland 		*bval = 1;
365f697b943SJake Freeland 	else
366f697b943SJake Freeland 		*bval = 0;
367f697b943SJake Freeland 
368f697b943SJake Freeland 	return (0);
369f697b943SJake Freeland }
370f697b943SJake Freeland 
371f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
372f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
373f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
374f697b943SJake Freeland 
375f697b943SJake Freeland void
376f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
377f697b943SJake Freeland {
378976aa07aSJean-Sébastien Pédron 
379f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
380f697b943SJake Freeland 	    &fops_bool_ro, &fops_bool_wo);
381f697b943SJake Freeland }
382f697b943SJake Freeland 
3830fce2dc1SBjoern A. Zeeb 
3840fce2dc1SBjoern A. Zeeb static int
3850fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
3860fce2dc1SBjoern A. Zeeb {
3870fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3880fce2dc1SBjoern A. Zeeb 	*value = *u8data;
3890fce2dc1SBjoern A. Zeeb 	return (0);
3900fce2dc1SBjoern A. Zeeb }
3910fce2dc1SBjoern A. Zeeb 
3920fce2dc1SBjoern A. Zeeb static int
3930fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
3940fce2dc1SBjoern A. Zeeb {
3950fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3960fce2dc1SBjoern A. Zeeb 	*u8data = (uint8_t)value;
3970fce2dc1SBjoern A. Zeeb 	return (0);
3980fce2dc1SBjoern A. Zeeb }
3990fce2dc1SBjoern A. Zeeb 
4000fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
4010fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
4020fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
4030fce2dc1SBjoern A. Zeeb 
4040fce2dc1SBjoern A. Zeeb void
4050fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
4060fce2dc1SBjoern A. Zeeb {
407976aa07aSJean-Sébastien Pédron 
4080fce2dc1SBjoern A. Zeeb 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
4090fce2dc1SBjoern A. Zeeb 	    &fops_u8_ro, &fops_u8_wo);
4100fce2dc1SBjoern A. Zeeb }
4110fce2dc1SBjoern A. Zeeb 
412976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
413976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
414976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
415976aa07aSJean-Sébastien Pédron 
416976aa07aSJean-Sébastien Pédron void
417976aa07aSJean-Sébastien Pédron debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
418976aa07aSJean-Sébastien Pédron {
419976aa07aSJean-Sébastien Pédron 
420976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
421976aa07aSJean-Sébastien Pédron 	    &fops_x8_ro, &fops_x8_wo);
422976aa07aSJean-Sébastien Pédron }
423976aa07aSJean-Sébastien Pédron 
424976aa07aSJean-Sébastien Pédron 
425976aa07aSJean-Sébastien Pédron static int
426976aa07aSJean-Sébastien Pédron debugfs_u16_get(void *data, uint64_t *value)
427976aa07aSJean-Sébastien Pédron {
428976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
429976aa07aSJean-Sébastien Pédron 	*value = *u16data;
430976aa07aSJean-Sébastien Pédron 	return (0);
431976aa07aSJean-Sébastien Pédron }
432976aa07aSJean-Sébastien Pédron 
433976aa07aSJean-Sébastien Pédron static int
434976aa07aSJean-Sébastien Pédron debugfs_u16_set(void *data, uint64_t value)
435976aa07aSJean-Sébastien Pédron {
436976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
437976aa07aSJean-Sébastien Pédron 	*u16data = (uint16_t)value;
438976aa07aSJean-Sébastien Pédron 	return (0);
439976aa07aSJean-Sébastien Pédron }
440976aa07aSJean-Sébastien Pédron 
441976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
442976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
443976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
444976aa07aSJean-Sébastien Pédron 
445976aa07aSJean-Sébastien Pédron void
446976aa07aSJean-Sébastien Pédron debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
447976aa07aSJean-Sébastien Pédron {
448976aa07aSJean-Sébastien Pédron 
449976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
450976aa07aSJean-Sébastien Pédron 	    &fops_u16_ro, &fops_u16_wo);
451976aa07aSJean-Sébastien Pédron }
452976aa07aSJean-Sébastien Pédron 
453976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
454976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
455976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
456976aa07aSJean-Sébastien Pédron 
457976aa07aSJean-Sébastien Pédron void
458976aa07aSJean-Sébastien Pédron debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
459976aa07aSJean-Sébastien Pédron {
460976aa07aSJean-Sébastien Pédron 
461976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
462976aa07aSJean-Sébastien Pédron 	    &fops_x16_ro, &fops_x16_wo);
463976aa07aSJean-Sébastien Pédron }
464976aa07aSJean-Sébastien Pédron 
465976aa07aSJean-Sébastien Pédron 
466976aa07aSJean-Sébastien Pédron static int
467976aa07aSJean-Sébastien Pédron debugfs_u32_get(void *data, uint64_t *value)
468976aa07aSJean-Sébastien Pédron {
469976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
470976aa07aSJean-Sébastien Pédron 	*value = *u32data;
471976aa07aSJean-Sébastien Pédron 	return (0);
472976aa07aSJean-Sébastien Pédron }
473976aa07aSJean-Sébastien Pédron 
474976aa07aSJean-Sébastien Pédron static int
475976aa07aSJean-Sébastien Pédron debugfs_u32_set(void *data, uint64_t value)
476976aa07aSJean-Sébastien Pédron {
477976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
478976aa07aSJean-Sébastien Pédron 	*u32data = (uint32_t)value;
479976aa07aSJean-Sébastien Pédron 	return (0);
480976aa07aSJean-Sébastien Pédron }
481976aa07aSJean-Sébastien Pédron 
482976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
483976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
484976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
485976aa07aSJean-Sébastien Pédron 
486976aa07aSJean-Sébastien Pédron void
487976aa07aSJean-Sébastien Pédron debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
488976aa07aSJean-Sébastien Pédron {
489976aa07aSJean-Sébastien Pédron 
490976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
491976aa07aSJean-Sébastien Pédron 	    &fops_u32_ro, &fops_u32_wo);
492976aa07aSJean-Sébastien Pédron }
493976aa07aSJean-Sébastien Pédron 
494976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
495976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
496976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
497976aa07aSJean-Sébastien Pédron 
498976aa07aSJean-Sébastien Pédron void
499976aa07aSJean-Sébastien Pédron debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
500976aa07aSJean-Sébastien Pédron {
501976aa07aSJean-Sébastien Pédron 
502976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
503976aa07aSJean-Sébastien Pédron 	    &fops_x32_ro, &fops_x32_wo);
504976aa07aSJean-Sébastien Pédron }
505976aa07aSJean-Sébastien Pédron 
506976aa07aSJean-Sébastien Pédron 
507976aa07aSJean-Sébastien Pédron static int
508976aa07aSJean-Sébastien Pédron debugfs_u64_get(void *data, uint64_t *value)
509976aa07aSJean-Sébastien Pédron {
510976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
511976aa07aSJean-Sébastien Pédron 	*value = *u64data;
512976aa07aSJean-Sébastien Pédron 	return (0);
513976aa07aSJean-Sébastien Pédron }
514976aa07aSJean-Sébastien Pédron 
515976aa07aSJean-Sébastien Pédron static int
516976aa07aSJean-Sébastien Pédron debugfs_u64_set(void *data, uint64_t value)
517976aa07aSJean-Sébastien Pédron {
518976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
519976aa07aSJean-Sébastien Pédron 	*u64data = (uint64_t)value;
520976aa07aSJean-Sébastien Pédron 	return (0);
521976aa07aSJean-Sébastien Pédron }
522976aa07aSJean-Sébastien Pédron 
523976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
524976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
525976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
526976aa07aSJean-Sébastien Pédron 
527976aa07aSJean-Sébastien Pédron void
528976aa07aSJean-Sébastien Pédron debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
529976aa07aSJean-Sébastien Pédron {
530976aa07aSJean-Sébastien Pédron 
531976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
532976aa07aSJean-Sébastien Pédron 	    &fops_u64_ro, &fops_u64_wo);
533976aa07aSJean-Sébastien Pédron }
534976aa07aSJean-Sébastien Pédron 
535976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
536976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
537976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
538976aa07aSJean-Sébastien Pédron 
539976aa07aSJean-Sébastien Pédron void
540976aa07aSJean-Sébastien Pédron debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
541976aa07aSJean-Sébastien Pédron {
542976aa07aSJean-Sébastien Pédron 
543976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
544976aa07aSJean-Sébastien Pédron 	    &fops_x64_ro, &fops_x64_wo);
545976aa07aSJean-Sébastien Pédron }
546976aa07aSJean-Sébastien Pédron 
5470fce2dc1SBjoern A. Zeeb 
548f697b943SJake Freeland static int
549f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
550f697b943SJake Freeland {
551f697b943SJake Freeland 	uint64_t *uldata = data;
552f697b943SJake Freeland 	*value = *uldata;
553f697b943SJake Freeland 	return (0);
554f697b943SJake Freeland }
555f697b943SJake Freeland 
556f697b943SJake Freeland static int
557f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
558f697b943SJake Freeland {
559f697b943SJake Freeland 	uint64_t *uldata = data;
560f697b943SJake Freeland 	*uldata = value;
561f697b943SJake Freeland 	return (0);
562f697b943SJake Freeland }
563f697b943SJake Freeland 
564f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
565f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
566f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
567f697b943SJake Freeland 
568f697b943SJake Freeland void
569f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
570f697b943SJake Freeland {
571976aa07aSJean-Sébastien Pédron 
572f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
573f697b943SJake Freeland 	    &fops_ulong_ro, &fops_ulong_wo);
574f697b943SJake Freeland }
575f697b943SJake Freeland 
5760fce2dc1SBjoern A. Zeeb 
577f2044a30SJean-Sébastien Pédron static int
578f2044a30SJean-Sébastien Pédron debugfs_atomic_t_get(void *data, uint64_t *value)
579f2044a30SJean-Sébastien Pédron {
580f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
581f2044a30SJean-Sébastien Pédron 	*value = atomic_read(atomic_data);
582f2044a30SJean-Sébastien Pédron 	return (0);
583f2044a30SJean-Sébastien Pédron }
584f2044a30SJean-Sébastien Pédron 
585f2044a30SJean-Sébastien Pédron static int
586f2044a30SJean-Sébastien Pédron debugfs_atomic_t_set(void *data, uint64_t value)
587f2044a30SJean-Sébastien Pédron {
588f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
589f2044a30SJean-Sébastien Pédron 	atomic_set(atomic_data, (int)value);
590f2044a30SJean-Sébastien Pédron 	return (0);
591f2044a30SJean-Sébastien Pédron }
592f2044a30SJean-Sébastien Pédron 
593f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
594f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
595f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
596f2044a30SJean-Sébastien Pédron 
597f2044a30SJean-Sébastien Pédron void
598f2044a30SJean-Sébastien Pédron debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
599f2044a30SJean-Sébastien Pédron {
600f2044a30SJean-Sébastien Pédron 
601f2044a30SJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
602f2044a30SJean-Sébastien Pédron 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
603f2044a30SJean-Sébastien Pédron }
604f2044a30SJean-Sébastien Pédron 
605f2044a30SJean-Sébastien Pédron 
6060fce2dc1SBjoern A. Zeeb static ssize_t
6070fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
6080fce2dc1SBjoern A. Zeeb {
6090fce2dc1SBjoern A. Zeeb 	struct debugfs_blob_wrapper *blob;
6100fce2dc1SBjoern A. Zeeb 
6110fce2dc1SBjoern A. Zeeb 	blob = filp->private_data;
6120fce2dc1SBjoern A. Zeeb 	if (blob == NULL)
6130fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6140fce2dc1SBjoern A. Zeeb 	if (blob->size == 0 || blob->data == NULL)
6150fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6160fce2dc1SBjoern A. Zeeb 
6170fce2dc1SBjoern A. Zeeb 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
6180fce2dc1SBjoern A. Zeeb }
6190fce2dc1SBjoern A. Zeeb 
6200fce2dc1SBjoern A. Zeeb static int
6210fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
6220fce2dc1SBjoern A. Zeeb {
623976aa07aSJean-Sébastien Pédron 
6240fce2dc1SBjoern A. Zeeb 	return (simple_open(inode, filp));
6250fce2dc1SBjoern A. Zeeb }
6260fce2dc1SBjoern A. Zeeb 
6270fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
6280fce2dc1SBjoern A. Zeeb 	.owner = THIS_MODULE,
6290fce2dc1SBjoern A. Zeeb 	.open = fops_blob_open,
6300fce2dc1SBjoern A. Zeeb 	.read = fops_blob_read,
6310fce2dc1SBjoern A. Zeeb 	.llseek = no_llseek
6320fce2dc1SBjoern A. Zeeb };
6330fce2dc1SBjoern A. Zeeb 
6340fce2dc1SBjoern A. Zeeb struct dentry *
6350fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
6360fce2dc1SBjoern A. Zeeb     struct debugfs_blob_wrapper *value)
6370fce2dc1SBjoern A. Zeeb {
6380fce2dc1SBjoern A. Zeeb 	/* Blobs are read-only. */
6390fce2dc1SBjoern A. Zeeb 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
6400fce2dc1SBjoern A. Zeeb }
6410fce2dc1SBjoern A. Zeeb 
6420fce2dc1SBjoern A. Zeeb 
643f697b943SJake Freeland static int
644f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
6453f6cab07SMatt Macy {
6463f6cab07SMatt Macy 
6473f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
64846888dedSMark Johnston 
64946888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
65046888dedSMark Johnston 
6513f6cab07SMatt Macy 	return (0);
6523f6cab07SMatt Macy }
6533f6cab07SMatt Macy 
6543f6cab07SMatt Macy static int
655f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
6563f6cab07SMatt Macy {
657976aa07aSJean-Sébastien Pédron 
6583f6cab07SMatt Macy 	return (0);
6593f6cab07SMatt Macy }
6603f6cab07SMatt Macy 
661f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
66203f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
663