xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision 03f1cf9f32ad6c8aacc2dcdb6b015923f5a346f8)
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 
723f6cab07SMatt Macy #include <linux/debugfs.h>
733f6cab07SMatt Macy #include <linux/seq_file.h>
743f6cab07SMatt Macy #include <linux/compat.h>
753f6cab07SMatt Macy 
763f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
773f6cab07SMatt Macy 
783f6cab07SMatt Macy static struct pfs_node *debugfs_root;
793f6cab07SMatt Macy 
803f6cab07SMatt Macy #define DM_SYMLINK 0x1
813f6cab07SMatt Macy #define DM_DIR 0x2
823f6cab07SMatt Macy #define DM_FILE 0x3
833f6cab07SMatt Macy 
843f6cab07SMatt Macy struct dentry_meta {
853f6cab07SMatt Macy 	struct dentry dm_dnode;
863f6cab07SMatt Macy 	const struct file_operations *dm_fops;
873f6cab07SMatt Macy 	void *dm_data;
883f6cab07SMatt Macy 	umode_t dm_mode;
893f6cab07SMatt Macy 	int dm_type;
903f6cab07SMatt Macy };
913f6cab07SMatt Macy 
923f6cab07SMatt Macy static int
933f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
943f6cab07SMatt Macy {
953f6cab07SMatt Macy 	struct dentry_meta *dm;
963f6cab07SMatt Macy 
973f6cab07SMatt Macy 	dm = pn->pn_data;
983f6cab07SMatt Macy 
993f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
1003f6cab07SMatt Macy 	return (0);
1013f6cab07SMatt Macy }
1023f6cab07SMatt Macy 
1033f6cab07SMatt Macy static int
1043f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1053f6cab07SMatt Macy {
1063f6cab07SMatt Macy 	struct dentry_meta *dm;
1073f6cab07SMatt Macy 
1083f6cab07SMatt Macy 	dm = pn->pn_data;
1093f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1103f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1113f6cab07SMatt Macy 
1123f6cab07SMatt Macy 	free(dm, M_DFSINT);
1133f6cab07SMatt Macy 	return (0);
1143f6cab07SMatt Macy }
1153f6cab07SMatt Macy 
1163f6cab07SMatt Macy static int
1173f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1183f6cab07SMatt Macy {
1193f6cab07SMatt Macy 	struct dentry_meta *d;
1203f6cab07SMatt Macy 	struct linux_file lf;
1213f6cab07SMatt Macy 	struct seq_file *sf;
1223f6cab07SMatt Macy 	struct vnode vn;
1233f6cab07SMatt Macy 	void *buf;
1243f6cab07SMatt Macy 	int rc;
1253f6cab07SMatt Macy 	size_t len;
1263f6cab07SMatt Macy 	off_t off;
1273f6cab07SMatt Macy 
1283f6cab07SMatt Macy 	d = pn->pn_data;
1293f6cab07SMatt Macy 
1303f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1313f6cab07SMatt Macy 		return (rc);
1323f6cab07SMatt Macy 	vn.v_data = d->dm_data;
1333f6cab07SMatt Macy 	buf = uio->uio_iov[0].iov_base;
1343f6cab07SMatt Macy 	len = min(uio->uio_iov[0].iov_len, uio->uio_resid);
1353f6cab07SMatt Macy 	off = 0;
1363f6cab07SMatt Macy 	lf.private_data = NULL;
1373f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1383f6cab07SMatt Macy 	if (rc < 0) {
1393f6cab07SMatt Macy #ifdef INVARIANTS
1403f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1413f6cab07SMatt Macy #endif
1423f6cab07SMatt Macy 		return (-rc);
1433f6cab07SMatt Macy 	}
1443f6cab07SMatt Macy 	sf = lf.private_data;
1453f6cab07SMatt Macy 	sf->buf = sb;
146*03f1cf9fSJohannes Lundberg 	if (uio->uio_rw == UIO_READ) {
147*03f1cf9fSJohannes Lundberg 		if (d->dm_fops->read)
1483f6cab07SMatt Macy 			rc = d->dm_fops->read(&lf, NULL, len, &off);
1493f6cab07SMatt Macy 		else
150*03f1cf9fSJohannes Lundberg 			rc = ENODEV;
151*03f1cf9fSJohannes Lundberg 	} else {
152*03f1cf9fSJohannes Lundberg 		if (d->dm_fops->write)
1533f6cab07SMatt Macy 			rc = d->dm_fops->write(&lf, buf, len, &off);
154*03f1cf9fSJohannes Lundberg 		else
155*03f1cf9fSJohannes Lundberg 			rc = ENODEV;
156*03f1cf9fSJohannes Lundberg 	}
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 
2163f6cab07SMatt Macy struct dentry *
2173f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2183f6cab07SMatt Macy {
2193f6cab07SMatt Macy 	struct dentry_meta *dm;
2203f6cab07SMatt Macy 	struct dentry *dnode;
2213f6cab07SMatt Macy 	struct pfs_node *pnode;
2223f6cab07SMatt Macy 
2233f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2243f6cab07SMatt Macy 	if (dm == NULL)
2253f6cab07SMatt Macy 		return (NULL);
2263f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2273f6cab07SMatt Macy 	dm->dm_mode = 0700;
2283f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2293f6cab07SMatt Macy 	if (parent != NULL)
2303f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2313f6cab07SMatt Macy 	else
2323f6cab07SMatt Macy 		pnode = debugfs_root;
2333f6cab07SMatt Macy 
2343f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2353f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2363f6cab07SMatt Macy 		free(dm, M_DFSINT);
2373f6cab07SMatt Macy 		return (NULL);
2383f6cab07SMatt Macy 	}
2393f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2403f6cab07SMatt Macy 	return (dnode);
2413f6cab07SMatt Macy }
2423f6cab07SMatt Macy 
2433f6cab07SMatt Macy struct dentry *
2443f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2453f6cab07SMatt Macy 	const char *dest)
2463f6cab07SMatt Macy {
2473f6cab07SMatt Macy 	struct dentry_meta *dm;
2483f6cab07SMatt Macy 	struct dentry *dnode;
2493f6cab07SMatt Macy 	struct pfs_node *pnode;
2503f6cab07SMatt Macy 	void *data;
2513f6cab07SMatt Macy 
2523f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
2533f6cab07SMatt Macy 	if (data == NULL)
2543f6cab07SMatt Macy 		return (NULL);
2553f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2563f6cab07SMatt Macy 	if (dm == NULL)
2573f6cab07SMatt Macy 		goto fail1;
2583f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2593f6cab07SMatt Macy 	dm->dm_mode = 0700;
2603f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
2613f6cab07SMatt Macy 	dm->dm_data = data;
2623f6cab07SMatt Macy 	if (parent != NULL)
2633f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2643f6cab07SMatt Macy 	else
2653f6cab07SMatt Macy 		pnode = debugfs_root;
2663f6cab07SMatt Macy 
2673f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
2683f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
2693f6cab07SMatt Macy 		goto fail;
2703f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2713f6cab07SMatt Macy 	return (dnode);
2723f6cab07SMatt Macy  fail:
2733f6cab07SMatt Macy 	free(dm, M_DFSINT);
2743f6cab07SMatt Macy  fail1:
2753f6cab07SMatt Macy 	free(data, M_DFSINT);
2763f6cab07SMatt Macy 	return (NULL);
2773f6cab07SMatt Macy }
2783f6cab07SMatt Macy 
2793f6cab07SMatt Macy void
2803f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
2813f6cab07SMatt Macy {
2823f6cab07SMatt Macy 	if (dnode == NULL)
2833f6cab07SMatt Macy 		return;
2843f6cab07SMatt Macy 
2853f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
2863f6cab07SMatt Macy }
2873f6cab07SMatt Macy 
2883f6cab07SMatt Macy void
2893f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
2903f6cab07SMatt Macy {
2913f6cab07SMatt Macy 	if (dnode == NULL)
2923f6cab07SMatt Macy 		return;
2933f6cab07SMatt Macy 
2943f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
2953f6cab07SMatt Macy }
2963f6cab07SMatt Macy 
2973f6cab07SMatt Macy 
2983f6cab07SMatt Macy static int
2993f6cab07SMatt Macy debugfs_init(PFS_INIT_ARGS)
3003f6cab07SMatt Macy {
3013f6cab07SMatt Macy 
3023f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
3033f6cab07SMatt Macy 	return (0);
3043f6cab07SMatt Macy }
3053f6cab07SMatt Macy 
3063f6cab07SMatt Macy static int
3073f6cab07SMatt Macy debugfs_uninit(PFS_INIT_ARGS)
3083f6cab07SMatt Macy {
3093f6cab07SMatt Macy 	return (0);
3103f6cab07SMatt Macy }
3113f6cab07SMatt Macy 
3123f6cab07SMatt Macy #ifdef PR_ALLOW_MOUNT_LINSYSFS
3133f6cab07SMatt Macy PSEUDOFS(debugfs, 1, PR_ALLOW_MOUNT_LINSYSFS);
3143f6cab07SMatt Macy #else
3153f6cab07SMatt Macy PSEUDOFS(debugfs, 1, VFCF_JAIL);
3163f6cab07SMatt Macy #endif
317*03f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
318