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
debugfs_attr(PFS_ATTR_ARGS)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
debugfs_destroy(PFS_DESTROY_ARGS)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
debugfs_fill(PFS_FILL_ARGS)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
13394e6c8d7SBjoern A. Zeeb printf("%s:%d open failed with %d\n", __func__, __LINE__, rc);
1343f6cab07SMatt Macy #endif
1353f6cab07SMatt Macy return (-rc);
1363f6cab07SMatt Macy }
137f697b943SJake Freeland
13868ec2949SHans Petter Selasky rc = -ENODEV;
139473c90acSJohn Baldwin switch (uio->uio_rw) {
140473c90acSJohn Baldwin case UIO_READ:
141473c90acSJohn Baldwin if (d->dm_fops->read != NULL) {
142f697b943SJake Freeland rc = -ENOMEM;
143473c90acSJohn Baldwin buf = malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
144f697b943SJake Freeland if (buf != NULL) {
145473c90acSJohn Baldwin rc = d->dm_fops->read(&lf, buf, sb->s_size,
146473c90acSJohn 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 }
152473c90acSJohn Baldwin }
153473c90acSJohn Baldwin break;
154473c90acSJohn Baldwin case UIO_WRITE:
155473c90acSJohn Baldwin if (d->dm_fops->write != NULL) {
156f697b943SJake Freeland sbuf_finish(sb);
157473c90acSJohn Baldwin rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb),
158473c90acSJohn Baldwin &off);
159473c90acSJohn Baldwin }
160473c90acSJohn Baldwin break;
161f697b943SJake Freeland }
162f697b943SJake Freeland
1633f6cab07SMatt Macy if (d->dm_fops->release)
1643f6cab07SMatt Macy d->dm_fops->release(&vn, &lf);
1653f6cab07SMatt Macy
1663f6cab07SMatt Macy if (rc < 0) {
1673f6cab07SMatt Macy #ifdef INVARIANTS
16894e6c8d7SBjoern A. Zeeb printf("%s:%d read/write failed with %d\n", __func__, __LINE__, rc);
1693f6cab07SMatt Macy #endif
1703f6cab07SMatt Macy return (-rc);
1713f6cab07SMatt Macy }
1723f6cab07SMatt Macy return (0);
1733f6cab07SMatt Macy }
1743f6cab07SMatt Macy
1753f6cab07SMatt Macy static int
debugfs_fill_data(PFS_FILL_ARGS)1763f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1773f6cab07SMatt Macy {
1783f6cab07SMatt Macy struct dentry_meta *dm;
1793f6cab07SMatt Macy
1803f6cab07SMatt Macy dm = pn->pn_data;
1813f6cab07SMatt Macy sbuf_printf(sb, "%s", (char *)dm->dm_data);
1823f6cab07SMatt Macy return (0);
1833f6cab07SMatt Macy }
1843f6cab07SMatt Macy
1853f6cab07SMatt Macy struct dentry *
debugfs_create_file(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops)1863f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1873f6cab07SMatt Macy struct dentry *parent, void *data,
1883f6cab07SMatt Macy const struct file_operations *fops)
1893f6cab07SMatt Macy {
1903f6cab07SMatt Macy struct dentry_meta *dm;
1913f6cab07SMatt Macy struct dentry *dnode;
1923f6cab07SMatt Macy struct pfs_node *pnode;
1933f6cab07SMatt Macy int flags;
1943f6cab07SMatt Macy
1953f6cab07SMatt Macy dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1963f6cab07SMatt Macy if (dm == NULL)
1973f6cab07SMatt Macy return (NULL);
1983f6cab07SMatt Macy dnode = &dm->dm_dnode;
1993f6cab07SMatt Macy dm->dm_fops = fops;
2003f6cab07SMatt Macy dm->dm_data = data;
2013f6cab07SMatt Macy dm->dm_mode = mode;
2023f6cab07SMatt Macy dm->dm_type = DM_FILE;
2033f6cab07SMatt Macy if (parent != NULL)
2043f6cab07SMatt Macy pnode = parent->d_pfs_node;
2053f6cab07SMatt Macy else
2063f6cab07SMatt Macy pnode = debugfs_root;
2073f6cab07SMatt Macy
2083f6cab07SMatt Macy flags = fops->write ? PFS_RDWR : PFS_RD;
2093f6cab07SMatt Macy dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2103f6cab07SMatt Macy debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2113f6cab07SMatt Macy if (dnode->d_pfs_node == NULL) {
2123f6cab07SMatt Macy free(dm, M_DFSINT);
2133f6cab07SMatt Macy return (NULL);
2143f6cab07SMatt Macy }
2153f6cab07SMatt Macy dnode->d_pfs_node->pn_data = dm;
2163f6cab07SMatt Macy
2173f6cab07SMatt Macy return (dnode);
2183f6cab07SMatt Macy }
2193f6cab07SMatt Macy
220a04aa80eSJean-Sébastien Pédron struct dentry *
debugfs_create_file_size(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops,loff_t file_size __unused)221a04aa80eSJean-Sébastien Pédron debugfs_create_file_size(const char *name, umode_t mode,
222a04aa80eSJean-Sébastien Pédron struct dentry *parent, void *data,
223a04aa80eSJean-Sébastien Pédron const struct file_operations *fops,
224a04aa80eSJean-Sébastien Pédron loff_t file_size __unused)
225a04aa80eSJean-Sébastien Pédron {
226a04aa80eSJean-Sébastien Pédron
227a04aa80eSJean-Sébastien Pédron return debugfs_create_file(name, mode, parent, data, fops);
228a04aa80eSJean-Sébastien Pédron }
229a04aa80eSJean-Sébastien Pédron
230f697b943SJake Freeland /*
231f697b943SJake Freeland * NOTE: Files created with the _unsafe moniker will not be protected from
232f697b943SJake Freeland * debugfs core file removals. It is the responsibility of @fops to protect
233f697b943SJake Freeland * its file using debugfs_file_get() and debugfs_file_put().
234f697b943SJake Freeland *
235f697b943SJake Freeland * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
236f697b943SJake Freeland * of writing. Therefore there is no difference between functions with _unsafe
237f697b943SJake Freeland * and functions without _unsafe when using lindebugfs. Functions with _unsafe
238f697b943SJake Freeland * exist only for Linux compatibility.
239f697b943SJake Freeland */
240f697b943SJake Freeland struct dentry *
debugfs_create_file_unsafe(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops)241f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
242f697b943SJake Freeland struct dentry *parent, void *data,
243f697b943SJake Freeland const struct file_operations *fops)
244f697b943SJake Freeland {
245a04aa80eSJean-Sébastien Pédron
246f697b943SJake Freeland return (debugfs_create_file(name, mode, parent, data, fops));
247f697b943SJake Freeland }
248f697b943SJake Freeland
249f697b943SJake Freeland struct dentry *
debugfs_create_mode_unsafe(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops,const struct file_operations * fops_ro,const struct file_operations * fops_wo)250f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
251f697b943SJake Freeland struct dentry *parent, void *data,
252f697b943SJake Freeland const struct file_operations *fops,
253f697b943SJake Freeland const struct file_operations *fops_ro,
254f697b943SJake Freeland const struct file_operations *fops_wo)
255f697b943SJake Freeland {
256f697b943SJake Freeland umode_t read = mode & S_IRUGO;
257f697b943SJake Freeland umode_t write = mode & S_IWUGO;
258f697b943SJake Freeland
259f697b943SJake Freeland if (read && !write)
260f697b943SJake Freeland return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
261f697b943SJake Freeland
262f697b943SJake Freeland if (write && !read)
263f697b943SJake Freeland return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
264f697b943SJake Freeland
265f697b943SJake Freeland return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
266f697b943SJake Freeland }
267f697b943SJake Freeland
2683f6cab07SMatt Macy struct dentry *
debugfs_create_dir(const char * name,struct dentry * parent)2693f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2703f6cab07SMatt Macy {
2713f6cab07SMatt Macy struct dentry_meta *dm;
2723f6cab07SMatt Macy struct dentry *dnode;
2733f6cab07SMatt Macy struct pfs_node *pnode;
2743f6cab07SMatt Macy
2753f6cab07SMatt Macy dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2763f6cab07SMatt Macy if (dm == NULL)
2773f6cab07SMatt Macy return (NULL);
2783f6cab07SMatt Macy dnode = &dm->dm_dnode;
2793f6cab07SMatt Macy dm->dm_mode = 0700;
2803f6cab07SMatt Macy dm->dm_type = DM_DIR;
2813f6cab07SMatt Macy if (parent != NULL)
2823f6cab07SMatt Macy pnode = parent->d_pfs_node;
2833f6cab07SMatt Macy else
2843f6cab07SMatt Macy pnode = debugfs_root;
2853f6cab07SMatt Macy
2863f6cab07SMatt Macy dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2873f6cab07SMatt Macy if (dnode->d_pfs_node == NULL) {
2883f6cab07SMatt Macy free(dm, M_DFSINT);
2893f6cab07SMatt Macy return (NULL);
2903f6cab07SMatt Macy }
2913f6cab07SMatt Macy dnode->d_pfs_node->pn_data = dm;
2923f6cab07SMatt Macy return (dnode);
2933f6cab07SMatt Macy }
2943f6cab07SMatt Macy
2953f6cab07SMatt Macy struct dentry *
debugfs_create_symlink(const char * name,struct dentry * parent,const char * dest)2963f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2973f6cab07SMatt Macy const char *dest)
2983f6cab07SMatt Macy {
2993f6cab07SMatt Macy struct dentry_meta *dm;
3003f6cab07SMatt Macy struct dentry *dnode;
3013f6cab07SMatt Macy struct pfs_node *pnode;
3023f6cab07SMatt Macy void *data;
3033f6cab07SMatt Macy
3043f6cab07SMatt Macy data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
3053f6cab07SMatt Macy if (data == NULL)
3063f6cab07SMatt Macy return (NULL);
3073f6cab07SMatt Macy dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
3083f6cab07SMatt Macy if (dm == NULL)
3093f6cab07SMatt Macy goto fail1;
3103f6cab07SMatt Macy dnode = &dm->dm_dnode;
3113f6cab07SMatt Macy dm->dm_mode = 0700;
3123f6cab07SMatt Macy dm->dm_type = DM_SYMLINK;
3133f6cab07SMatt Macy dm->dm_data = data;
3143f6cab07SMatt Macy if (parent != NULL)
3153f6cab07SMatt Macy pnode = parent->d_pfs_node;
3163f6cab07SMatt Macy else
3173f6cab07SMatt Macy pnode = debugfs_root;
3183f6cab07SMatt Macy
3193f6cab07SMatt Macy dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3203f6cab07SMatt Macy if (dnode->d_pfs_node == NULL)
3213f6cab07SMatt Macy goto fail;
3223f6cab07SMatt Macy dnode->d_pfs_node->pn_data = dm;
3233f6cab07SMatt Macy return (dnode);
3243f6cab07SMatt Macy fail:
3253f6cab07SMatt Macy free(dm, M_DFSINT);
3263f6cab07SMatt Macy fail1:
3273f6cab07SMatt Macy free(data, M_DFSINT);
3283f6cab07SMatt Macy return (NULL);
3293f6cab07SMatt Macy }
3303f6cab07SMatt Macy
3312ee13118SJean-Sébastien Pédron struct dentry *
debugfs_lookup(const char * name,struct dentry * parent)3322ee13118SJean-Sébastien Pédron debugfs_lookup(const char *name, struct dentry *parent)
3332ee13118SJean-Sébastien Pédron {
3342ee13118SJean-Sébastien Pédron struct dentry_meta *dm;
3352ee13118SJean-Sébastien Pédron struct dentry *dnode;
3362ee13118SJean-Sébastien Pédron struct pfs_node *pnode;
3372ee13118SJean-Sébastien Pédron
3382ee13118SJean-Sébastien Pédron pnode = pfs_find_node(parent->d_pfs_node, name);
3392ee13118SJean-Sébastien Pédron if (pnode == NULL)
3402ee13118SJean-Sébastien Pédron return (NULL);
3412ee13118SJean-Sébastien Pédron
3422ee13118SJean-Sébastien Pédron dm = (struct dentry_meta *)pnode->pn_data;
3432ee13118SJean-Sébastien Pédron dnode = &dm->dm_dnode;
3442ee13118SJean-Sébastien Pédron
3452ee13118SJean-Sébastien Pédron return (dnode);
3462ee13118SJean-Sébastien Pédron }
3472ee13118SJean-Sébastien Pédron
3483f6cab07SMatt Macy void
debugfs_remove(struct dentry * dnode)3493f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3503f6cab07SMatt Macy {
3513f6cab07SMatt Macy if (dnode == NULL)
3523f6cab07SMatt Macy return;
3533f6cab07SMatt Macy
3543f6cab07SMatt Macy pfs_destroy(dnode->d_pfs_node);
3553f6cab07SMatt Macy }
3563f6cab07SMatt Macy
3573f6cab07SMatt Macy void
debugfs_remove_recursive(struct dentry * dnode)3583f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3593f6cab07SMatt Macy {
3603f6cab07SMatt Macy if (dnode == NULL)
3613f6cab07SMatt Macy return;
3623f6cab07SMatt Macy
3633f6cab07SMatt Macy pfs_destroy(dnode->d_pfs_node);
3643f6cab07SMatt Macy }
3653f6cab07SMatt Macy
3663f6cab07SMatt Macy static int
debugfs_bool_get(void * data,uint64_t * ullval)367f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
368f697b943SJake Freeland {
369f697b943SJake Freeland bool *bval = data;
370f697b943SJake Freeland
371f697b943SJake Freeland if (*bval)
372f697b943SJake Freeland *ullval = 1;
373f697b943SJake Freeland else
374f697b943SJake Freeland *ullval = 0;
375f697b943SJake Freeland
376f697b943SJake Freeland return (0);
377f697b943SJake Freeland }
378f697b943SJake Freeland
379f697b943SJake Freeland static int
debugfs_bool_set(void * data,uint64_t ullval)380f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
381f697b943SJake Freeland {
382f697b943SJake Freeland bool *bval = data;
383f697b943SJake Freeland
384f697b943SJake Freeland if (ullval)
385f697b943SJake Freeland *bval = 1;
386f697b943SJake Freeland else
387f697b943SJake Freeland *bval = 0;
388f697b943SJake Freeland
389f697b943SJake Freeland return (0);
390f697b943SJake Freeland }
391f697b943SJake Freeland
392f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
393f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
394f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
395f697b943SJake Freeland
396f697b943SJake Freeland void
debugfs_create_bool(const char * name,umode_t mode,struct dentry * parent,bool * value)397f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
398f697b943SJake Freeland {
399976aa07aSJean-Sébastien Pédron
400f697b943SJake Freeland debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
401f697b943SJake Freeland &fops_bool_ro, &fops_bool_wo);
402f697b943SJake Freeland }
403f697b943SJake Freeland
4040fce2dc1SBjoern A. Zeeb
4050fce2dc1SBjoern A. Zeeb static int
debugfs_u8_get(void * data,uint64_t * value)4060fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
4070fce2dc1SBjoern A. Zeeb {
4080fce2dc1SBjoern A. Zeeb uint8_t *u8data = data;
4090fce2dc1SBjoern A. Zeeb *value = *u8data;
4100fce2dc1SBjoern A. Zeeb return (0);
4110fce2dc1SBjoern A. Zeeb }
4120fce2dc1SBjoern A. Zeeb
4130fce2dc1SBjoern A. Zeeb static int
debugfs_u8_set(void * data,uint64_t value)4140fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
4150fce2dc1SBjoern A. Zeeb {
4160fce2dc1SBjoern A. Zeeb uint8_t *u8data = data;
4170fce2dc1SBjoern A. Zeeb *u8data = (uint8_t)value;
4180fce2dc1SBjoern A. Zeeb return (0);
4190fce2dc1SBjoern A. Zeeb }
4200fce2dc1SBjoern A. Zeeb
4210fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
4220fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
4230fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
4240fce2dc1SBjoern A. Zeeb
4250fce2dc1SBjoern A. Zeeb void
debugfs_create_u8(const char * name,umode_t mode,struct dentry * parent,uint8_t * value)4260fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
4270fce2dc1SBjoern A. Zeeb {
428976aa07aSJean-Sébastien Pédron
4290fce2dc1SBjoern A. Zeeb debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
4300fce2dc1SBjoern A. Zeeb &fops_u8_ro, &fops_u8_wo);
4310fce2dc1SBjoern A. Zeeb }
4320fce2dc1SBjoern A. Zeeb
433976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
434976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
435976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
436976aa07aSJean-Sébastien Pédron
437976aa07aSJean-Sébastien Pédron void
debugfs_create_x8(const char * name,umode_t mode,struct dentry * parent,uint8_t * value)438976aa07aSJean-Sébastien Pédron debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
439976aa07aSJean-Sébastien Pédron {
440976aa07aSJean-Sébastien Pédron
441976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
442976aa07aSJean-Sébastien Pédron &fops_x8_ro, &fops_x8_wo);
443976aa07aSJean-Sébastien Pédron }
444976aa07aSJean-Sébastien Pédron
445976aa07aSJean-Sébastien Pédron
446976aa07aSJean-Sébastien Pédron static int
debugfs_u16_get(void * data,uint64_t * value)447976aa07aSJean-Sébastien Pédron debugfs_u16_get(void *data, uint64_t *value)
448976aa07aSJean-Sébastien Pédron {
449976aa07aSJean-Sébastien Pédron uint16_t *u16data = data;
450976aa07aSJean-Sébastien Pédron *value = *u16data;
451976aa07aSJean-Sébastien Pédron return (0);
452976aa07aSJean-Sébastien Pédron }
453976aa07aSJean-Sébastien Pédron
454976aa07aSJean-Sébastien Pédron static int
debugfs_u16_set(void * data,uint64_t value)455976aa07aSJean-Sébastien Pédron debugfs_u16_set(void *data, uint64_t value)
456976aa07aSJean-Sébastien Pédron {
457976aa07aSJean-Sébastien Pédron uint16_t *u16data = data;
458976aa07aSJean-Sébastien Pédron *u16data = (uint16_t)value;
459976aa07aSJean-Sébastien Pédron return (0);
460976aa07aSJean-Sébastien Pédron }
461976aa07aSJean-Sébastien Pédron
462976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
463976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
464976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
465976aa07aSJean-Sébastien Pédron
466976aa07aSJean-Sébastien Pédron void
debugfs_create_u16(const char * name,umode_t mode,struct dentry * parent,uint16_t * value)467976aa07aSJean-Sébastien Pédron debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
468976aa07aSJean-Sébastien Pédron {
469976aa07aSJean-Sébastien Pédron
470976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
471976aa07aSJean-Sébastien Pédron &fops_u16_ro, &fops_u16_wo);
472976aa07aSJean-Sébastien Pédron }
473976aa07aSJean-Sébastien Pédron
474976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
475976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
476976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
477976aa07aSJean-Sébastien Pédron
478976aa07aSJean-Sébastien Pédron void
debugfs_create_x16(const char * name,umode_t mode,struct dentry * parent,uint16_t * value)479976aa07aSJean-Sébastien Pédron debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
480976aa07aSJean-Sébastien Pédron {
481976aa07aSJean-Sébastien Pédron
482976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
483976aa07aSJean-Sébastien Pédron &fops_x16_ro, &fops_x16_wo);
484976aa07aSJean-Sébastien Pédron }
485976aa07aSJean-Sébastien Pédron
486976aa07aSJean-Sébastien Pédron
487976aa07aSJean-Sébastien Pédron static int
debugfs_u32_get(void * data,uint64_t * value)488976aa07aSJean-Sébastien Pédron debugfs_u32_get(void *data, uint64_t *value)
489976aa07aSJean-Sébastien Pédron {
490976aa07aSJean-Sébastien Pédron uint32_t *u32data = data;
491976aa07aSJean-Sébastien Pédron *value = *u32data;
492976aa07aSJean-Sébastien Pédron return (0);
493976aa07aSJean-Sébastien Pédron }
494976aa07aSJean-Sébastien Pédron
495976aa07aSJean-Sébastien Pédron static int
debugfs_u32_set(void * data,uint64_t value)496976aa07aSJean-Sébastien Pédron debugfs_u32_set(void *data, uint64_t value)
497976aa07aSJean-Sébastien Pédron {
498976aa07aSJean-Sébastien Pédron uint32_t *u32data = data;
499976aa07aSJean-Sébastien Pédron *u32data = (uint32_t)value;
500976aa07aSJean-Sébastien Pédron return (0);
501976aa07aSJean-Sébastien Pédron }
502976aa07aSJean-Sébastien Pédron
503976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
504976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
505976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
506976aa07aSJean-Sébastien Pédron
507976aa07aSJean-Sébastien Pédron void
debugfs_create_u32(const char * name,umode_t mode,struct dentry * parent,uint32_t * value)508976aa07aSJean-Sébastien Pédron debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
509976aa07aSJean-Sébastien Pédron {
510976aa07aSJean-Sébastien Pédron
511976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
512976aa07aSJean-Sébastien Pédron &fops_u32_ro, &fops_u32_wo);
513976aa07aSJean-Sébastien Pédron }
514976aa07aSJean-Sébastien Pédron
515976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
516976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
517976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
518976aa07aSJean-Sébastien Pédron
519976aa07aSJean-Sébastien Pédron void
debugfs_create_x32(const char * name,umode_t mode,struct dentry * parent,uint32_t * value)520976aa07aSJean-Sébastien Pédron debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
521976aa07aSJean-Sébastien Pédron {
522976aa07aSJean-Sébastien Pédron
523976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
524976aa07aSJean-Sébastien Pédron &fops_x32_ro, &fops_x32_wo);
525976aa07aSJean-Sébastien Pédron }
526976aa07aSJean-Sébastien Pédron
527976aa07aSJean-Sébastien Pédron
528976aa07aSJean-Sébastien Pédron static int
debugfs_u64_get(void * data,uint64_t * value)529976aa07aSJean-Sébastien Pédron debugfs_u64_get(void *data, uint64_t *value)
530976aa07aSJean-Sébastien Pédron {
531976aa07aSJean-Sébastien Pédron uint64_t *u64data = data;
532976aa07aSJean-Sébastien Pédron *value = *u64data;
533976aa07aSJean-Sébastien Pédron return (0);
534976aa07aSJean-Sébastien Pédron }
535976aa07aSJean-Sébastien Pédron
536976aa07aSJean-Sébastien Pédron static int
debugfs_u64_set(void * data,uint64_t value)537976aa07aSJean-Sébastien Pédron debugfs_u64_set(void *data, uint64_t value)
538976aa07aSJean-Sébastien Pédron {
539976aa07aSJean-Sébastien Pédron uint64_t *u64data = data;
540976aa07aSJean-Sébastien Pédron *u64data = (uint64_t)value;
541976aa07aSJean-Sébastien Pédron return (0);
542976aa07aSJean-Sébastien Pédron }
543976aa07aSJean-Sébastien Pédron
544976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
545976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
546976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
547976aa07aSJean-Sébastien Pédron
548976aa07aSJean-Sébastien Pédron void
debugfs_create_u64(const char * name,umode_t mode,struct dentry * parent,uint64_t * value)549976aa07aSJean-Sébastien Pédron debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
550976aa07aSJean-Sébastien Pédron {
551976aa07aSJean-Sébastien Pédron
552976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
553976aa07aSJean-Sébastien Pédron &fops_u64_ro, &fops_u64_wo);
554976aa07aSJean-Sébastien Pédron }
555976aa07aSJean-Sébastien Pédron
556976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
557976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
558976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
559976aa07aSJean-Sébastien Pédron
560976aa07aSJean-Sébastien Pédron void
debugfs_create_x64(const char * name,umode_t mode,struct dentry * parent,uint64_t * value)561976aa07aSJean-Sébastien Pédron debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
562976aa07aSJean-Sébastien Pédron {
563976aa07aSJean-Sébastien Pédron
564976aa07aSJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
565976aa07aSJean-Sébastien Pédron &fops_x64_ro, &fops_x64_wo);
566976aa07aSJean-Sébastien Pédron }
567976aa07aSJean-Sébastien Pédron
5680fce2dc1SBjoern A. Zeeb
569f697b943SJake Freeland static int
debugfs_ulong_get(void * data,uint64_t * value)570f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
571f697b943SJake Freeland {
572f697b943SJake Freeland uint64_t *uldata = data;
573f697b943SJake Freeland *value = *uldata;
574f697b943SJake Freeland return (0);
575f697b943SJake Freeland }
576f697b943SJake Freeland
577f697b943SJake Freeland static int
debugfs_ulong_set(void * data,uint64_t value)578f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
579f697b943SJake Freeland {
580f697b943SJake Freeland uint64_t *uldata = data;
581f697b943SJake Freeland *uldata = value;
582f697b943SJake Freeland return (0);
583f697b943SJake Freeland }
584f697b943SJake Freeland
585f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
586f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
587f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
588f697b943SJake Freeland
589f697b943SJake Freeland void
debugfs_create_ulong(const char * name,umode_t mode,struct dentry * parent,unsigned long * value)590f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
591f697b943SJake Freeland {
592976aa07aSJean-Sébastien Pédron
593f697b943SJake Freeland debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
594f697b943SJake Freeland &fops_ulong_ro, &fops_ulong_wo);
595f697b943SJake Freeland }
596f697b943SJake Freeland
5970fce2dc1SBjoern A. Zeeb
598f2044a30SJean-Sébastien Pédron static int
debugfs_atomic_t_get(void * data,uint64_t * value)599f2044a30SJean-Sébastien Pédron debugfs_atomic_t_get(void *data, uint64_t *value)
600f2044a30SJean-Sébastien Pédron {
601f2044a30SJean-Sébastien Pédron atomic_t *atomic_data = data;
602f2044a30SJean-Sébastien Pédron *value = atomic_read(atomic_data);
603f2044a30SJean-Sébastien Pédron return (0);
604f2044a30SJean-Sébastien Pédron }
605f2044a30SJean-Sébastien Pédron
606f2044a30SJean-Sébastien Pédron static int
debugfs_atomic_t_set(void * data,uint64_t value)607f2044a30SJean-Sébastien Pédron debugfs_atomic_t_set(void *data, uint64_t value)
608f2044a30SJean-Sébastien Pédron {
609f2044a30SJean-Sébastien Pédron atomic_t *atomic_data = data;
610f2044a30SJean-Sébastien Pédron atomic_set(atomic_data, (int)value);
611f2044a30SJean-Sébastien Pédron return (0);
612f2044a30SJean-Sébastien Pédron }
613f2044a30SJean-Sébastien Pédron
614f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
615f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
616f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
617f2044a30SJean-Sébastien Pédron
618f2044a30SJean-Sébastien Pédron void
debugfs_create_atomic_t(const char * name,umode_t mode,struct dentry * parent,atomic_t * value)619f2044a30SJean-Sébastien Pédron debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
620f2044a30SJean-Sébastien Pédron {
621f2044a30SJean-Sébastien Pédron
622f2044a30SJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
623f2044a30SJean-Sébastien Pédron &fops_atomic_t_ro, &fops_atomic_t_wo);
624f2044a30SJean-Sébastien Pédron }
625f2044a30SJean-Sébastien Pédron
626f2044a30SJean-Sébastien Pédron
627*78e25e65SJean-Sébastien Pédron static int
fops_str_open(struct inode * inode,struct file * filp)628*78e25e65SJean-Sébastien Pédron fops_str_open(struct inode *inode, struct file *filp)
629*78e25e65SJean-Sébastien Pédron {
630*78e25e65SJean-Sébastien Pédron
631*78e25e65SJean-Sébastien Pédron return (simple_open(inode, filp));
632*78e25e65SJean-Sébastien Pédron }
633*78e25e65SJean-Sébastien Pédron
634*78e25e65SJean-Sébastien Pédron static ssize_t
fops_str_read(struct file * filp,char __user * ubuf,size_t read_size,loff_t * ppos)635*78e25e65SJean-Sébastien Pédron fops_str_read(struct file *filp, char __user *ubuf, size_t read_size,
636*78e25e65SJean-Sébastien Pédron loff_t *ppos)
637*78e25e65SJean-Sébastien Pédron {
638*78e25e65SJean-Sébastien Pédron ssize_t ret;
639*78e25e65SJean-Sébastien Pédron char *str, *str_with_newline;
640*78e25e65SJean-Sébastien Pédron size_t str_len, str_with_newline_len;
641*78e25e65SJean-Sébastien Pédron
642*78e25e65SJean-Sébastien Pédron if (filp->private_data == NULL)
643*78e25e65SJean-Sébastien Pédron return (-EINVAL);
644*78e25e65SJean-Sébastien Pédron
645*78e25e65SJean-Sébastien Pédron str = *(char **)filp->private_data;
646*78e25e65SJean-Sébastien Pédron str_len = strlen(str);
647*78e25e65SJean-Sébastien Pédron
648*78e25e65SJean-Sébastien Pédron /*
649*78e25e65SJean-Sébastien Pédron * `str_with_newline` is terminated with a newline, but is not
650*78e25e65SJean-Sébastien Pédron * NUL-terminated.
651*78e25e65SJean-Sébastien Pédron */
652*78e25e65SJean-Sébastien Pédron str_with_newline_len = str_len + 1;
653*78e25e65SJean-Sébastien Pédron str_with_newline = kmalloc(str_with_newline_len, GFP_KERNEL);
654*78e25e65SJean-Sébastien Pédron if (str_with_newline == NULL)
655*78e25e65SJean-Sébastien Pédron return (-ENOMEM);
656*78e25e65SJean-Sébastien Pédron
657*78e25e65SJean-Sébastien Pédron strncpy(str_with_newline, str, str_len);
658*78e25e65SJean-Sébastien Pédron str_with_newline[str_len] = '\n';
659*78e25e65SJean-Sébastien Pédron
660*78e25e65SJean-Sébastien Pédron ret = simple_read_from_buffer(ubuf, read_size, ppos,
661*78e25e65SJean-Sébastien Pédron str_with_newline, str_with_newline_len);
662*78e25e65SJean-Sébastien Pédron
663*78e25e65SJean-Sébastien Pédron kfree(str_with_newline);
664*78e25e65SJean-Sébastien Pédron
665*78e25e65SJean-Sébastien Pédron return (ret);
666*78e25e65SJean-Sébastien Pédron }
667*78e25e65SJean-Sébastien Pédron
668*78e25e65SJean-Sébastien Pédron static ssize_t
fops_str_write(struct file * filp,const char * buf,size_t write_size,loff_t * ppos)669*78e25e65SJean-Sébastien Pédron fops_str_write(struct file *filp, const char *buf, size_t write_size,
670*78e25e65SJean-Sébastien Pédron loff_t *ppos)
671*78e25e65SJean-Sébastien Pédron {
672*78e25e65SJean-Sébastien Pédron char *old, *new;
673*78e25e65SJean-Sébastien Pédron size_t old_len, new_len;
674*78e25e65SJean-Sébastien Pédron
675*78e25e65SJean-Sébastien Pédron if (filp->private_data == NULL)
676*78e25e65SJean-Sébastien Pédron return (-EINVAL);
677*78e25e65SJean-Sébastien Pédron
678*78e25e65SJean-Sébastien Pédron old = *(char **)filp->private_data;
679*78e25e65SJean-Sébastien Pédron new = NULL;
680*78e25e65SJean-Sébastien Pédron
681*78e25e65SJean-Sébastien Pédron /*
682*78e25e65SJean-Sébastien Pédron * We enforce concatenation of the newly written value to the existing
683*78e25e65SJean-Sébastien Pédron * value.
684*78e25e65SJean-Sébastien Pédron */
685*78e25e65SJean-Sébastien Pédron old_len = strlen(old);
686*78e25e65SJean-Sébastien Pédron if (*ppos && *ppos != old_len)
687*78e25e65SJean-Sébastien Pédron return (-EINVAL);
688*78e25e65SJean-Sébastien Pédron
689*78e25e65SJean-Sébastien Pédron new_len = old_len + write_size;
690*78e25e65SJean-Sébastien Pédron if (new_len + 1 > PAGE_SIZE)
691*78e25e65SJean-Sébastien Pédron return (-E2BIG);
692*78e25e65SJean-Sébastien Pédron
693*78e25e65SJean-Sébastien Pédron new = kmalloc(new_len + 1, GFP_KERNEL);
694*78e25e65SJean-Sébastien Pédron if (new == NULL)
695*78e25e65SJean-Sébastien Pédron return (-ENOMEM);
696*78e25e65SJean-Sébastien Pédron
697*78e25e65SJean-Sébastien Pédron memcpy(new, old, old_len);
698*78e25e65SJean-Sébastien Pédron if (copy_from_user(new + old_len, buf, write_size) != 0) {
699*78e25e65SJean-Sébastien Pédron kfree(new);
700*78e25e65SJean-Sébastien Pédron return (-EFAULT);
701*78e25e65SJean-Sébastien Pédron }
702*78e25e65SJean-Sébastien Pédron
703*78e25e65SJean-Sébastien Pédron new[new_len] = '\0';
704*78e25e65SJean-Sébastien Pédron strim(new);
705*78e25e65SJean-Sébastien Pédron
706*78e25e65SJean-Sébastien Pédron filp->private_data = &new;
707*78e25e65SJean-Sébastien Pédron
708*78e25e65SJean-Sébastien Pédron kfree(old);
709*78e25e65SJean-Sébastien Pédron
710*78e25e65SJean-Sébastien Pédron return (write_size);
711*78e25e65SJean-Sébastien Pédron }
712*78e25e65SJean-Sébastien Pédron
713*78e25e65SJean-Sébastien Pédron static const struct file_operations fops_str = {
714*78e25e65SJean-Sébastien Pédron .owner = THIS_MODULE,
715*78e25e65SJean-Sébastien Pédron .open = fops_str_open,
716*78e25e65SJean-Sébastien Pédron .read = fops_str_read,
717*78e25e65SJean-Sébastien Pédron .write = fops_str_write,
718*78e25e65SJean-Sébastien Pédron .llseek = no_llseek
719*78e25e65SJean-Sébastien Pédron };
720*78e25e65SJean-Sébastien Pédron static const struct file_operations fops_str_ro = {
721*78e25e65SJean-Sébastien Pédron .owner = THIS_MODULE,
722*78e25e65SJean-Sébastien Pédron .open = fops_str_open,
723*78e25e65SJean-Sébastien Pédron .read = fops_str_read,
724*78e25e65SJean-Sébastien Pédron .llseek = no_llseek
725*78e25e65SJean-Sébastien Pédron };
726*78e25e65SJean-Sébastien Pédron static const struct file_operations fops_str_wo = {
727*78e25e65SJean-Sébastien Pédron .owner = THIS_MODULE,
728*78e25e65SJean-Sébastien Pédron .open = fops_str_open,
729*78e25e65SJean-Sébastien Pédron .write = fops_str_write,
730*78e25e65SJean-Sébastien Pédron .llseek = no_llseek
731*78e25e65SJean-Sébastien Pédron };
732*78e25e65SJean-Sébastien Pédron
733*78e25e65SJean-Sébastien Pédron void
debugfs_create_str(const char * name,umode_t mode,struct dentry * parent,char ** value)734*78e25e65SJean-Sébastien Pédron debugfs_create_str(const char *name, umode_t mode, struct dentry *parent,
735*78e25e65SJean-Sébastien Pédron char **value)
736*78e25e65SJean-Sébastien Pédron {
737*78e25e65SJean-Sébastien Pédron debugfs_create_mode_unsafe(name, mode, parent, value,
738*78e25e65SJean-Sébastien Pédron &fops_str, &fops_str_ro, &fops_str_wo);
739*78e25e65SJean-Sébastien Pédron }
740*78e25e65SJean-Sébastien Pédron
741*78e25e65SJean-Sébastien Pédron
7420fce2dc1SBjoern A. Zeeb static ssize_t
fops_blob_read(struct file * filp,char __user * ubuf,size_t read_size,loff_t * ppos)7430fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
7440fce2dc1SBjoern A. Zeeb {
7450fce2dc1SBjoern A. Zeeb struct debugfs_blob_wrapper *blob;
7460fce2dc1SBjoern A. Zeeb
7470fce2dc1SBjoern A. Zeeb blob = filp->private_data;
7480fce2dc1SBjoern A. Zeeb if (blob == NULL)
7490fce2dc1SBjoern A. Zeeb return (-EINVAL);
7500fce2dc1SBjoern A. Zeeb if (blob->size == 0 || blob->data == NULL)
7510fce2dc1SBjoern A. Zeeb return (-EINVAL);
7520fce2dc1SBjoern A. Zeeb
7530fce2dc1SBjoern A. Zeeb return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
7540fce2dc1SBjoern A. Zeeb }
7550fce2dc1SBjoern A. Zeeb
7560fce2dc1SBjoern A. Zeeb static int
fops_blob_open(struct inode * inode,struct file * filp)7570fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
7580fce2dc1SBjoern A. Zeeb {
759976aa07aSJean-Sébastien Pédron
7600fce2dc1SBjoern A. Zeeb return (simple_open(inode, filp));
7610fce2dc1SBjoern A. Zeeb }
7620fce2dc1SBjoern A. Zeeb
7630fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
7640fce2dc1SBjoern A. Zeeb .owner = THIS_MODULE,
7650fce2dc1SBjoern A. Zeeb .open = fops_blob_open,
7660fce2dc1SBjoern A. Zeeb .read = fops_blob_read,
7670fce2dc1SBjoern A. Zeeb .llseek = no_llseek
7680fce2dc1SBjoern A. Zeeb };
7690fce2dc1SBjoern A. Zeeb
7700fce2dc1SBjoern A. Zeeb struct dentry *
debugfs_create_blob(const char * name,umode_t mode,struct dentry * parent,struct debugfs_blob_wrapper * value)7710fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
7720fce2dc1SBjoern A. Zeeb struct debugfs_blob_wrapper *value)
7730fce2dc1SBjoern A. Zeeb {
7740fce2dc1SBjoern A. Zeeb /* Blobs are read-only. */
7750fce2dc1SBjoern A. Zeeb return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
7760fce2dc1SBjoern A. Zeeb }
7770fce2dc1SBjoern A. Zeeb
7780fce2dc1SBjoern A. Zeeb
779f697b943SJake Freeland static int
lindebugfs_init(PFS_INIT_ARGS)780f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
7813f6cab07SMatt Macy {
7823f6cab07SMatt Macy
7833f6cab07SMatt Macy debugfs_root = pi->pi_root;
78446888dedSMark Johnston
78546888dedSMark Johnston (void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
78646888dedSMark Johnston
7873f6cab07SMatt Macy return (0);
7883f6cab07SMatt Macy }
7893f6cab07SMatt Macy
7903f6cab07SMatt Macy static int
lindebugfs_uninit(PFS_INIT_ARGS)791f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
7923f6cab07SMatt Macy {
793976aa07aSJean-Sébastien Pédron
7943f6cab07SMatt Macy return (0);
7953f6cab07SMatt Macy }
7963f6cab07SMatt Macy
797f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
79803f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
799