xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision f2044a3030fb2a657e59dee4b7e5865acff936bd)
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 
72*f2044a30SJean-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 
216f697b943SJake Freeland /*
217f697b943SJake Freeland  * NOTE: Files created with the _unsafe moniker will not be protected from
218f697b943SJake Freeland  * debugfs core file removals. It is the responsibility of @fops to protect
219f697b943SJake Freeland  * its file using debugfs_file_get() and debugfs_file_put().
220f697b943SJake Freeland  *
221f697b943SJake Freeland  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
222f697b943SJake Freeland  * of writing. Therefore there is no difference between functions with _unsafe
223f697b943SJake Freeland  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
224f697b943SJake Freeland  * exist only for Linux compatibility.
225f697b943SJake Freeland  */
226f697b943SJake Freeland struct dentry *
227f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
228f697b943SJake Freeland     struct dentry *parent, void *data,
229f697b943SJake Freeland     const struct file_operations *fops)
230f697b943SJake Freeland {
231f697b943SJake Freeland 	return (debugfs_create_file(name, mode, parent, data, fops));
232f697b943SJake Freeland }
233f697b943SJake Freeland 
234f697b943SJake Freeland struct dentry *
235f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
236f697b943SJake Freeland     struct dentry *parent, void *data,
237f697b943SJake Freeland     const struct file_operations *fops,
238f697b943SJake Freeland     const struct file_operations *fops_ro,
239f697b943SJake Freeland     const struct file_operations *fops_wo)
240f697b943SJake Freeland {
241f697b943SJake Freeland 	umode_t read = mode & S_IRUGO;
242f697b943SJake Freeland 	umode_t write = mode & S_IWUGO;
243f697b943SJake Freeland 
244f697b943SJake Freeland 	if (read && !write)
245f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
246f697b943SJake Freeland 
247f697b943SJake Freeland 	if (write && !read)
248f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
249f697b943SJake Freeland 
250f697b943SJake Freeland 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
251f697b943SJake Freeland }
252f697b943SJake Freeland 
2533f6cab07SMatt Macy struct dentry *
2543f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2553f6cab07SMatt Macy {
2563f6cab07SMatt Macy 	struct dentry_meta *dm;
2573f6cab07SMatt Macy 	struct dentry *dnode;
2583f6cab07SMatt Macy 	struct pfs_node *pnode;
2593f6cab07SMatt Macy 
2603f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2613f6cab07SMatt Macy 	if (dm == NULL)
2623f6cab07SMatt Macy 		return (NULL);
2633f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2643f6cab07SMatt Macy 	dm->dm_mode = 0700;
2653f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2663f6cab07SMatt Macy 	if (parent != NULL)
2673f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2683f6cab07SMatt Macy 	else
2693f6cab07SMatt Macy 		pnode = debugfs_root;
2703f6cab07SMatt Macy 
2713f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2723f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2733f6cab07SMatt Macy 		free(dm, M_DFSINT);
2743f6cab07SMatt Macy 		return (NULL);
2753f6cab07SMatt Macy 	}
2763f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2773f6cab07SMatt Macy 	return (dnode);
2783f6cab07SMatt Macy }
2793f6cab07SMatt Macy 
2803f6cab07SMatt Macy struct dentry *
2813f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2823f6cab07SMatt Macy     const char *dest)
2833f6cab07SMatt Macy {
2843f6cab07SMatt Macy 	struct dentry_meta *dm;
2853f6cab07SMatt Macy 	struct dentry *dnode;
2863f6cab07SMatt Macy 	struct pfs_node *pnode;
2873f6cab07SMatt Macy 	void *data;
2883f6cab07SMatt Macy 
2893f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
2903f6cab07SMatt Macy 	if (data == NULL)
2913f6cab07SMatt Macy 		return (NULL);
2923f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2933f6cab07SMatt Macy 	if (dm == NULL)
2943f6cab07SMatt Macy 		goto fail1;
2953f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2963f6cab07SMatt Macy 	dm->dm_mode = 0700;
2973f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
2983f6cab07SMatt Macy 	dm->dm_data = data;
2993f6cab07SMatt Macy 	if (parent != NULL)
3003f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
3013f6cab07SMatt Macy 	else
3023f6cab07SMatt Macy 		pnode = debugfs_root;
3033f6cab07SMatt Macy 
3043f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3053f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
3063f6cab07SMatt Macy 		goto fail;
3073f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
3083f6cab07SMatt Macy 	return (dnode);
3093f6cab07SMatt Macy  fail:
3103f6cab07SMatt Macy 	free(dm, M_DFSINT);
3113f6cab07SMatt Macy  fail1:
3123f6cab07SMatt Macy 	free(data, M_DFSINT);
3133f6cab07SMatt Macy 	return (NULL);
3143f6cab07SMatt Macy }
3153f6cab07SMatt Macy 
3163f6cab07SMatt Macy void
3173f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3183f6cab07SMatt Macy {
3193f6cab07SMatt Macy 	if (dnode == NULL)
3203f6cab07SMatt Macy 		return;
3213f6cab07SMatt Macy 
3223f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3233f6cab07SMatt Macy }
3243f6cab07SMatt Macy 
3253f6cab07SMatt Macy void
3263f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3273f6cab07SMatt Macy {
3283f6cab07SMatt Macy 	if (dnode == NULL)
3293f6cab07SMatt Macy 		return;
3303f6cab07SMatt Macy 
3313f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3323f6cab07SMatt Macy }
3333f6cab07SMatt Macy 
3343f6cab07SMatt Macy static int
335f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
336f697b943SJake Freeland {
337f697b943SJake Freeland 	bool *bval = data;
338f697b943SJake Freeland 
339f697b943SJake Freeland 	if (*bval)
340f697b943SJake Freeland 		*ullval = 1;
341f697b943SJake Freeland 	else
342f697b943SJake Freeland 		*ullval = 0;
343f697b943SJake Freeland 
344f697b943SJake Freeland 	return (0);
345f697b943SJake Freeland }
346f697b943SJake Freeland 
347f697b943SJake Freeland static int
348f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
349f697b943SJake Freeland {
350f697b943SJake Freeland 	bool *bval = data;
351f697b943SJake Freeland 
352f697b943SJake Freeland 	if (ullval)
353f697b943SJake Freeland 		*bval = 1;
354f697b943SJake Freeland 	else
355f697b943SJake Freeland 		*bval = 0;
356f697b943SJake Freeland 
357f697b943SJake Freeland 	return (0);
358f697b943SJake Freeland }
359f697b943SJake Freeland 
360f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
361f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
362f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
363f697b943SJake Freeland 
364f697b943SJake Freeland void
365f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
366f697b943SJake Freeland {
367f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
368f697b943SJake Freeland 	    &fops_bool_ro, &fops_bool_wo);
369f697b943SJake Freeland }
370f697b943SJake Freeland 
3710fce2dc1SBjoern A. Zeeb 
3720fce2dc1SBjoern A. Zeeb static int
3730fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
3740fce2dc1SBjoern A. Zeeb {
3750fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3760fce2dc1SBjoern A. Zeeb 	*value = *u8data;
3770fce2dc1SBjoern A. Zeeb 	return (0);
3780fce2dc1SBjoern A. Zeeb }
3790fce2dc1SBjoern A. Zeeb 
3800fce2dc1SBjoern A. Zeeb static int
3810fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
3820fce2dc1SBjoern A. Zeeb {
3830fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3840fce2dc1SBjoern A. Zeeb 	*u8data = (uint8_t)value;
3850fce2dc1SBjoern A. Zeeb 	return (0);
3860fce2dc1SBjoern A. Zeeb }
3870fce2dc1SBjoern A. Zeeb 
3880fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
3890fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
3900fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
3910fce2dc1SBjoern A. Zeeb 
3920fce2dc1SBjoern A. Zeeb void
3930fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
3940fce2dc1SBjoern A. Zeeb {
3950fce2dc1SBjoern A. Zeeb 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
3960fce2dc1SBjoern A. Zeeb 	    &fops_u8_ro, &fops_u8_wo);
3970fce2dc1SBjoern A. Zeeb }
3980fce2dc1SBjoern A. Zeeb 
3990fce2dc1SBjoern A. Zeeb 
400f697b943SJake Freeland static int
401f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
402f697b943SJake Freeland {
403f697b943SJake Freeland 	uint64_t *uldata = data;
404f697b943SJake Freeland 	*value = *uldata;
405f697b943SJake Freeland 	return (0);
406f697b943SJake Freeland }
407f697b943SJake Freeland 
408f697b943SJake Freeland static int
409f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
410f697b943SJake Freeland {
411f697b943SJake Freeland 	uint64_t *uldata = data;
412f697b943SJake Freeland 	*uldata = value;
413f697b943SJake Freeland 	return (0);
414f697b943SJake Freeland }
415f697b943SJake Freeland 
416f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
417f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
418f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
419f697b943SJake Freeland 
420f697b943SJake Freeland void
421f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
422f697b943SJake Freeland {
423f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
424f697b943SJake Freeland 	    &fops_ulong_ro, &fops_ulong_wo);
425f697b943SJake Freeland }
426f697b943SJake Freeland 
4270fce2dc1SBjoern A. Zeeb 
428*f2044a30SJean-Sébastien Pédron static int
429*f2044a30SJean-Sébastien Pédron debugfs_atomic_t_get(void *data, uint64_t *value)
430*f2044a30SJean-Sébastien Pédron {
431*f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
432*f2044a30SJean-Sébastien Pédron 	*value = atomic_read(atomic_data);
433*f2044a30SJean-Sébastien Pédron 	return (0);
434*f2044a30SJean-Sébastien Pédron }
435*f2044a30SJean-Sébastien Pédron 
436*f2044a30SJean-Sébastien Pédron static int
437*f2044a30SJean-Sébastien Pédron debugfs_atomic_t_set(void *data, uint64_t value)
438*f2044a30SJean-Sébastien Pédron {
439*f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
440*f2044a30SJean-Sébastien Pédron 	atomic_set(atomic_data, (int)value);
441*f2044a30SJean-Sébastien Pédron 	return (0);
442*f2044a30SJean-Sébastien Pédron }
443*f2044a30SJean-Sébastien Pédron 
444*f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
445*f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
446*f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
447*f2044a30SJean-Sébastien Pédron 
448*f2044a30SJean-Sébastien Pédron void
449*f2044a30SJean-Sébastien Pédron debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
450*f2044a30SJean-Sébastien Pédron {
451*f2044a30SJean-Sébastien Pédron 
452*f2044a30SJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
453*f2044a30SJean-Sébastien Pédron 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
454*f2044a30SJean-Sébastien Pédron }
455*f2044a30SJean-Sébastien Pédron 
456*f2044a30SJean-Sébastien Pédron 
4570fce2dc1SBjoern A. Zeeb static ssize_t
4580fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
4590fce2dc1SBjoern A. Zeeb {
4600fce2dc1SBjoern A. Zeeb 	struct debugfs_blob_wrapper *blob;
4610fce2dc1SBjoern A. Zeeb 
4620fce2dc1SBjoern A. Zeeb 	blob = filp->private_data;
4630fce2dc1SBjoern A. Zeeb 	if (blob == NULL)
4640fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
4650fce2dc1SBjoern A. Zeeb 	if (blob->size == 0 || blob->data == NULL)
4660fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
4670fce2dc1SBjoern A. Zeeb 
4680fce2dc1SBjoern A. Zeeb 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
4690fce2dc1SBjoern A. Zeeb }
4700fce2dc1SBjoern A. Zeeb 
4710fce2dc1SBjoern A. Zeeb static int
4720fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
4730fce2dc1SBjoern A. Zeeb {
4740fce2dc1SBjoern A. Zeeb 	return (simple_open(inode, filp));
4750fce2dc1SBjoern A. Zeeb }
4760fce2dc1SBjoern A. Zeeb 
4770fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
4780fce2dc1SBjoern A. Zeeb 	.owner = THIS_MODULE,
4790fce2dc1SBjoern A. Zeeb 	.open = fops_blob_open,
4800fce2dc1SBjoern A. Zeeb 	.read = fops_blob_read,
4810fce2dc1SBjoern A. Zeeb 	.llseek = no_llseek
4820fce2dc1SBjoern A. Zeeb };
4830fce2dc1SBjoern A. Zeeb 
4840fce2dc1SBjoern A. Zeeb struct dentry *
4850fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
4860fce2dc1SBjoern A. Zeeb     struct debugfs_blob_wrapper *value)
4870fce2dc1SBjoern A. Zeeb {
4880fce2dc1SBjoern A. Zeeb 	/* Blobs are read-only. */
4890fce2dc1SBjoern A. Zeeb 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
4900fce2dc1SBjoern A. Zeeb }
4910fce2dc1SBjoern A. Zeeb 
4920fce2dc1SBjoern A. Zeeb 
493f697b943SJake Freeland static int
494f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
4953f6cab07SMatt Macy {
4963f6cab07SMatt Macy 
4973f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
49846888dedSMark Johnston 
49946888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
50046888dedSMark Johnston 
5013f6cab07SMatt Macy 	return (0);
5023f6cab07SMatt Macy }
5033f6cab07SMatt Macy 
5043f6cab07SMatt Macy static int
505f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
5063f6cab07SMatt Macy {
5073f6cab07SMatt Macy 	return (0);
5083f6cab07SMatt Macy }
5093f6cab07SMatt Macy 
510f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
51103f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
512