xref: /src/sys/compat/lindebugfs/lindebugfs.c (revision 2cf15144daf7ec44cdcd9bf3ef007939b79c361e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/queue.h>
32 #include <sys/blist.h>
33 #include <sys/conf.h>
34 #include <sys/exec.h>
35 #include <sys/filedesc.h>
36 #include <sys/kernel.h>
37 #include <sys/linker.h>
38 #include <sys/malloc.h>
39 #include <sys/mount.h>
40 #include <sys/mutex.h>
41 #include <sys/proc.h>
42 #include <sys/resourcevar.h>
43 #include <sys/sbuf.h>
44 #include <sys/smp.h>
45 #include <sys/socket.h>
46 #include <sys/vnode.h>
47 #include <sys/bus.h>
48 #include <sys/pciio.h>
49 
50 #include <dev/pci/pcivar.h>
51 #include <dev/pci/pcireg.h>
52 
53 #include <net/if.h>
54 
55 #include <vm/vm.h>
56 #include <vm/pmap.h>
57 #include <vm/vm_map.h>
58 #include <vm/vm_param.h>
59 #include <vm/vm_object.h>
60 #include <vm/swap_pager.h>
61 
62 #include <machine/bus.h>
63 
64 #include <compat/linux/linux_ioctl.h>
65 #include <compat/linux/linux_mib.h>
66 #include <compat/linux/linux_util.h>
67 #include <fs/pseudofs/pseudofs.h>
68 
69 #include <asm/atomic.h>
70 #include <linux/compat.h>
71 #include <linux/debugfs.h>
72 #include <linux/fs.h>
73 
74 MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
75 
76 static struct pfs_node *debugfs_root;
77 
78 #define DM_SYMLINK 0x1
79 #define DM_DIR 0x2
80 #define DM_FILE 0x3
81 
82 struct dentry_meta {
83 	struct dentry dm_dnode;
84 	const struct file_operations *dm_fops;
85 	void *dm_data;
86 	umode_t dm_mode;
87 	int dm_type;
88 };
89 
90 static int
debugfs_attr(PFS_ATTR_ARGS)91 debugfs_attr(PFS_ATTR_ARGS)
92 {
93 	struct dentry_meta *dm;
94 
95 	dm = pn->pn_data;
96 
97 	vap->va_mode = dm->dm_mode;
98 	return (0);
99 }
100 
101 static int
debugfs_destroy(PFS_DESTROY_ARGS)102 debugfs_destroy(PFS_DESTROY_ARGS)
103 {
104 	struct dentry_meta *dm;
105 
106 	dm = pn->pn_data;
107 	if (dm != NULL && dm->dm_type == DM_SYMLINK)
108 		free(dm->dm_data, M_DFSINT);
109 
110 	free(dm, M_DFSINT);
111 	return (0);
112 }
113 
114 static int
debugfs_fill(PFS_FILL_ARGS)115 debugfs_fill(PFS_FILL_ARGS)
116 {
117 	struct dentry_meta *d;
118 	struct linux_file lf = {};
119 	struct vnode vn;
120 	struct iovec *iov;
121 	size_t cnt, orig_resid;
122 	ssize_t rc;
123 	off_t off;
124 
125 	/* Linux file operations assume a pointer to a user buffer. */
126 	if (uio->uio_segflg != UIO_USERSPACE)
127 		return (EOPNOTSUPP);
128 
129 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
130 		return (rc);
131 
132 	d = pn->pn_data;
133 	vn.v_data = d->dm_data;
134 
135 	rc = d->dm_fops->open(&vn, &lf);
136 	if (rc < 0) {
137 #ifdef INVARIANTS
138 		printf("%s:%d open failed with %zd\n", __func__, __LINE__, rc);
139 #endif
140 		return (-rc);
141 	}
142 
143 	off = uio->uio_offset;
144 	orig_resid = uio->uio_resid;
145 	while (uio->uio_resid > 0) {
146 		KASSERT(uio->uio_iovcnt > 0,
147 		    ("%s: uio %p iovcnt underflow", __func__, uio));
148 
149 		iov = uio->uio_iov;
150 		cnt = iov->iov_len;
151 		if (cnt == 0) {
152 			uio->uio_iov++;
153 			uio->uio_iovcnt--;
154 			continue;
155 		}
156 		if (cnt > uio->uio_resid)
157 			cnt = uio->uio_resid;
158 
159 		switch (uio->uio_rw) {
160 		case UIO_READ:
161 			if (d->dm_fops->read != NULL)
162 				rc = d->dm_fops->read(&lf, iov->iov_base, cnt,
163 				    &off);
164 			else
165 				rc = -ENODEV;
166 			break;
167 		case UIO_WRITE:
168 			if (d->dm_fops->write != NULL)
169 				rc = d->dm_fops->write(&lf, iov->iov_base, cnt,
170 				    &off);
171 			else
172 				rc = -ENODEV;
173 			break;
174 		}
175 
176 		if (rc <= 0)
177 			break;
178 
179 		iov->iov_base = (char *)iov->iov_base + rc;
180 		iov->iov_len -= rc;
181 		uio->uio_resid -= rc;
182 		uio->uio_offset = off;
183 	}
184 
185 	if (d->dm_fops->release)
186 		d->dm_fops->release(&vn, &lf);
187 
188 	/* Return success for short operations. */
189 	if (orig_resid != uio->uio_resid)
190 		rc = 0;
191 
192 	if (rc < 0) {
193 #ifdef INVARIANTS
194 		printf("%s:%d read/write failed with %zd\n", __func__, __LINE__,
195 		    rc);
196 #endif
197 		return (-rc);
198 	}
199 	return (0);
200 }
201 
202 static int
debugfs_fill_data(PFS_FILL_ARGS)203 debugfs_fill_data(PFS_FILL_ARGS)
204 {
205 	struct dentry_meta *dm;
206 
207 	dm = pn->pn_data;
208 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
209 	return (0);
210 }
211 
212 struct dentry *
debugfs_create_file(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops)213 debugfs_create_file(const char *name, umode_t mode,
214     struct dentry *parent, void *data,
215     const struct file_operations *fops)
216 {
217 	struct dentry_meta *dm;
218 	struct dentry *dnode;
219 	struct pfs_node *pnode;
220 	int flags;
221 
222 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
223 	if (dm == NULL)
224 		return (NULL);
225 	dnode = &dm->dm_dnode;
226 	dm->dm_fops = fops;
227 	dm->dm_data = data;
228 	dm->dm_mode = mode;
229 	dm->dm_type = DM_FILE;
230 	if (parent != NULL)
231 		pnode = parent->d_pfs_node;
232 	else
233 		pnode = debugfs_root;
234 
235 	flags = fops->write ? PFS_RDWR : PFS_RD;
236 	pfs_create_file(pnode, &dnode->d_pfs_node, name, debugfs_fill,
237 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_RAW | PFS_NOWAIT);
238 	if (dnode->d_pfs_node == NULL) {
239 		free(dm, M_DFSINT);
240 		return (NULL);
241 	}
242 	dnode->d_pfs_node->pn_data = dm;
243 
244 	return (dnode);
245 }
246 
247 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)248 debugfs_create_file_size(const char *name, umode_t mode,
249     struct dentry *parent, void *data,
250     const struct file_operations *fops,
251     loff_t file_size __unused)
252 {
253 
254 	return debugfs_create_file(name, mode, parent, data, fops);
255 }
256 
257 /*
258  * NOTE: Files created with the _unsafe moniker will not be protected from
259  * debugfs core file removals. It is the responsibility of @fops to protect
260  * its file using debugfs_file_get() and debugfs_file_put().
261  *
262  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
263  * of writing. Therefore there is no difference between functions with _unsafe
264  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
265  * exist only for Linux compatibility.
266  */
267 struct dentry *
debugfs_create_file_unsafe(const char * name,umode_t mode,struct dentry * parent,void * data,const struct file_operations * fops)268 debugfs_create_file_unsafe(const char *name, umode_t mode,
269     struct dentry *parent, void *data,
270     const struct file_operations *fops)
271 {
272 
273 	return (debugfs_create_file(name, mode, parent, data, fops));
274 }
275 
276 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)277 debugfs_create_mode_unsafe(const char *name, umode_t mode,
278     struct dentry *parent, void *data,
279     const struct file_operations *fops,
280     const struct file_operations *fops_ro,
281     const struct file_operations *fops_wo)
282 {
283 	umode_t read = mode & S_IRUGO;
284 	umode_t write = mode & S_IWUGO;
285 
286 	if (read && !write)
287 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
288 
289 	if (write && !read)
290 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
291 
292 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
293 }
294 
295 struct dentry *
debugfs_create_dir(const char * name,struct dentry * parent)296 debugfs_create_dir(const char *name, struct dentry *parent)
297 {
298 	struct dentry_meta *dm;
299 	struct dentry *dnode;
300 	struct pfs_node *pnode;
301 
302 	if (name == NULL)
303 		return (NULL);
304 
305 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
306 	if (dm == NULL)
307 		return (NULL);
308 	dnode = &dm->dm_dnode;
309 	dm->dm_mode = 0700;
310 	dm->dm_type = DM_DIR;
311 	if (parent != NULL)
312 		pnode = parent->d_pfs_node;
313 	else
314 		pnode = debugfs_root;
315 
316 	pfs_create_dir(pnode, &dnode->d_pfs_node, name, debugfs_attr, NULL,
317 	    debugfs_destroy, PFS_RD | PFS_NOWAIT);
318 	if (dnode->d_pfs_node == NULL) {
319 		free(dm, M_DFSINT);
320 		return (NULL);
321 	}
322 	dnode->d_pfs_node->pn_data = dm;
323 	return (dnode);
324 }
325 
326 struct dentry *
debugfs_create_symlink(const char * name,struct dentry * parent,const char * dest)327 debugfs_create_symlink(const char *name, struct dentry *parent,
328     const char *dest)
329 {
330 	struct dentry_meta *dm;
331 	struct dentry *dnode;
332 	struct pfs_node *pnode;
333 	void *data;
334 
335 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
336 	if (data == NULL)
337 		return (NULL);
338 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
339 	if (dm == NULL)
340 		goto fail1;
341 	dnode = &dm->dm_dnode;
342 	dm->dm_mode = 0700;
343 	dm->dm_type = DM_SYMLINK;
344 	dm->dm_data = data;
345 	if (parent != NULL)
346 		pnode = parent->d_pfs_node;
347 	else
348 		pnode = debugfs_root;
349 
350 	pfs_create_link(pnode, &dnode->d_pfs_node, name, &debugfs_fill_data,
351 	    NULL, NULL, NULL, PFS_NOWAIT);
352 	if (dnode->d_pfs_node == NULL)
353 		goto fail;
354 	dnode->d_pfs_node->pn_data = dm;
355 	return (dnode);
356  fail:
357 	free(dm, M_DFSINT);
358  fail1:
359 	free(data, M_DFSINT);
360 	return (NULL);
361 }
362 
363 struct dentry *
debugfs_lookup(const char * name,struct dentry * parent)364 debugfs_lookup(const char *name, struct dentry *parent)
365 {
366 	struct dentry_meta *dm;
367 	struct dentry *dnode;
368 	struct pfs_node *pnode;
369 
370 	pnode = pfs_find_node(parent->d_pfs_node, name);
371 	if (pnode == NULL)
372 		return (NULL);
373 
374 	dm = (struct dentry_meta *)pnode->pn_data;
375 	dnode = &dm->dm_dnode;
376 
377 	return (dnode);
378 }
379 
380 void
debugfs_remove(struct dentry * dnode)381 debugfs_remove(struct dentry *dnode)
382 {
383 	if (dnode == NULL)
384 		return;
385 
386 	pfs_destroy(dnode->d_pfs_node);
387 }
388 
389 void
debugfs_remove_recursive(struct dentry * dnode)390 debugfs_remove_recursive(struct dentry *dnode)
391 {
392 	if (dnode == NULL)
393 		return;
394 
395 	pfs_destroy(dnode->d_pfs_node);
396 }
397 
398 static int
debugfs_bool_get(void * data,uint64_t * ullval)399 debugfs_bool_get(void *data, uint64_t *ullval)
400 {
401 	bool *bval = data;
402 
403 	if (*bval)
404 		*ullval = 1;
405 	else
406 		*ullval = 0;
407 
408 	return (0);
409 }
410 
411 static int
debugfs_bool_set(void * data,uint64_t ullval)412 debugfs_bool_set(void *data, uint64_t ullval)
413 {
414 	bool *bval = data;
415 
416 	if (ullval)
417 		*bval = 1;
418 	else
419 		*bval = 0;
420 
421 	return (0);
422 }
423 
424 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
425 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
426 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
427 
428 void
debugfs_create_bool(const char * name,umode_t mode,struct dentry * parent,bool * value)429 debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
430 {
431 
432 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
433 	    &fops_bool_ro, &fops_bool_wo);
434 }
435 
436 
437 static int
debugfs_u8_get(void * data,uint64_t * value)438 debugfs_u8_get(void *data, uint64_t *value)
439 {
440 	uint8_t *u8data = data;
441 	*value = *u8data;
442 	return (0);
443 }
444 
445 static int
debugfs_u8_set(void * data,uint64_t value)446 debugfs_u8_set(void *data, uint64_t value)
447 {
448 	uint8_t *u8data = data;
449 	*u8data = (uint8_t)value;
450 	return (0);
451 }
452 
453 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
454 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
455 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
456 
457 void
debugfs_create_u8(const char * name,umode_t mode,struct dentry * parent,uint8_t * value)458 debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
459 {
460 
461 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
462 	    &fops_u8_ro, &fops_u8_wo);
463 }
464 
465 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
466 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
467 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
468 
469 void
debugfs_create_x8(const char * name,umode_t mode,struct dentry * parent,uint8_t * value)470 debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
471 {
472 
473 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
474 	    &fops_x8_ro, &fops_x8_wo);
475 }
476 
477 
478 static int
debugfs_u16_get(void * data,uint64_t * value)479 debugfs_u16_get(void *data, uint64_t *value)
480 {
481 	uint16_t *u16data = data;
482 	*value = *u16data;
483 	return (0);
484 }
485 
486 static int
debugfs_u16_set(void * data,uint64_t value)487 debugfs_u16_set(void *data, uint64_t value)
488 {
489 	uint16_t *u16data = data;
490 	*u16data = (uint16_t)value;
491 	return (0);
492 }
493 
494 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
495 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
496 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
497 
498 void
debugfs_create_u16(const char * name,umode_t mode,struct dentry * parent,uint16_t * value)499 debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
500 {
501 
502 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
503 	    &fops_u16_ro, &fops_u16_wo);
504 }
505 
506 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
507 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
508 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
509 
510 void
debugfs_create_x16(const char * name,umode_t mode,struct dentry * parent,uint16_t * value)511 debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
512 {
513 
514 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
515 	    &fops_x16_ro, &fops_x16_wo);
516 }
517 
518 
519 static int
debugfs_u32_get(void * data,uint64_t * value)520 debugfs_u32_get(void *data, uint64_t *value)
521 {
522 	uint32_t *u32data = data;
523 	*value = *u32data;
524 	return (0);
525 }
526 
527 static int
debugfs_u32_set(void * data,uint64_t value)528 debugfs_u32_set(void *data, uint64_t value)
529 {
530 	uint32_t *u32data = data;
531 	*u32data = (uint32_t)value;
532 	return (0);
533 }
534 
535 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
536 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
537 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
538 
539 void
debugfs_create_u32(const char * name,umode_t mode,struct dentry * parent,uint32_t * value)540 debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
541 {
542 
543 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
544 	    &fops_u32_ro, &fops_u32_wo);
545 }
546 
547 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
548 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
549 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
550 
551 void
debugfs_create_x32(const char * name,umode_t mode,struct dentry * parent,uint32_t * value)552 debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
553 {
554 
555 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
556 	    &fops_x32_ro, &fops_x32_wo);
557 }
558 
559 
560 static int
debugfs_u64_get(void * data,uint64_t * value)561 debugfs_u64_get(void *data, uint64_t *value)
562 {
563 	uint64_t *u64data = data;
564 	*value = *u64data;
565 	return (0);
566 }
567 
568 static int
debugfs_u64_set(void * data,uint64_t value)569 debugfs_u64_set(void *data, uint64_t value)
570 {
571 	uint64_t *u64data = data;
572 	*u64data = (uint64_t)value;
573 	return (0);
574 }
575 
576 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
577 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
578 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
579 
580 void
debugfs_create_u64(const char * name,umode_t mode,struct dentry * parent,uint64_t * value)581 debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
582 {
583 
584 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
585 	    &fops_u64_ro, &fops_u64_wo);
586 }
587 
588 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
589 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
590 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
591 
592 void
debugfs_create_x64(const char * name,umode_t mode,struct dentry * parent,uint64_t * value)593 debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
594 {
595 
596 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
597 	    &fops_x64_ro, &fops_x64_wo);
598 }
599 
600 
601 static int
debugfs_ulong_get(void * data,uint64_t * value)602 debugfs_ulong_get(void *data, uint64_t *value)
603 {
604 	uint64_t *uldata = data;
605 	*value = *uldata;
606 	return (0);
607 }
608 
609 static int
debugfs_ulong_set(void * data,uint64_t value)610 debugfs_ulong_set(void *data, uint64_t value)
611 {
612 	uint64_t *uldata = data;
613 	*uldata = value;
614 	return (0);
615 }
616 
617 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
618 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
619 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
620 
621 void
debugfs_create_ulong(const char * name,umode_t mode,struct dentry * parent,unsigned long * value)622 debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
623 {
624 
625 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
626 	    &fops_ulong_ro, &fops_ulong_wo);
627 }
628 
629 
630 static int
debugfs_atomic_t_get(void * data,uint64_t * value)631 debugfs_atomic_t_get(void *data, uint64_t *value)
632 {
633 	atomic_t *atomic_data = data;
634 	*value = atomic_read(atomic_data);
635 	return (0);
636 }
637 
638 static int
debugfs_atomic_t_set(void * data,uint64_t value)639 debugfs_atomic_t_set(void *data, uint64_t value)
640 {
641 	atomic_t *atomic_data = data;
642 	atomic_set(atomic_data, (int)value);
643 	return (0);
644 }
645 
646 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
647 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
648 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
649 
650 void
debugfs_create_atomic_t(const char * name,umode_t mode,struct dentry * parent,atomic_t * value)651 debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
652 {
653 
654 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
655 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
656 }
657 
658 
659 static int
fops_str_open(struct inode * inode,struct file * filp)660 fops_str_open(struct inode *inode, struct file *filp)
661 {
662 
663 	return (simple_open(inode, filp));
664 }
665 
666 static ssize_t
fops_str_read(struct file * filp,char __user * ubuf,size_t read_size,loff_t * ppos)667 fops_str_read(struct file *filp, char __user *ubuf, size_t read_size,
668     loff_t *ppos)
669 {
670 	ssize_t ret;
671 	char *str, *str_with_newline;
672 	size_t str_len, str_with_newline_len;
673 
674 	if (filp->private_data == NULL)
675 		return (-EINVAL);
676 
677 	str = *(char **)filp->private_data;
678 	str_len = strlen(str);
679 
680 	/*
681 	 * `str_with_newline` is terminated with a newline, but is not
682 	 * NUL-terminated.
683 	 */
684 	str_with_newline_len = str_len + 1;
685 	str_with_newline = kmalloc(str_with_newline_len, GFP_KERNEL);
686 	if (str_with_newline == NULL)
687 		return (-ENOMEM);
688 
689 	strncpy(str_with_newline, str, str_len);
690 	str_with_newline[str_len] = '\n';
691 
692 	ret = simple_read_from_buffer(ubuf, read_size, ppos,
693 	    str_with_newline, str_with_newline_len);
694 
695 	kfree(str_with_newline);
696 
697 	return (ret);
698 }
699 
700 static ssize_t
fops_str_write(struct file * filp,const char __user * buf,size_t write_size,loff_t * ppos)701 fops_str_write(struct file *filp, const char __user *buf, size_t write_size,
702     loff_t *ppos)
703 {
704 	char *old, *new;
705 	size_t old_len, new_len;
706 
707 	if (filp->private_data == NULL)
708 		return (-EINVAL);
709 
710 	old = *(char **)filp->private_data;
711 	new = NULL;
712 
713 	/*
714 	 * We enforce concatenation of the newly written value to the existing
715 	 * value.
716 	 */
717 	old_len = strlen(old);
718 	if (*ppos && *ppos != old_len)
719 		return (-EINVAL);
720 
721 	new_len = old_len + write_size;
722 	if (new_len + 1 > PAGE_SIZE)
723 		return (-E2BIG);
724 
725 	new = kmalloc(new_len + 1, GFP_KERNEL);
726 	if (new == NULL)
727 		return (-ENOMEM);
728 
729 	memcpy(new, old, old_len);
730 	if (copy_from_user(new + old_len, buf, write_size) != 0) {
731 		kfree(new);
732 		return (-EFAULT);
733 	}
734 
735 	new[new_len] = '\0';
736 	strim(new);
737 
738 	filp->private_data = &new;
739 
740 	kfree(old);
741 
742 	return (write_size);
743 }
744 
745 static const struct file_operations fops_str = {
746 	.owner = THIS_MODULE,
747 	.open = fops_str_open,
748 	.read = fops_str_read,
749 	.write = fops_str_write,
750 	.llseek = no_llseek
751 };
752 static const struct file_operations fops_str_ro = {
753 	.owner = THIS_MODULE,
754 	.open = fops_str_open,
755 	.read = fops_str_read,
756 	.llseek = no_llseek
757 };
758 static const struct file_operations fops_str_wo = {
759 	.owner = THIS_MODULE,
760 	.open = fops_str_open,
761 	.write = fops_str_write,
762 	.llseek = no_llseek
763 };
764 
765 void
debugfs_create_str(const char * name,umode_t mode,struct dentry * parent,char ** value)766 debugfs_create_str(const char *name, umode_t mode, struct dentry *parent,
767     char **value)
768 {
769 	debugfs_create_mode_unsafe(name, mode, parent, value,
770 	    &fops_str, &fops_str_ro, &fops_str_wo);
771 }
772 
773 
774 static ssize_t
fops_blob_read(struct file * filp,char __user * ubuf,size_t read_size,loff_t * ppos)775 fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
776 {
777 	struct debugfs_blob_wrapper *blob;
778 
779 	blob = filp->private_data;
780 	if (blob == NULL)
781 		return (-EINVAL);
782 	if (blob->size == 0 || blob->data == NULL)
783 		return (-EINVAL);
784 
785 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
786 }
787 
788 static int
fops_blob_open(struct inode * inode,struct file * filp)789 fops_blob_open(struct inode *inode, struct file *filp)
790 {
791 
792 	return (simple_open(inode, filp));
793 }
794 
795 static const struct file_operations __fops_blob_ro = {
796 	.owner = THIS_MODULE,
797 	.open = fops_blob_open,
798 	.read = fops_blob_read,
799 	.llseek = no_llseek
800 };
801 
802 struct dentry *
debugfs_create_blob(const char * name,umode_t mode,struct dentry * parent,struct debugfs_blob_wrapper * value)803 debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
804     struct debugfs_blob_wrapper *value)
805 {
806 	/* Blobs are read-only. */
807 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
808 }
809 
810 
811 static int
lindebugfs_init(PFS_INIT_ARGS)812 lindebugfs_init(PFS_INIT_ARGS)
813 {
814 
815 	debugfs_root = pi->pi_root;
816 
817 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
818 
819 	return (0);
820 }
821 
822 static int
lindebugfs_uninit(PFS_INIT_ARGS)823 lindebugfs_uninit(PFS_INIT_ARGS)
824 {
825 
826 	return (0);
827 }
828 
829 PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
830 MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
831