xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision f374ba41)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/queue.h>
35 #include <sys/blist.h>
36 #include <sys/conf.h>
37 #include <sys/exec.h>
38 #include <sys/filedesc.h>
39 #include <sys/kernel.h>
40 #include <sys/linker.h>
41 #include <sys/malloc.h>
42 #include <sys/mount.h>
43 #include <sys/mutex.h>
44 #include <sys/proc.h>
45 #include <sys/resourcevar.h>
46 #include <sys/sbuf.h>
47 #include <sys/smp.h>
48 #include <sys/socket.h>
49 #include <sys/vnode.h>
50 #include <sys/bus.h>
51 #include <sys/pciio.h>
52 
53 #include <dev/pci/pcivar.h>
54 #include <dev/pci/pcireg.h>
55 
56 #include <net/if.h>
57 
58 #include <vm/vm.h>
59 #include <vm/pmap.h>
60 #include <vm/vm_map.h>
61 #include <vm/vm_param.h>
62 #include <vm/vm_object.h>
63 #include <vm/swap_pager.h>
64 
65 #include <machine/bus.h>
66 
67 #include <compat/linux/linux_ioctl.h>
68 #include <compat/linux/linux_mib.h>
69 #include <compat/linux/linux_util.h>
70 #include <fs/pseudofs/pseudofs.h>
71 
72 #include <asm/atomic.h>
73 #include <linux/compat.h>
74 #include <linux/debugfs.h>
75 #include <linux/fs.h>
76 
77 MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
78 
79 static struct pfs_node *debugfs_root;
80 
81 #define DM_SYMLINK 0x1
82 #define DM_DIR 0x2
83 #define DM_FILE 0x3
84 
85 struct dentry_meta {
86 	struct dentry dm_dnode;
87 	const struct file_operations *dm_fops;
88 	void *dm_data;
89 	umode_t dm_mode;
90 	int dm_type;
91 };
92 
93 static int
94 debugfs_attr(PFS_ATTR_ARGS)
95 {
96 	struct dentry_meta *dm;
97 
98 	dm = pn->pn_data;
99 
100 	vap->va_mode = dm->dm_mode;
101 	return (0);
102 }
103 
104 static int
105 debugfs_destroy(PFS_DESTROY_ARGS)
106 {
107 	struct dentry_meta *dm;
108 
109 	dm = pn->pn_data;
110 	if (dm->dm_type == DM_SYMLINK)
111 		free(dm->dm_data, M_DFSINT);
112 
113 	free(dm, M_DFSINT);
114 	return (0);
115 }
116 
117 static int
118 debugfs_fill(PFS_FILL_ARGS)
119 {
120 	struct dentry_meta *d;
121 	struct linux_file lf = {};
122 	struct vnode vn;
123 	char *buf;
124 	int rc;
125 	off_t off = 0;
126 
127 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
128 		return (rc);
129 
130 	d = pn->pn_data;
131 	vn.v_data = d->dm_data;
132 
133 	rc = d->dm_fops->open(&vn, &lf);
134 	if (rc < 0) {
135 #ifdef INVARIANTS
136 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
137 #endif
138 		return (-rc);
139 	}
140 
141 	rc = -ENODEV;
142 	if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
143 		rc = -ENOMEM;
144 		buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
145 		if (buf != NULL) {
146 			rc = d->dm_fops->read(&lf, buf, sb->s_size, &off);
147 			if (rc > 0)
148 				sbuf_bcpy(sb, buf, strlen(buf));
149 
150 			free(buf, M_DFSINT);
151 		}
152 	} else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
153 		sbuf_finish(sb);
154 		rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
155 	}
156 
157 	if (d->dm_fops->release)
158 		d->dm_fops->release(&vn, &lf);
159 	else
160 		single_release(&vn, &lf);
161 
162 	if (rc < 0) {
163 #ifdef INVARIANTS
164 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
165 #endif
166 		return (-rc);
167 	}
168 	return (0);
169 }
170 
171 static int
172 debugfs_fill_data(PFS_FILL_ARGS)
173 {
174 	struct dentry_meta *dm;
175 
176 	dm = pn->pn_data;
177 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
178 	return (0);
179 }
180 
181 struct dentry *
182 debugfs_create_file(const char *name, umode_t mode,
183     struct dentry *parent, void *data,
184     const struct file_operations *fops)
185 {
186 	struct dentry_meta *dm;
187 	struct dentry *dnode;
188 	struct pfs_node *pnode;
189 	int flags;
190 
191 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
192 	if (dm == NULL)
193 		return (NULL);
194 	dnode = &dm->dm_dnode;
195 	dm->dm_fops = fops;
196 	dm->dm_data = data;
197 	dm->dm_mode = mode;
198 	dm->dm_type = DM_FILE;
199 	if (parent != NULL)
200 		pnode = parent->d_pfs_node;
201 	else
202 		pnode = debugfs_root;
203 
204 	flags = fops->write ? PFS_RDWR : PFS_RD;
205 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
206 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
207 	if (dnode->d_pfs_node == NULL) {
208 		free(dm, M_DFSINT);
209 		return (NULL);
210 	}
211 	dnode->d_pfs_node->pn_data = dm;
212 
213 	return (dnode);
214 }
215 
216 struct dentry *
217 debugfs_create_file_size(const char *name, umode_t mode,
218     struct dentry *parent, void *data,
219     const struct file_operations *fops,
220     loff_t file_size __unused)
221 {
222 
223 	return debugfs_create_file(name, mode, parent, data, fops);
224 }
225 
226 /*
227  * NOTE: Files created with the _unsafe moniker will not be protected from
228  * debugfs core file removals. It is the responsibility of @fops to protect
229  * its file using debugfs_file_get() and debugfs_file_put().
230  *
231  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
232  * of writing. Therefore there is no difference between functions with _unsafe
233  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
234  * exist only for Linux compatibility.
235  */
236 struct dentry *
237 debugfs_create_file_unsafe(const char *name, umode_t mode,
238     struct dentry *parent, void *data,
239     const struct file_operations *fops)
240 {
241 
242 	return (debugfs_create_file(name, mode, parent, data, fops));
243 }
244 
245 struct dentry *
246 debugfs_create_mode_unsafe(const char *name, umode_t mode,
247     struct dentry *parent, void *data,
248     const struct file_operations *fops,
249     const struct file_operations *fops_ro,
250     const struct file_operations *fops_wo)
251 {
252 	umode_t read = mode & S_IRUGO;
253 	umode_t write = mode & S_IWUGO;
254 
255 	if (read && !write)
256 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
257 
258 	if (write && !read)
259 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
260 
261 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
262 }
263 
264 struct dentry *
265 debugfs_create_dir(const char *name, struct dentry *parent)
266 {
267 	struct dentry_meta *dm;
268 	struct dentry *dnode;
269 	struct pfs_node *pnode;
270 
271 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
272 	if (dm == NULL)
273 		return (NULL);
274 	dnode = &dm->dm_dnode;
275 	dm->dm_mode = 0700;
276 	dm->dm_type = DM_DIR;
277 	if (parent != NULL)
278 		pnode = parent->d_pfs_node;
279 	else
280 		pnode = debugfs_root;
281 
282 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
283 	if (dnode->d_pfs_node == NULL) {
284 		free(dm, M_DFSINT);
285 		return (NULL);
286 	}
287 	dnode->d_pfs_node->pn_data = dm;
288 	return (dnode);
289 }
290 
291 struct dentry *
292 debugfs_create_symlink(const char *name, struct dentry *parent,
293     const char *dest)
294 {
295 	struct dentry_meta *dm;
296 	struct dentry *dnode;
297 	struct pfs_node *pnode;
298 	void *data;
299 
300 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
301 	if (data == NULL)
302 		return (NULL);
303 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
304 	if (dm == NULL)
305 		goto fail1;
306 	dnode = &dm->dm_dnode;
307 	dm->dm_mode = 0700;
308 	dm->dm_type = DM_SYMLINK;
309 	dm->dm_data = data;
310 	if (parent != NULL)
311 		pnode = parent->d_pfs_node;
312 	else
313 		pnode = debugfs_root;
314 
315 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
316 	if (dnode->d_pfs_node == NULL)
317 		goto fail;
318 	dnode->d_pfs_node->pn_data = dm;
319 	return (dnode);
320  fail:
321 	free(dm, M_DFSINT);
322  fail1:
323 	free(data, M_DFSINT);
324 	return (NULL);
325 }
326 
327 void
328 debugfs_remove(struct dentry *dnode)
329 {
330 	if (dnode == NULL)
331 		return;
332 
333 	pfs_destroy(dnode->d_pfs_node);
334 }
335 
336 void
337 debugfs_remove_recursive(struct dentry *dnode)
338 {
339 	if (dnode == NULL)
340 		return;
341 
342 	pfs_destroy(dnode->d_pfs_node);
343 }
344 
345 static int
346 debugfs_bool_get(void *data, uint64_t *ullval)
347 {
348 	bool *bval = data;
349 
350 	if (*bval)
351 		*ullval = 1;
352 	else
353 		*ullval = 0;
354 
355 	return (0);
356 }
357 
358 static int
359 debugfs_bool_set(void *data, uint64_t ullval)
360 {
361 	bool *bval = data;
362 
363 	if (ullval)
364 		*bval = 1;
365 	else
366 		*bval = 0;
367 
368 	return (0);
369 }
370 
371 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
372 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
373 DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
374 
375 void
376 debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
377 {
378 
379 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
380 	    &fops_bool_ro, &fops_bool_wo);
381 }
382 
383 
384 static int
385 debugfs_u8_get(void *data, uint64_t *value)
386 {
387 	uint8_t *u8data = data;
388 	*value = *u8data;
389 	return (0);
390 }
391 
392 static int
393 debugfs_u8_set(void *data, uint64_t value)
394 {
395 	uint8_t *u8data = data;
396 	*u8data = (uint8_t)value;
397 	return (0);
398 }
399 
400 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
401 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
402 DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
403 
404 void
405 debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
406 {
407 
408 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
409 	    &fops_u8_ro, &fops_u8_wo);
410 }
411 
412 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
413 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
414 DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
415 
416 void
417 debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
418 {
419 
420 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
421 	    &fops_x8_ro, &fops_x8_wo);
422 }
423 
424 
425 static int
426 debugfs_u16_get(void *data, uint64_t *value)
427 {
428 	uint16_t *u16data = data;
429 	*value = *u16data;
430 	return (0);
431 }
432 
433 static int
434 debugfs_u16_set(void *data, uint64_t value)
435 {
436 	uint16_t *u16data = data;
437 	*u16data = (uint16_t)value;
438 	return (0);
439 }
440 
441 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
442 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
443 DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
444 
445 void
446 debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
447 {
448 
449 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
450 	    &fops_u16_ro, &fops_u16_wo);
451 }
452 
453 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
454 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
455 DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
456 
457 void
458 debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
459 {
460 
461 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
462 	    &fops_x16_ro, &fops_x16_wo);
463 }
464 
465 
466 static int
467 debugfs_u32_get(void *data, uint64_t *value)
468 {
469 	uint32_t *u32data = data;
470 	*value = *u32data;
471 	return (0);
472 }
473 
474 static int
475 debugfs_u32_set(void *data, uint64_t value)
476 {
477 	uint32_t *u32data = data;
478 	*u32data = (uint32_t)value;
479 	return (0);
480 }
481 
482 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
483 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
484 DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
485 
486 void
487 debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
488 {
489 
490 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
491 	    &fops_u32_ro, &fops_u32_wo);
492 }
493 
494 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
495 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
496 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
497 
498 void
499 debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
500 {
501 
502 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
503 	    &fops_x32_ro, &fops_x32_wo);
504 }
505 
506 
507 static int
508 debugfs_u64_get(void *data, uint64_t *value)
509 {
510 	uint64_t *u64data = data;
511 	*value = *u64data;
512 	return (0);
513 }
514 
515 static int
516 debugfs_u64_set(void *data, uint64_t value)
517 {
518 	uint64_t *u64data = data;
519 	*u64data = (uint64_t)value;
520 	return (0);
521 }
522 
523 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
524 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
525 DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
526 
527 void
528 debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
529 {
530 
531 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
532 	    &fops_u64_ro, &fops_u64_wo);
533 }
534 
535 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
536 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
537 DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
538 
539 void
540 debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
541 {
542 
543 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
544 	    &fops_x64_ro, &fops_x64_wo);
545 }
546 
547 
548 static int
549 debugfs_ulong_get(void *data, uint64_t *value)
550 {
551 	uint64_t *uldata = data;
552 	*value = *uldata;
553 	return (0);
554 }
555 
556 static int
557 debugfs_ulong_set(void *data, uint64_t value)
558 {
559 	uint64_t *uldata = data;
560 	*uldata = value;
561 	return (0);
562 }
563 
564 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
565 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
566 DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
567 
568 void
569 debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
570 {
571 
572 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
573 	    &fops_ulong_ro, &fops_ulong_wo);
574 }
575 
576 
577 static int
578 debugfs_atomic_t_get(void *data, uint64_t *value)
579 {
580 	atomic_t *atomic_data = data;
581 	*value = atomic_read(atomic_data);
582 	return (0);
583 }
584 
585 static int
586 debugfs_atomic_t_set(void *data, uint64_t value)
587 {
588 	atomic_t *atomic_data = data;
589 	atomic_set(atomic_data, (int)value);
590 	return (0);
591 }
592 
593 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
594 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
595 DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
596 
597 void
598 debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
599 {
600 
601 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
602 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
603 }
604 
605 
606 static ssize_t
607 fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
608 {
609 	struct debugfs_blob_wrapper *blob;
610 
611 	blob = filp->private_data;
612 	if (blob == NULL)
613 		return (-EINVAL);
614 	if (blob->size == 0 || blob->data == NULL)
615 		return (-EINVAL);
616 
617 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
618 }
619 
620 static int
621 fops_blob_open(struct inode *inode, struct file *filp)
622 {
623 
624 	return (simple_open(inode, filp));
625 }
626 
627 static const struct file_operations __fops_blob_ro = {
628 	.owner = THIS_MODULE,
629 	.open = fops_blob_open,
630 	.read = fops_blob_read,
631 	.llseek = no_llseek
632 };
633 
634 struct dentry *
635 debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
636     struct debugfs_blob_wrapper *value)
637 {
638 	/* Blobs are read-only. */
639 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
640 }
641 
642 
643 static int
644 lindebugfs_init(PFS_INIT_ARGS)
645 {
646 
647 	debugfs_root = pi->pi_root;
648 
649 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
650 
651 	return (0);
652 }
653 
654 static int
655 lindebugfs_uninit(PFS_INIT_ARGS)
656 {
657 
658 	return (0);
659 }
660 
661 PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
662 MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
663