summaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
Diffstat (limited to 'samples')
-rw-r--r--samples/Kconfig21
-rw-r--r--samples/Makefile3
-rw-r--r--samples/bpf/Makefile4
-rw-r--r--samples/bpf/sockex2_kern.c1
-rwxr-xr-xsamples/check-exec/run-script-ask.sh (renamed from samples/check-exec/run-script-ask.inc)0
-rw-r--r--samples/connector/cn_test.c2
-rw-r--r--samples/damon/Kconfig17
-rw-r--r--samples/damon/Makefile1
-rw-r--r--samples/damon/mtier.c178
-rw-r--r--samples/damon/prcl.c2
-rw-r--r--samples/ftrace/sample-trace-array.c4
-rw-r--r--samples/hung_task/Makefile2
-rw-r--r--samples/hung_task/hung_task_tests.c97
-rw-r--r--samples/kmemleak/kmemleak-test.c36
-rw-r--r--samples/landlock/sandboxer.c37
-rw-r--r--samples/livepatch/livepatch-callbacks-busymod.c1
-rw-r--r--samples/livepatch/livepatch-callbacks-demo.c1
-rw-r--r--samples/livepatch/livepatch-callbacks-mod.c1
-rw-r--r--samples/livepatch/livepatch-sample.c1
-rw-r--r--samples/livepatch/livepatch-shadow-fix1.c1
-rw-r--r--samples/livepatch/livepatch-shadow-fix2.c1
-rw-r--r--samples/rust/Kconfig34
-rw-r--r--samples/rust/Makefile3
-rw-r--r--samples/rust/rust_configfs.rs192
-rw-r--r--samples/rust/rust_dma.rs97
-rw-r--r--samples/rust/rust_driver_auxiliary.rs120
-rw-r--r--samples/rust/rust_driver_faux.rs4
-rw-r--r--samples/rust/rust_driver_pci.rs27
-rw-r--r--samples/rust/rust_driver_platform.rs13
-rw-r--r--samples/rust/rust_minimal.rs2
-rw-r--r--samples/rust/rust_misc_device.rs183
-rw-r--r--samples/rust/rust_print_main.rs2
-rw-r--r--samples/trace_events/trace-events-sample.h8
-rw-r--r--samples/tsm-mr/Makefile2
-rw-r--r--samples/tsm-mr/tsm_mr_sample.c131
-rw-r--r--samples/vfs/samples-vfs.h14
-rw-r--r--samples/vfs/test-list-all-mounts.c35
37 files changed, 1125 insertions, 153 deletions
diff --git a/samples/Kconfig b/samples/Kconfig
index 820e00b2ed68..ffef99950206 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -184,6 +184,17 @@ config SAMPLE_TIMER
bool "Timer sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
+config SAMPLE_TSM_MR
+ tristate "TSM measurement sample"
+ select TSM_MEASUREMENTS
+ select VIRT_DRIVERS
+ help
+ Build a sample module that emulates MRs (Measurement Registers) and
+ exposes them to user mode applications through the TSM sysfs
+ interface (/sys/class/misc/tsm_mr_sample/emulated_mr/).
+
+ The module name will be tsm-mr-sample when built as a module.
+
config SAMPLE_UHID
bool "UHID sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
@@ -300,6 +311,16 @@ config SAMPLE_CHECK_EXEC
demonstrate how they should be used with execveat(2) +
AT_EXECVE_CHECK.
+config SAMPLE_HUNG_TASK
+ tristate "Hung task detector test code"
+ depends on DETECT_HUNG_TASK && DEBUG_FS
+ help
+ Build a module that provides debugfs files (e.g., mutex, semaphore,
+ etc.) under <debugfs>/hung_task. If user reads one of these files,
+ it will sleep long time (256 seconds) with holding a lock. Thus,
+ if 2 or more processes read the same file concurrently, it will
+ be detected by the hung_task watchdog.
+
source "samples/rust/Kconfig"
source "samples/damon/Kconfig"
diff --git a/samples/Makefile b/samples/Makefile
index f24cd0d72dd0..07641e177bd8 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -42,3 +42,6 @@ obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/
obj-$(CONFIG_SAMPLES_RUST) += rust/
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/
+obj-$(CONFIG_SAMPLE_DAMON_MTIER) += damon/
+obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task/
+obj-$(CONFIG_SAMPLE_TSM_MR) += tsm-mr/
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index dd9944a97b7e..95a4fa1f1e44 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -307,7 +307,7 @@ $(obj)/$(TRACE_HELPERS): TPROGS_CFLAGS := $(TPROGS_CFLAGS) -D__must_check=
VMLINUX_BTF_PATHS ?= $(abspath $(if $(O),$(O)/vmlinux)) \
$(abspath $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux)) \
- $(abspath ./vmlinux)
+ $(abspath $(objtree)/vmlinux)
VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
$(obj)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL)
@@ -376,7 +376,7 @@ $(obj)/%.o: $(src)/%.c
@echo " CLANG-bpf " $@
$(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \
-I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \
- -I$(LIBBPF_INCLUDE) \
+ -I$(LIBBPF_INCLUDE) $(CLANG_SYS_INCLUDES) \
-D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \
-D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
diff --git a/samples/bpf/sockex2_kern.c b/samples/bpf/sockex2_kern.c
index b7997541f7ee..f93d9145ab8a 100644
--- a/samples/bpf/sockex2_kern.c
+++ b/samples/bpf/sockex2_kern.c
@@ -31,7 +31,6 @@ static inline int proto_ports_offset(__u64 proto)
switch (proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
- case IPPROTO_DCCP:
case IPPROTO_ESP:
case IPPROTO_SCTP:
case IPPROTO_UDPLITE:
diff --git a/samples/check-exec/run-script-ask.inc b/samples/check-exec/run-script-ask.sh
index 8ef0fdc37266..8ef0fdc37266 100755
--- a/samples/check-exec/run-script-ask.inc
+++ b/samples/check-exec/run-script-ask.sh
diff --git a/samples/connector/cn_test.c b/samples/connector/cn_test.c
index 0958a171d048..73d50b4aebb6 100644
--- a/samples/connector/cn_test.c
+++ b/samples/connector/cn_test.c
@@ -172,7 +172,7 @@ static int cn_test_init(void)
static void cn_test_fini(void)
{
- del_timer_sync(&cn_test_timer);
+ timer_delete_sync(&cn_test_timer);
cn_del_callback(&cn_test_id);
cn_test_id.val--;
cn_del_callback(&cn_test_id);
diff --git a/samples/damon/Kconfig b/samples/damon/Kconfig
index 63f6dcd71daa..cbf96fd8a8bf 100644
--- a/samples/damon/Kconfig
+++ b/samples/damon/Kconfig
@@ -3,7 +3,7 @@
menu "DAMON Samples"
config SAMPLE_DAMON_WSSE
- bool "DAMON sameple module for working set size estimation"
+ bool "DAMON sample module for working set size estimation"
depends on DAMON && DAMON_VADDR
help
This builds DAMON sample module for working set size estimation.
@@ -15,7 +15,7 @@ config SAMPLE_DAMON_WSSE
If unsure, say N.
config SAMPLE_DAMON_PRCL
- bool "DAMON sameple module for access-aware proactive reclamation"
+ bool "DAMON sample module for access-aware proactive reclamation"
depends on DAMON && DAMON_VADDR
help
This builds DAMON sample module for access-aware proactive
@@ -27,4 +27,17 @@ config SAMPLE_DAMON_PRCL
If unsure, say N.
+config SAMPLE_DAMON_MTIER
+ bool "DAMON sample module for memory tiering"
+ depends on DAMON && DAMON_PADDR
+ help
+ Thps builds DAMON sample module for memory tierign.
+
+ The module assumes the system is constructed with two NUMA nodes,
+ which seems as local and remote nodes to all CPUs. For example,
+ node0 is for DDR5 DRAMs connected via DIMM, while node1 is for DDR4
+ DRAMs connected via CXL.
+
+ If unsure, say N.
+
endmenu
diff --git a/samples/damon/Makefile b/samples/damon/Makefile
index 7f155143f237..72f68cbf422a 100644
--- a/samples/damon/Makefile
+++ b/samples/damon/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += wsse.o
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += prcl.o
+obj-$(CONFIG_SAMPLE_DAMON_MTIER) += mtier.o
diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c
new file mode 100644
index 000000000000..36d2cd933f5a
--- /dev/null
+++ b/samples/damon/mtier.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * memory tiering: migrate cold pages in node 0 and hot pages in node 1 to node
+ * 1 and node 0, respectively. Adjust the hotness/coldness threshold aiming
+ * resulting 99.6 % node 0 utilization ratio.
+ */
+
+#define pr_fmt(fmt) "damon_sample_mtier: " fmt
+
+#include <linux/damon.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+static unsigned long node0_start_addr __read_mostly;
+module_param(node0_start_addr, ulong, 0600);
+
+static unsigned long node0_end_addr __read_mostly;
+module_param(node0_end_addr, ulong, 0600);
+
+static unsigned long node1_start_addr __read_mostly;
+module_param(node1_start_addr, ulong, 0600);
+
+static unsigned long node1_end_addr __read_mostly;
+module_param(node1_end_addr, ulong, 0600);
+
+static int damon_sample_mtier_enable_store(
+ const char *val, const struct kernel_param *kp);
+
+static const struct kernel_param_ops enable_param_ops = {
+ .set = damon_sample_mtier_enable_store,
+ .get = param_get_bool,
+};
+
+static bool enable __read_mostly;
+module_param_cb(enable, &enable_param_ops, &enable, 0600);
+MODULE_PARM_DESC(enable, "Enable of disable DAMON_SAMPLE_MTIER");
+
+static struct damon_ctx *ctxs[2];
+
+static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)
+{
+ struct damon_ctx *ctx;
+ struct damon_attrs attrs;
+ struct damon_target *target;
+ struct damon_region *region;
+ struct damos *scheme;
+ struct damos_quota_goal *quota_goal;
+ struct damos_filter *filter;
+
+ ctx = damon_new_ctx();
+ if (!ctx)
+ return NULL;
+ attrs = (struct damon_attrs) {
+ .sample_interval = 5 * USEC_PER_MSEC,
+ .aggr_interval = 100 * USEC_PER_MSEC,
+ .ops_update_interval = 60 * USEC_PER_MSEC * MSEC_PER_SEC,
+ .min_nr_regions = 10,
+ .max_nr_regions = 1000,
+ };
+
+ /*
+ * auto-tune sampling and aggregation interval aiming 4% DAMON-observed
+ * accesses ratio, keeping sampling interval in [5ms, 10s] range.
+ */
+ attrs.intervals_goal = (struct damon_intervals_goal) {
+ .access_bp = 400, .aggrs = 3,
+ .min_sample_us = 5000, .max_sample_us = 10000000,
+ };
+ if (damon_set_attrs(ctx, &attrs))
+ goto free_out;
+ if (damon_select_ops(ctx, DAMON_OPS_PADDR))
+ goto free_out;
+
+ target = damon_new_target();
+ if (!target)
+ goto free_out;
+ damon_add_target(ctx, target);
+ region = damon_new_region(
+ promote ? node1_start_addr : node0_start_addr,
+ promote ? node1_end_addr : node0_end_addr);
+ if (!region)
+ goto free_out;
+ damon_add_region(region, target);
+
+ scheme = damon_new_scheme(
+ /* access pattern */
+ &(struct damos_access_pattern) {
+ .min_sz_region = PAGE_SIZE,
+ .max_sz_region = ULONG_MAX,
+ .min_nr_accesses = promote ? 1 : 0,
+ .max_nr_accesses = promote ? UINT_MAX : 0,
+ .min_age_region = 0,
+ .max_age_region = UINT_MAX},
+ /* action */
+ promote ? DAMOS_MIGRATE_HOT : DAMOS_MIGRATE_COLD,
+ 1000000, /* apply interval (1s) */
+ &(struct damos_quota){
+ /* 200 MiB per sec by most */
+ .reset_interval = 1000,
+ .sz = 200 * 1024 * 1024,
+ /* ignore size of region when prioritizing */
+ .weight_sz = 0,
+ .weight_nr_accesses = 100,
+ .weight_age = 100,
+ },
+ &(struct damos_watermarks){},
+ promote ? 0 : 1); /* migrate target node id */
+ if (!scheme)
+ goto free_out;
+ damon_set_schemes(ctx, &scheme, 1);
+ quota_goal = damos_new_quota_goal(
+ promote ? DAMOS_QUOTA_NODE_MEM_USED_BP :
+ DAMOS_QUOTA_NODE_MEM_FREE_BP,
+ promote ? 9970 : 50);
+ if (!quota_goal)
+ goto free_out;
+ quota_goal->nid = 0;
+ damos_add_quota_goal(&scheme->quota, quota_goal);
+ filter = damos_new_filter(DAMOS_FILTER_TYPE_YOUNG, true, promote);
+ if (!filter)
+ goto free_out;
+ damos_add_filter(scheme, filter);
+ return ctx;
+free_out:
+ damon_destroy_ctx(ctx);
+ return NULL;
+}
+
+static int damon_sample_mtier_start(void)
+{
+ struct damon_ctx *ctx;
+
+ ctx = damon_sample_mtier_build_ctx(true);
+ if (!ctx)
+ return -ENOMEM;
+ ctxs[0] = ctx;
+ ctx = damon_sample_mtier_build_ctx(false);
+ if (!ctx) {
+ damon_destroy_ctx(ctxs[0]);
+ return -ENOMEM;
+ }
+ ctxs[1] = ctx;
+ return damon_start(ctxs, 2, true);
+}
+
+static void damon_sample_mtier_stop(void)
+{
+ damon_stop(ctxs, 2);
+ damon_destroy_ctx(ctxs[0]);
+ damon_destroy_ctx(ctxs[1]);
+}
+
+static int damon_sample_mtier_enable_store(
+ const char *val, const struct kernel_param *kp)
+{
+ bool enabled = enable;
+ int err;
+
+ err = kstrtobool(val, &enable);
+ if (err)
+ return err;
+
+ if (enable == enabled)
+ return 0;
+
+ if (enable)
+ return damon_sample_mtier_start();
+ damon_sample_mtier_stop();
+ return 0;
+}
+
+static int __init damon_sample_mtier_init(void)
+{
+ return 0;
+}
+
+module_init(damon_sample_mtier_init);
diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c
index c3acbdab7a62..056b1b21a0fe 100644
--- a/samples/damon/prcl.c
+++ b/samples/damon/prcl.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* proactive reclamation: monitor access pattern of a given process, find
- * regiosn that seems not accessed, and proactively page out the regions.
+ * regions that seems not accessed, and proactively page out the regions.
*/
#define pr_fmt(fmt) "damon_sample_prcl: " fmt
diff --git a/samples/ftrace/sample-trace-array.c b/samples/ftrace/sample-trace-array.c
index d0ee9001c7b3..4147616102f9 100644
--- a/samples/ftrace/sample-trace-array.c
+++ b/samples/ftrace/sample-trace-array.c
@@ -82,7 +82,7 @@ static int simple_thread(void *arg)
while (!kthread_should_stop())
simple_thread_func(count++);
- del_timer(&mytimer);
+ timer_delete(&mytimer);
cancel_work_sync(&trace_work);
/*
@@ -112,7 +112,7 @@ static int __init sample_trace_array_init(void)
/*
* If context specific per-cpu buffers havent already been allocated.
*/
- trace_printk_init_buffers();
+ trace_array_init_printk(tr);
simple_tsk = kthread_run(simple_thread, NULL, "sample-instance");
if (IS_ERR(simple_tsk)) {
diff --git a/samples/hung_task/Makefile b/samples/hung_task/Makefile
new file mode 100644
index 000000000000..86036f1a204d
--- /dev/null
+++ b/samples/hung_task/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task_tests.o
diff --git a/samples/hung_task/hung_task_tests.c b/samples/hung_task/hung_task_tests.c
new file mode 100644
index 000000000000..a5c09bd3a47d
--- /dev/null
+++ b/samples/hung_task/hung_task_tests.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * hung_task_tests.c - Sample code for testing hung tasks with mutex,
+ * semaphore, etc.
+ *
+ * Usage: Load this module and read `<debugfs>/hung_task/mutex`,
+ * `<debugfs>/hung_task/semaphore`, etc., with 2 or more processes.
+ *
+ * This is for testing kernel hung_task error messages with various locking
+ * mechanisms (e.g., mutex, semaphore, etc.). Note that this may freeze
+ * your system or cause a panic. Use only for testing purposes.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+#define HUNG_TASK_DIR "hung_task"
+#define HUNG_TASK_MUTEX_FILE "mutex"
+#define HUNG_TASK_SEM_FILE "semaphore"
+#define SLEEP_SECOND 256
+
+static const char dummy_string[] = "This is a dummy string.";
+static DEFINE_MUTEX(dummy_mutex);
+static DEFINE_SEMAPHORE(dummy_sem, 1);
+static struct dentry *hung_task_dir;
+
+/* Mutex-based read function */
+static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ /* Second task waits on mutex, entering uninterruptible sleep */
+ guard(mutex)(&dummy_mutex);
+
+ /* First task sleeps here, interruptible */
+ msleep_interruptible(SLEEP_SECOND * 1000);
+
+ return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
+ sizeof(dummy_string));
+}
+
+/* Semaphore-based read function */
+static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ /* Second task waits on semaphore, entering uninterruptible sleep */
+ down(&dummy_sem);
+
+ /* First task sleeps here, interruptible */
+ msleep_interruptible(SLEEP_SECOND * 1000);
+
+ up(&dummy_sem);
+
+ return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
+ sizeof(dummy_string));
+}
+
+/* File operations for mutex */
+static const struct file_operations hung_task_mutex_fops = {
+ .read = read_dummy_mutex,
+};
+
+/* File operations for semaphore */
+static const struct file_operations hung_task_sem_fops = {
+ .read = read_dummy_semaphore,
+};
+
+static int __init hung_task_tests_init(void)
+{
+ hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL);
+ if (IS_ERR(hung_task_dir))
+ return PTR_ERR(hung_task_dir);
+
+ /* Create debugfs files for mutex and semaphore tests */
+ debugfs_create_file(HUNG_TASK_MUTEX_FILE, 0400, hung_task_dir, NULL,
+ &hung_task_mutex_fops);
+ debugfs_create_file(HUNG_TASK_SEM_FILE, 0400, hung_task_dir, NULL,
+ &hung_task_sem_fops);
+
+ return 0;
+}
+
+static void __exit hung_task_tests_exit(void)
+{
+ debugfs_remove_recursive(hung_task_dir);
+}
+
+module_init(hung_task_tests_init);
+module_exit(hung_task_tests_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Masami Hiramatsu <mhiramat@kernel.org>");
+MODULE_AUTHOR("Zi Li <amaindex@outlook.com>");
+MODULE_DESCRIPTION("Simple sleep under lock files for testing hung task");
diff --git a/samples/kmemleak/kmemleak-test.c b/samples/kmemleak/kmemleak-test.c
index 544c36d51d56..8609812a37eb 100644
--- a/samples/kmemleak/kmemleak-test.c
+++ b/samples/kmemleak/kmemleak-test.c
@@ -40,25 +40,25 @@ static int kmemleak_test_init(void)
pr_info("Kmemleak testing\n");
/* make some orphan objects */
- pr_info("kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL));
- pr_info("kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL));
- pr_info("kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL));
- pr_info("kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL));
- pr_info("kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL));
- pr_info("kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL));
- pr_info("kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL));
- pr_info("kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL));
+ pr_info("kmalloc(32) = 0x%px\n", kmalloc(32, GFP_KERNEL));
+ pr_info("kmalloc(32) = 0x%px\n", kmalloc(32, GFP_KERNEL));
+ pr_info("kmalloc(1024) = 0x%px\n", kmalloc(1024, GFP_KERNEL));
+ pr_info("kmalloc(1024) = 0x%px\n", kmalloc(1024, GFP_KERNEL));
+ pr_info("kmalloc(2048) = 0x%px\n", kmalloc(2048, GFP_KERNEL));
+ pr_info("kmalloc(2048) = 0x%px\n", kmalloc(2048, GFP_KERNEL));
+ pr_info("kmalloc(4096) = 0x%px\n", kmalloc(4096, GFP_KERNEL));
+ pr_info("kmalloc(4096) = 0x%px\n", kmalloc(4096, GFP_KERNEL));
#ifndef CONFIG_MODULES
- pr_info("kmem_cache_alloc(files_cachep) = %p\n",
+ pr_info("kmem_cache_alloc(files_cachep) = 0x%px\n",
kmem_cache_alloc(files_cachep, GFP_KERNEL));
- pr_info("kmem_cache_alloc(files_cachep) = %p\n",
+ pr_info("kmem_cache_alloc(files_cachep) = 0x%px\n",
kmem_cache_alloc(files_cachep, GFP_KERNEL));
#endif
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
/*
* Add elements to a list. They should only appear as orphan
@@ -66,7 +66,7 @@ static int kmemleak_test_init(void)
*/
for (i = 0; i < 10; i++) {
elem = kzalloc(sizeof(*elem), GFP_KERNEL);
- pr_info("kzalloc(sizeof(*elem)) = %p\n", elem);
+ pr_info("kzalloc(sizeof(*elem)) = 0x%px\n", elem);
if (!elem)
return -ENOMEM;
INIT_LIST_HEAD(&elem->list);
@@ -75,11 +75,11 @@ static int kmemleak_test_init(void)
for_each_possible_cpu(i) {
per_cpu(kmemleak_test_pointer, i) = kmalloc(129, GFP_KERNEL);
- pr_info("kmalloc(129) = %p\n",
+ pr_info("kmalloc(129) = 0x%px\n",
per_cpu(kmemleak_test_pointer, i));
}
- pr_info("__alloc_percpu(64, 4) = %p\n", __alloc_percpu(64, 4));
+ pr_info("__alloc_percpu(64, 4) = 0x%px\n", __alloc_percpu(64, 4));
return 0;
}
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index 07fab2ef534e..4e2854c6f9a3 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -58,6 +58,7 @@ static inline int landlock_restrict_self(const int ruleset_fd,
#define ENV_TCP_BIND_NAME "LL_TCP_BIND"
#define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT"
#define ENV_SCOPED_NAME "LL_SCOPED"
+#define ENV_FORCE_LOG_NAME "LL_FORCE_LOG"
#define ENV_DELIMITER ":"
static int str2num(const char *numstr, __u64 *num_dst)
@@ -295,7 +296,7 @@ out_unset:
/* clang-format on */
-#define LANDLOCK_ABI_LAST 6
+#define LANDLOCK_ABI_LAST 7
#define XSTR(s) #s
#define STR(s) XSTR(s)
@@ -322,6 +323,9 @@ static const char help[] =
" - \"a\" to restrict opening abstract unix sockets\n"
" - \"s\" to restrict sending signals\n"
"\n"
+ "A sandboxer should not log denied access requests to avoid spamming logs, "
+ "but to test audit we can set " ENV_FORCE_LOG_NAME "=1\n"
+ "\n"
"Example:\n"
ENV_FS_RO_NAME "=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
ENV_FS_RW_NAME "=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
@@ -340,7 +344,7 @@ int main(const int argc, char *const argv[], char *const *const envp)
const char *cmd_path;
char *const *cmd_argv;
int ruleset_fd, abi;
- char *env_port_name;
+ char *env_port_name, *env_force_log;
__u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ,
access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE;
@@ -351,6 +355,8 @@ int main(const int argc, char *const argv[], char *const *const envp)
.scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL,
};
+ int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
+ int set_restrict_flags = 0;
if (argc < 2) {
fprintf(stderr, help, argv[0]);
@@ -422,6 +428,13 @@ int main(const int argc, char *const argv[], char *const *const envp)
/* Removes LANDLOCK_SCOPE_* for ABI < 6 */
ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL);
+ __attribute__((fallthrough));
+ case 6:
+ /* Removes LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON for ABI < 7 */
+ supported_restrict_flags &=
+ ~LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
+
+ /* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
fprintf(stderr,
"Hint: You should update the running kernel "
"to leverage Landlock features "
@@ -456,6 +469,24 @@ int main(const int argc, char *const argv[], char *const *const envp)
if (check_ruleset_scope(ENV_SCOPED_NAME, &ruleset_attr))
return 1;
+ /* Enables optional logs. */
+ env_force_log = getenv(ENV_FORCE_LOG_NAME);
+ if (env_force_log) {
+ if (strcmp(env_force_log, "1") != 0) {
+ fprintf(stderr, "Unknown value for " ENV_FORCE_LOG_NAME
+ " (only \"1\" is handled)\n");
+ return 1;
+ }
+ if (!(supported_restrict_flags &
+ LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON)) {
+ fprintf(stderr,
+ "Audit logs not supported by current kernel\n");
+ return 1;
+ }
+ set_restrict_flags |= LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
+ unsetenv(ENV_FORCE_LOG_NAME);
+ }
+
ruleset_fd =
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) {
@@ -483,7 +514,7 @@ int main(const int argc, char *const argv[], char *const *const envp)
perror("Failed to restrict privileges");
goto err_close_ruleset;
}
- if (landlock_restrict_self(ruleset_fd, 0)) {
+ if (landlock_restrict_self(ruleset_fd, set_restrict_flags)) {
perror("Failed to enforce ruleset");
goto err_close_ruleset;
}
diff --git a/samples/livepatch/livepatch-callbacks-busymod.c b/samples/livepatch/livepatch-callbacks-busymod.c
index 69105596e72e..fadc2a85cb35 100644
--- a/samples/livepatch/livepatch-callbacks-busymod.c
+++ b/samples/livepatch/livepatch-callbacks-busymod.c
@@ -56,4 +56,5 @@ static void livepatch_callbacks_mod_exit(void)
module_init(livepatch_callbacks_mod_init);
module_exit(livepatch_callbacks_mod_exit);
+MODULE_DESCRIPTION("Live patching demo for (un)patching callbacks, support module");
MODULE_LICENSE("GPL");
diff --git a/samples/livepatch/livepatch-callbacks-demo.c b/samples/livepatch/livepatch-callbacks-demo.c
index 11c3f4357812..9e69d9caed25 100644
--- a/samples/livepatch/livepatch-callbacks-demo.c
+++ b/samples/livepatch/livepatch-callbacks-demo.c
@@ -192,5 +192,6 @@ static void livepatch_callbacks_demo_exit(void)
module_init(livepatch_callbacks_demo_init);
module_exit(livepatch_callbacks_demo_exit);
+MODULE_DESCRIPTION("Live patching demo for (un)patching callbacks");
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
diff --git a/samples/livepatch/livepatch-callbacks-mod.c b/samples/livepatch/livepatch-callbacks-mod.c
index 2a074f422a51..d1851b471ad9 100644
--- a/samples/livepatch/livepatch-callbacks-mod.c
+++ b/samples/livepatch/livepatch-callbacks-mod.c
@@ -38,4 +38,5 @@ static void livepatch_callbacks_mod_exit(void)
module_init(livepatch_callbacks_mod_init);
module_exit(livepatch_callbacks_mod_exit);
+MODULE_DESCRIPTION("Live patching demo for (un)patching callbacks, support module");
MODULE_LICENSE("GPL");
diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c
index cd76d7ebe598..5263a2f31c48 100644
--- a/samples/livepatch/livepatch-sample.c
+++ b/samples/livepatch/livepatch-sample.c
@@ -66,5 +66,6 @@ static void livepatch_exit(void)
module_init(livepatch_init);
module_exit(livepatch_exit);
+MODULE_DESCRIPTION("Kernel Live Patching Sample Module");
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c
index f3f153895d6c..cbf68ca40097 100644
--- a/samples/livepatch/livepatch-shadow-fix1.c
+++ b/samples/livepatch/livepatch-shadow-fix1.c
@@ -168,5 +168,6 @@ static void livepatch_shadow_fix1_exit(void)
module_init(livepatch_shadow_fix1_init);
module_exit(livepatch_shadow_fix1_exit);
+MODULE_DESCRIPTION("Live patching demo for shadow variables");
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c
index 361046a4f10c..b99122cb221f 100644
--- a/samples/livepatch/livepatch-shadow-fix2.c
+++ b/samples/livepatch/livepatch-shadow-fix2.c
@@ -128,5 +128,6 @@ static void livepatch_shadow_fix2_exit(void)
module_init(livepatch_shadow_fix2_init);
module_exit(livepatch_shadow_fix2_exit);
+MODULE_DESCRIPTION("Live patching demo for shadow variables");
MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index 3b6eae84b297..7f7371a004ee 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -10,6 +10,17 @@ menuconfig SAMPLES_RUST
if SAMPLES_RUST
+config SAMPLE_RUST_CONFIGFS
+ tristate "Configfs sample"
+ depends on CONFIGFS_FS
+ help
+ This option builds the Rust configfs sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_configfs.
+
+ If unsure, say N.
+
config SAMPLE_RUST_MINIMAL
tristate "Minimal"
help
@@ -40,6 +51,17 @@ config SAMPLE_RUST_PRINT
If unsure, say N.
+config SAMPLE_RUST_DMA
+ tristate "DMA Test Driver"
+ depends on PCI
+ help
+ This option builds the Rust DMA Test driver sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_dma.
+
+ If unsure, say N.
+
config SAMPLE_RUST_DRIVER_PCI
tristate "PCI Driver"
depends on PCI
@@ -71,6 +93,18 @@ config SAMPLE_RUST_DRIVER_FAUX
If unsure, say N.
+config SAMPLE_RUST_DRIVER_AUXILIARY
+ tristate "Auxiliary Driver"
+ depends on PCI
+ select AUXILIARY_BUS
+ help
+ This option builds the Rust auxiliary driver sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_driver_auxiliary.
+
+ If unsure, say N.
+
config SAMPLE_RUST_HOSTPROGS
bool "Host programs"
help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 0dbc6d90f1ef..bd2faad63b4f 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -4,9 +4,12 @@ ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o
obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
+obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o
+obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) += rust_configfs.o
rust_print-y := rust_print_main.o rust_print_events.o
diff --git a/samples/rust/rust_configfs.rs b/samples/rust/rust_configfs.rs
new file mode 100644
index 000000000000..60ddbe62cda3
--- /dev/null
+++ b/samples/rust/rust_configfs.rs
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust configfs sample.
+
+use kernel::alloc::flags;
+use kernel::c_str;
+use kernel::configfs;
+use kernel::configfs_attrs;
+use kernel::new_mutex;
+use kernel::page::PAGE_SIZE;
+use kernel::prelude::*;
+use kernel::sync::Mutex;
+
+module! {
+ type: RustConfigfs,
+ name: "rust_configfs",
+ author: "Rust for Linux Contributors",
+ description: "Rust configfs sample",
+ license: "GPL",
+}
+
+#[pin_data]
+struct RustConfigfs {
+ #[pin]
+ config: configfs::Subsystem<Configuration>,
+}
+
+#[pin_data]
+struct Configuration {
+ message: &'static CStr,
+ #[pin]
+ bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
+}
+
+impl Configuration {
+ fn new() -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {
+ message: c_str!("Hello World\n"),
+ bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
+ })
+ }
+}
+
+impl kernel::InPlaceModule for RustConfigfs {
+ fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
+ pr_info!("Rust configfs sample (init)\n");
+
+ // Define a subsystem with the data type `Configuration`, two
+ // attributes, `message` and `bar` and child group type `Child`. `mkdir`
+ // in the directory representing this subsystem will create directories
+ // backed by the `Child` type.
+ let item_type = configfs_attrs! {
+ container: configfs::Subsystem<Configuration>,
+ data: Configuration,
+ child: Child,
+ attributes: [
+ message: 0,
+ bar: 1,
+ ],
+ };
+
+ try_pin_init!(Self {
+ config <- configfs::Subsystem::new(
+ c_str!("rust_configfs"), item_type, Configuration::new()
+ ),
+ })
+ }
+}
+
+#[vtable]
+impl configfs::GroupOperations for Configuration {
+ type Child = Child;
+
+ fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<Child>, Error>> {
+ // Define a group with data type `Child`, one attribute `baz` and child
+ // group type `GrandChild`. `mkdir` in the directory representing this
+ // group will create directories backed by the `GrandChild` type.
+ let tpe = configfs_attrs! {
+ container: configfs::Group<Child>,
+ data: Child,
+ child: GrandChild,
+ attributes: [
+ baz: 0,
+ ],
+ };
+
+ Ok(configfs::Group::new(name.try_into()?, tpe, Child::new()))
+ }
+}
+
+#[vtable]
+impl configfs::AttributeOperations<0> for Configuration {
+ type Data = Configuration;
+
+ fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ pr_info!("Show message\n");
+ let data = container.message;
+ page[0..data.len()].copy_from_slice(data);
+ Ok(data.len())
+ }
+}
+
+#[vtable]
+impl configfs::AttributeOperations<1> for Configuration {
+ type Data = Configuration;
+
+ fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ pr_info!("Show bar\n");
+ let guard = container.bar.lock();
+ let data = guard.0.as_slice();
+ let len = guard.1;
+ page[0..len].copy_from_slice(&data[0..len]);
+ Ok(len)
+ }
+
+ fn store(container: &Configuration, page: &[u8]) -> Result {
+ pr_info!("Store bar\n");
+ let mut guard = container.bar.lock();
+ guard.0[0..page.len()].copy_from_slice(page);
+ guard.1 = page.len();
+ Ok(())
+ }
+}
+
+// `pin_data` cannot handle structs without braces.
+#[pin_data]
+struct Child {}
+
+impl Child {
+ fn new() -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {})
+ }
+}
+
+#[vtable]
+impl configfs::GroupOperations for Child {
+ type Child = GrandChild;
+
+ fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandChild>, Error>> {
+ // Define a group with data type `GrandChild`, one attribute `gc`. As no
+ // child type is specified, it will not be possible to create subgroups
+ // in this group, and `mkdir`in the directory representing this group
+ // will return an error.
+ let tpe = configfs_attrs! {
+ container: configfs::Group<GrandChild>,
+ data: GrandChild,
+ attributes: [
+ gc: 0,
+ ],
+ };
+
+ Ok(configfs::Group::new(
+ name.try_into()?,
+ tpe,
+ GrandChild::new(),
+ ))
+ }
+}
+
+#[vtable]
+impl configfs::AttributeOperations<0> for Child {
+ type Data = Child;
+
+ fn show(_container: &Child, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ pr_info!("Show baz\n");
+ let data = c"Hello Baz\n".to_bytes();
+ page[0..data.len()].copy_from_slice(data);
+ Ok(data.len())
+ }
+}
+
+// `pin_data` cannot handle structs without braces.
+#[pin_data]
+struct GrandChild {}
+
+impl GrandChild {
+ fn new() -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {})
+ }
+}
+
+#[vtable]
+impl configfs::AttributeOperations<0> for GrandChild {
+ type Data = GrandChild;
+
+ fn show(_container: &GrandChild, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ pr_info!("Show grand child\n");
+ let data = c"Hello GC\n".to_bytes();
+ page[0..data.len()].copy_from_slice(data);
+ Ok(data.len())
+ }
+}
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
new file mode 100644
index 000000000000..874c2c964afa
--- /dev/null
+++ b/samples/rust/rust_dma.rs
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust DMA api test (based on QEMU's `pci-testdev`).
+//!
+//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
+
+use kernel::{bindings, device::Core, dma::CoherentAllocation, pci, prelude::*, types::ARef};
+
+struct DmaSampleDriver {
+ pdev: ARef<pci::Device>,
+ ca: CoherentAllocation<MyStruct>,
+}
+
+const TEST_VALUES: [(u32, u32); 5] = [
+ (0xa, 0xb),
+ (0xc, 0xd),
+ (0xe, 0xf),
+ (0xab, 0xba),
+ (0xcd, 0xef),
+];
+
+struct MyStruct {
+ h: u32,
+ b: u32,
+}
+
+impl MyStruct {
+ fn new(h: u32, b: u32) -> Self {
+ Self { h, b }
+ }
+}
+// SAFETY: All bit patterns are acceptable values for `MyStruct`.
+unsafe impl kernel::transmute::AsBytes for MyStruct {}
+// SAFETY: Instances of `MyStruct` have no uninitialized portions.
+unsafe impl kernel::transmute::FromBytes for MyStruct {}
+
+kernel::pci_device_table!(
+ PCI_TABLE,
+ MODULE_PCI_TABLE,
+ <DmaSampleDriver as pci::Driver>::IdInfo,
+ [(
+ pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
+ ()
+ )]
+);
+
+impl pci::Driver for DmaSampleDriver {
+ type IdInfo = ();
+ const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
+
+ fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+ dev_info!(pdev.as_ref(), "Probe DMA test driver.\n");
+
+ let ca: CoherentAllocation<MyStruct> =
+ CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?;
+
+ || -> Result {
+ for (i, value) in TEST_VALUES.into_iter().enumerate() {
+ kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1));
+ }
+
+ Ok(())
+ }()?;
+
+ let drvdata = KBox::new(
+ Self {
+ pdev: pdev.into(),
+ ca,
+ },
+ GFP_KERNEL,
+ )?;
+
+ Ok(drvdata.into())
+ }
+}
+
+impl Drop for DmaSampleDriver {
+ fn drop(&mut self) {
+ dev_info!(self.pdev.as_ref(), "Unload DMA test driver.\n");
+
+ let _ = || -> Result {
+ for (i, value) in TEST_VALUES.into_iter().enumerate() {
+ assert_eq!(kernel::dma_read!(self.ca[i].h), value.0);
+ assert_eq!(kernel::dma_read!(self.ca[i].b), value.1);
+ }
+ Ok(())
+ }();
+ }
+}
+
+kernel::module_pci_driver! {
+ type: DmaSampleDriver,
+ name: "rust_dma",
+ authors: ["Abdiel Janulgue"],
+ description: "Rust DMA test",
+ license: "GPL v2",
+}
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
new file mode 100644
index 000000000000..3e15e6d002bb
--- /dev/null
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust auxiliary driver sample (based on a PCI driver for QEMU's `pci-testdev`).
+//!
+//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
+
+use kernel::{
+ auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr,
+ InPlaceModule,
+};
+
+use pin_init::PinInit;
+
+const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
+const AUXILIARY_NAME: &CStr = c_str!("auxiliary");
+
+struct AuxiliaryDriver;
+
+kernel::auxiliary_device_table!(
+ AUX_TABLE,
+ MODULE_AUX_TABLE,
+ <AuxiliaryDriver as auxiliary::Driver>::IdInfo,
+ [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())]
+);
+
+impl auxiliary::Driver for AuxiliaryDriver {
+ type IdInfo = ();
+
+ const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
+
+ fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+ dev_info!(
+ adev.as_ref(),
+ "Probing auxiliary driver for auxiliary device with id={}\n",
+ adev.id()
+ );
+
+ ParentDriver::connect(adev)?;
+
+ let this = KBox::new(Self, GFP_KERNEL)?;
+
+ Ok(this.into())
+ }
+}
+
+struct ParentDriver {
+ _reg: [auxiliary::Registration; 2],
+}
+
+kernel::pci_device_table!(
+ PCI_TABLE,
+ MODULE_PCI_TABLE,
+ <ParentDriver as pci::Driver>::IdInfo,
+ [(
+ pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
+ ()
+ )]
+);
+
+impl pci::Driver for ParentDriver {
+ type IdInfo = ();
+
+ const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
+
+ fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+ let this = KBox::new(
+ Self {
+ _reg: [
+ auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?,
+ auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?,
+ ],
+ },
+ GFP_KERNEL,
+ )?;
+
+ Ok(this.into())
+ }
+}
+
+impl ParentDriver {
+ fn connect(adev: &auxiliary::Device) -> Result<()> {
+ let parent = adev.parent().ok_or(EINVAL)?;
+ let pdev: &pci::Device = parent.try_into()?;
+
+ dev_info!(
+ adev.as_ref(),
+ "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n",
+ adev.id(),
+ pdev.vendor_id(),
+ pdev.device_id()
+ );
+
+ Ok(())
+ }
+}
+
+#[pin_data]
+struct SampleModule {
+ #[pin]
+ _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>,
+ #[pin]
+ _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>,
+}
+
+impl InPlaceModule for SampleModule {
+ fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {
+ _pci_driver <- driver::Registration::new(MODULE_NAME, module),
+ _aux_driver <- driver::Registration::new(MODULE_NAME, module),
+ })
+ }
+}
+
+module! {
+ type: SampleModule,
+ name: "rust_driver_auxiliary",
+ author: "Danilo Krummrich",
+ description: "Rust auxiliary driver",
+ license: "GPL v2",
+}
diff --git a/samples/rust/rust_driver_faux.rs b/samples/rust/rust_driver_faux.rs
index 048c6cb98b29..ecc9fd378cbd 100644
--- a/samples/rust/rust_driver_faux.rs
+++ b/samples/rust/rust_driver_faux.rs
@@ -7,7 +7,7 @@ use kernel::{c_str, faux, prelude::*, Module};
module! {
type: SampleModule,
name: "rust_faux_driver",
- author: "Lyude Paul",
+ authors: ["Lyude Paul"],
description: "Rust faux device sample",
license: "GPL",
}
@@ -20,7 +20,7 @@ impl Module for SampleModule {
fn init(_module: &'static ThisModule) -> Result<Self> {
pr_info!("Initialising Rust Faux Device Sample\n");
- let reg = faux::Registration::new(c_str!("rust-faux-sample-device"))?;
+ let reg = faux::Registration::new(c_str!("rust-faux-sample-device"), None)?;
dev_info!(reg.as_ref(), "Hello from faux device!\n");
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 1fb6e44f3395..15147e4401b2 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -4,7 +4,7 @@
//!
//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
-use kernel::{bindings, c_str, devres::Devres, pci, prelude::*};
+use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef};
struct Regs;
@@ -26,7 +26,7 @@ impl TestIndex {
}
struct SampleDriver {
- pdev: pci::Device,
+ pdev: ARef<pci::Device>,
bar: Devres<Bar0>,
}
@@ -43,17 +43,17 @@ kernel::pci_device_table!(
impl SampleDriver {
fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> {
// Select the test.
- bar.writeb(index.0, Regs::TEST);
+ bar.write8(index.0, Regs::TEST);
- let offset = u32::from_le(bar.readl(Regs::OFFSET)) as usize;
- let data = bar.readb(Regs::DATA);
+ let offset = u32::from_le(bar.read32(Regs::OFFSET)) as usize;
+ let data = bar.read8(Regs::DATA);
// Write `data` to `offset` to increase `count` by one.
//
- // Note that we need `try_writeb`, since `offset` can't be checked at compile-time.
- bar.try_writeb(data, offset)?;
+ // Note that we need `try_write8`, since `offset` can't be checked at compile-time.
+ bar.try_write8(data, offset)?;
- Ok(bar.readl(Regs::COUNT))
+ Ok(bar.read32(Regs::COUNT))
}
}
@@ -62,7 +62,7 @@ impl pci::Driver for SampleDriver {
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
- fn probe(pdev: &mut pci::Device, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+ fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
dev_dbg!(
pdev.as_ref(),
"Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n",
@@ -77,18 +77,17 @@ impl pci::Driver for SampleDriver {
let drvdata = KBox::new(
Self {
- pdev: pdev.clone(),
+ pdev: pdev.into(),
bar,
},
GFP_KERNEL,
)?;
- let bar = drvdata.bar.try_access().ok_or(ENXIO)?;
-
+ let bar = drvdata.bar.access(pdev.as_ref())?;
dev_info!(
pdev.as_ref(),
"pci-testdev data-match count: {}\n",
- Self::testdev(info, &bar)?
+ Self::testdev(info, bar)?
);
Ok(drvdata.into())
@@ -104,7 +103,7 @@ impl Drop for SampleDriver {
kernel::module_pci_driver! {
type: SampleDriver,
name: "rust_driver_pci",
- author: "Danilo Krummrich",
+ authors: ["Danilo Krummrich"],
description: "Rust PCI driver",
license: "GPL v2",
}
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index 8120609e2940..8b42b3cfb363 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -2,10 +2,10 @@
//! Rust Platform driver sample.
-use kernel::{c_str, of, platform, prelude::*};
+use kernel::{c_str, device::Core, of, platform, prelude::*, types::ARef};
struct SampleDriver {
- pdev: platform::Device,
+ pdev: ARef<platform::Device>,
}
struct Info(u32);
@@ -21,14 +21,17 @@ impl platform::Driver for SampleDriver {
type IdInfo = Info;
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
- fn probe(pdev: &mut platform::Device, info: Option<&Self::IdInfo>) -> Result<Pin<KBox<Self>>> {
+ fn probe(
+ pdev: &platform::Device<Core>,
+ info: Option<&Self::IdInfo>,
+ ) -> Result<Pin<KBox<Self>>> {
dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n");
if let Some(info) = info {
dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0);
}
- let drvdata = KBox::new(Self { pdev: pdev.clone() }, GFP_KERNEL)?;
+ let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?;
Ok(drvdata.into())
}
@@ -43,7 +46,7 @@ impl Drop for SampleDriver {
kernel::module_platform_driver! {
type: SampleDriver,
name: "rust_driver_platform",
- author: "Danilo Krummrich",
+ authors: ["Danilo Krummrich"],
description: "Rust Platform driver",
license: "GPL v2",
}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
index 4aaf117bf8e3..1fc7a1be6b6d 100644
--- a/samples/rust/rust_minimal.rs
+++ b/samples/rust/rust_minimal.rs
@@ -7,7 +7,7 @@ use kernel::prelude::*;
module! {
type: RustMinimal,
name: "rust_minimal",
- author: "Rust for Linux Contributors",
+ authors: ["Rust for Linux Contributors"],
description: "Rust minimal sample",
license: "GPL",
}
diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_device.rs
index 40ad7266c225..c881fd6dbd08 100644
--- a/samples/rust/rust_misc_device.rs
+++ b/samples/rust/rust_misc_device.rs
@@ -3,97 +3,98 @@
// Copyright (C) 2024 Google LLC.
//! Rust misc device sample.
+//!
+//! Below is an example userspace C program that exercises this sample's functionality.
+//!
+//! ```c
+//! #include <stdio.h>
+//! #include <stdlib.h>
+//! #include <errno.h>
+//! #include <fcntl.h>
+//! #include <unistd.h>
+//! #include <sys/ioctl.h>
+//!
+//! #define RUST_MISC_DEV_FAIL _IO('|', 0)
+//! #define RUST_MISC_DEV_HELLO _IO('|', 0x80)
+//! #define RUST_MISC_DEV_GET_VALUE _IOR('|', 0x81, int)
+//! #define RUST_MISC_DEV_SET_VALUE _IOW('|', 0x82, int)
+//!
+//! int main() {
+//! int value, new_value;
+//! int fd, ret;
+//!
+//! // Open the device file
+//! printf("Opening /dev/rust-misc-device for reading and writing\n");
+//! fd = open("/dev/rust-misc-device", O_RDWR);
+//! if (fd < 0) {
+//! perror("open");
+//! return errno;
+//! }
+//!
+//! // Make call into driver to say "hello"
+//! printf("Calling Hello\n");
+//! ret = ioctl(fd, RUST_MISC_DEV_HELLO, NULL);
+//! if (ret < 0) {
+//! perror("ioctl: Failed to call into Hello");
+//! close(fd);
+//! return errno;
+//! }
+//!
+//! // Get initial value
+//! printf("Fetching initial value\n");
+//! ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &value);
+//! if (ret < 0) {
+//! perror("ioctl: Failed to fetch the initial value");
+//! close(fd);
+//! return errno;
+//! }
+//!
+//! value++;
+//!
+//! // Set value to something different
+//! printf("Submitting new value (%d)\n", value);
+//! ret = ioctl(fd, RUST_MISC_DEV_SET_VALUE, &value);
+//! if (ret < 0) {
+//! perror("ioctl: Failed to submit new value");
+//! close(fd);
+//! return errno;
+//! }
+//!
+//! // Ensure new value was applied
+//! printf("Fetching new value\n");
+//! ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &new_value);
+//! if (ret < 0) {
+//! perror("ioctl: Failed to fetch the new value");
+//! close(fd);
+//! return errno;
+//! }
+//!
+//! if (value != new_value) {
+//! printf("Failed: Committed and retrieved values are different (%d - %d)\n", value, new_value);
+//! close(fd);
+//! return -1;
+//! }
+//!
+//! // Call the unsuccessful ioctl
+//! printf("Attempting to call in to an non-existent IOCTL\n");
+//! ret = ioctl(fd, RUST_MISC_DEV_FAIL, NULL);
+//! if (ret < 0) {
+//! perror("ioctl: Succeeded to fail - this was expected");
+//! } else {
+//! printf("ioctl: Failed to fail\n");
+//! close(fd);
+//! return -1;
+//! }
+//!
+//! // Close the device file
+//! printf("Closing /dev/rust-misc-device\n");
+//! close(fd);
+//!
+//! printf("Success\n");
+//! return 0;
+//! }
+//! ```
-/// Below is an example userspace C program that exercises this sample's functionality.
-///
-/// ```c
-/// #include <stdio.h>
-/// #include <stdlib.h>
-/// #include <errno.h>
-/// #include <fcntl.h>
-/// #include <unistd.h>
-/// #include <sys/ioctl.h>
-///
-/// #define RUST_MISC_DEV_FAIL _IO('|', 0)
-/// #define RUST_MISC_DEV_HELLO _IO('|', 0x80)
-/// #define RUST_MISC_DEV_GET_VALUE _IOR('|', 0x81, int)
-/// #define RUST_MISC_DEV_SET_VALUE _IOW('|', 0x82, int)
-///
-/// int main() {
-/// int value, new_value;
-/// int fd, ret;
-///
-/// // Open the device file
-/// printf("Opening /dev/rust-misc-device for reading and writing\n");
-/// fd = open("/dev/rust-misc-device", O_RDWR);
-/// if (fd < 0) {
-/// perror("open");
-/// return errno;
-/// }
-///
-/// // Make call into driver to say "hello"
-/// printf("Calling Hello\n");
-/// ret = ioctl(fd, RUST_MISC_DEV_HELLO, NULL);
-/// if (ret < 0) {
-/// perror("ioctl: Failed to call into Hello");
-/// close(fd);
-/// return errno;
-/// }
-///
-/// // Get initial value
-/// printf("Fetching initial value\n");
-/// ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &value);
-/// if (ret < 0) {
-/// perror("ioctl: Failed to fetch the initial value");
-/// close(fd);
-/// return errno;
-/// }
-///
-/// value++;
-///
-/// // Set value to something different
-/// printf("Submitting new value (%d)\n", value);
-/// ret = ioctl(fd, RUST_MISC_DEV_SET_VALUE, &value);
-/// if (ret < 0) {
-/// perror("ioctl: Failed to submit new value");
-/// close(fd);
-/// return errno;
-/// }
-///
-/// // Ensure new value was applied
-/// printf("Fetching new value\n");
-/// ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &new_value);
-/// if (ret < 0) {
-/// perror("ioctl: Failed to fetch the new value");
-/// close(fd);
-/// return errno;
-/// }
-///
-/// if (value != new_value) {
-/// printf("Failed: Committed and retrieved values are different (%d - %d)\n", value, new_value);
-/// close(fd);
-/// return -1;
-/// }
-///
-/// // Call the unsuccessful ioctl
-/// printf("Attempting to call in to an non-existent IOCTL\n");
-/// ret = ioctl(fd, RUST_MISC_DEV_FAIL, NULL);
-/// if (ret < 0) {
-/// perror("ioctl: Succeeded to fail - this was expected");
-/// } else {
-/// printf("ioctl: Failed to fail\n");
-/// close(fd);
-/// return -1;
-/// }
-///
-/// // Close the device file
-/// printf("Closing /dev/rust-misc-device\n");
-/// close(fd);
-///
-/// printf("Success\n");
-/// return 0;
-/// }
-/// ```
use core::pin::Pin;
use kernel::{
@@ -116,7 +117,7 @@ const RUST_MISC_DEV_SET_VALUE: u32 = _IOW::<i32>('|' as u32, 0x82);
module! {
type: RustMiscDeviceModule,
name: "rust_misc_device",
- author: "Lee Jones",
+ authors: ["Lee Jones"],
description: "Rust misc device sample",
license: "GPL",
}
diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs
index 7e8af5f176a3..8ea95e8c2f36 100644
--- a/samples/rust/rust_print_main.rs
+++ b/samples/rust/rust_print_main.rs
@@ -8,7 +8,7 @@ use kernel::prelude::*;
module! {
type: RustPrint,
name: "rust_print",
- author: "Rust for Linux Contributors",
+ authors: ["Rust for Linux Contributors"],
description: "Rust printing macros sample",
license: "GPL",
}
diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h
index 999f78d380ae..1a05fc153353 100644
--- a/samples/trace_events/trace-events-sample.h
+++ b/samples/trace_events/trace-events-sample.h
@@ -319,7 +319,8 @@ TRACE_EVENT(foo_bar,
__assign_cpumask(cpum, cpumask_bits(mask));
),
- TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar,
+ TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s [%d] %*pbl",
+ __entry->foo, __entry->bar,
/*
* Notice here the use of some helper functions. This includes:
@@ -370,7 +371,10 @@ TRACE_EVENT(foo_bar,
__get_str(str), __get_str(lstr),
__get_bitmask(cpus), __get_cpumask(cpum),
- __get_str(vstr))
+ __get_str(vstr),
+ __get_dynamic_array_len(cpus),
+ __get_dynamic_array_len(cpus),
+ __get_dynamic_array(cpus))
);
/*
diff --git a/samples/tsm-mr/Makefile b/samples/tsm-mr/Makefile
new file mode 100644
index 000000000000..587c3947b3a7
--- /dev/null
+++ b/samples/tsm-mr/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_TSM_MR) += tsm_mr_sample.o
diff --git a/samples/tsm-mr/tsm_mr_sample.c b/samples/tsm-mr/tsm_mr_sample.c
new file mode 100644
index 000000000000..a2c652148639
--- /dev/null
+++ b/samples/tsm-mr/tsm_mr_sample.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2024-2005 Intel Corporation. All rights reserved. */
+
+#define pr_fmt(x) KBUILD_MODNAME ": " x
+
+#include <linux/module.h>
+#include <linux/tsm-mr.h>
+#include <linux/miscdevice.h>
+#include <crypto/hash.h>
+
+static struct {
+ u8 static_mr[SHA384_DIGEST_SIZE];
+ u8 config_mr[SHA512_DIGEST_SIZE];
+ u8 rtmr0[SHA256_DIGEST_SIZE];
+ u8 rtmr1[SHA384_DIGEST_SIZE];
+ u8 report_digest[SHA512_DIGEST_SIZE];
+} sample_report = {
+ .static_mr = "static_mr",
+ .config_mr = "config_mr",
+ .rtmr0 = "rtmr0",
+ .rtmr1 = "rtmr1",
+};
+
+static int sample_report_refresh(const struct tsm_measurements *tm)
+{
+ struct crypto_shash *tfm;
+ int rc;
+
+ tfm = crypto_alloc_shash(hash_algo_name[HASH_ALGO_SHA512], 0, 0);
+ if (IS_ERR(tfm)) {
+ pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+
+ rc = crypto_shash_tfm_digest(tfm, (u8 *)&sample_report,
+ offsetof(typeof(sample_report),
+ report_digest),
+ sample_report.report_digest);
+ crypto_free_shash(tfm);
+ if (rc)
+ pr_err("crypto_shash_tfm_digest failed: %d\n", rc);
+ return rc;
+}
+
+static int sample_report_extend_mr(const struct tsm_measurements *tm,
+ const struct tsm_measurement_register *mr,
+ const u8 *data)
+{
+ SHASH_DESC_ON_STACK(desc, 0);
+ int rc;
+
+ desc->tfm = crypto_alloc_shash(hash_algo_name[mr->mr_hash], 0, 0);
+ if (IS_ERR(desc->tfm)) {
+ pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(desc->tfm));
+ return PTR_ERR(desc->tfm);
+ }
+
+ rc = crypto_shash_init(desc);
+ if (!rc)
+ rc = crypto_shash_update(desc, mr->mr_value, mr->mr_size);
+ if (!rc)
+ rc = crypto_shash_finup(desc, data, mr->mr_size, mr->mr_value);
+ crypto_free_shash(desc->tfm);
+ if (rc)
+ pr_err("SHA calculation failed: %d\n", rc);
+ return rc;
+}
+
+#define MR_(mr, hash) .mr_value = &sample_report.mr, TSM_MR_(mr, hash)
+static const struct tsm_measurement_register sample_mrs[] = {
+ /* static MR, read-only */
+ { MR_(static_mr, SHA384) },
+ /* config MR, read-only */
+ { MR_(config_mr, SHA512) | TSM_MR_F_NOHASH },
+ /* RTMR, direct extension prohibited */
+ { MR_(rtmr0, SHA256) | TSM_MR_F_LIVE },
+ /* RTMR, direct extension allowed */
+ { MR_(rtmr1, SHA384) | TSM_MR_F_RTMR },
+ /* RTMR, crypto agile, alaised to rtmr0 and rtmr1, respectively */
+ { .mr_value = &sample_report.rtmr0,
+ TSM_MR_(rtmr_crypto_agile, SHA256) | TSM_MR_F_RTMR },
+ { .mr_value = &sample_report.rtmr1,
+ TSM_MR_(rtmr_crypto_agile, SHA384) | TSM_MR_F_RTMR },
+ /* sha512 digest of the whole structure */
+ { MR_(report_digest, SHA512) | TSM_MR_F_LIVE },
+};
+#undef MR_
+
+static struct tsm_measurements sample_tm = {
+ .mrs = sample_mrs,
+ .nr_mrs = ARRAY_SIZE(sample_mrs),
+ .refresh = sample_report_refresh,
+ .write = sample_report_extend_mr,
+};
+
+static const struct attribute_group *sample_groups[] = {
+ NULL,
+ NULL,
+};
+
+static struct miscdevice sample_misc_dev = {
+ .name = KBUILD_MODNAME,
+ .minor = MISC_DYNAMIC_MINOR,
+ .groups = sample_groups,
+};
+
+static int __init tsm_mr_sample_init(void)
+{
+ int rc;
+
+ sample_groups[0] = tsm_mr_create_attribute_group(&sample_tm);
+ if (IS_ERR(sample_groups[0]))
+ return PTR_ERR(sample_groups[0]);
+
+ rc = misc_register(&sample_misc_dev);
+ if (rc)
+ tsm_mr_free_attribute_group(sample_groups[0]);
+ return rc;
+}
+
+static void __exit tsm_mr_sample_exit(void)
+{
+ misc_deregister(&sample_misc_dev);
+ tsm_mr_free_attribute_group(sample_groups[0]);
+}
+
+module_init(tsm_mr_sample_init);
+module_exit(tsm_mr_sample_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sample module using tsm-mr to expose emulated MRs");
diff --git a/samples/vfs/samples-vfs.h b/samples/vfs/samples-vfs.h
index 103e1e7c4cec..498baf581b56 100644
--- a/samples/vfs/samples-vfs.h
+++ b/samples/vfs/samples-vfs.h
@@ -42,7 +42,11 @@ struct statmount {
__u32 opt_array; /* [str] Array of nul terminated fs options */
__u32 opt_sec_num; /* Number of security options */
__u32 opt_sec_array; /* [str] Array of nul terminated security options */
- __u64 __spare2[46];
+ __u32 mnt_uidmap_num; /* Number of uid mappings */
+ __u32 mnt_uidmap; /* [str] Array of uid mappings */
+ __u32 mnt_gidmap_num; /* Number of gid mappings */
+ __u32 mnt_gidmap; /* [str] Array of gid mappings */
+ __u64 __spare2[44];
char str[]; /* Variable size part containing strings */
};
@@ -158,6 +162,14 @@ struct mnt_ns_info {
#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */
#endif
+#ifndef STATMOUNT_MNT_UIDMAP
+#define STATMOUNT_MNT_UIDMAP 0x00002000U /* Want/got uidmap... */
+#endif
+
+#ifndef STATMOUNT_MNT_GIDMAP
+#define STATMOUNT_MNT_GIDMAP 0x00004000U /* Want/got gidmap... */
+#endif
+
#ifndef MOUNT_ATTR_RDONLY
#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
#endif
diff --git a/samples/vfs/test-list-all-mounts.c b/samples/vfs/test-list-all-mounts.c
index 1a02ea4593e3..713c174626aa 100644
--- a/samples/vfs/test-list-all-mounts.c
+++ b/samples/vfs/test-list-all-mounts.c
@@ -128,20 +128,43 @@ next:
STATMOUNT_MNT_POINT |
STATMOUNT_MNT_NS_ID |
STATMOUNT_MNT_OPTS |
- STATMOUNT_FS_TYPE, 0);
+ STATMOUNT_FS_TYPE |
+ STATMOUNT_MNT_UIDMAP |
+ STATMOUNT_MNT_GIDMAP, 0);
if (!stmnt) {
printf("Failed to statmount(%" PRIu64 ") in mount namespace(%" PRIu64 ")\n",
(uint64_t)last_mnt_id, (uint64_t)info.mnt_ns_id);
continue;
}
- printf("mnt_id:\t\t%" PRIu64 "\nmnt_parent_id:\t%" PRIu64 "\nfs_type:\t%s\nmnt_root:\t%s\nmnt_point:\t%s\nmnt_opts:\t%s\n\n",
+ printf("mnt_id:\t\t%" PRIu64 "\nmnt_parent_id:\t%" PRIu64 "\nfs_type:\t%s\nmnt_root:\t%s\nmnt_point:\t%s\nmnt_opts:\t%s\n",
(uint64_t)stmnt->mnt_id,
(uint64_t)stmnt->mnt_parent_id,
- stmnt->str + stmnt->fs_type,
- stmnt->str + stmnt->mnt_root,
- stmnt->str + stmnt->mnt_point,
- stmnt->str + stmnt->mnt_opts);
+ (stmnt->mask & STATMOUNT_FS_TYPE) ? stmnt->str + stmnt->fs_type : "",
+ (stmnt->mask & STATMOUNT_MNT_ROOT) ? stmnt->str + stmnt->mnt_root : "",
+ (stmnt->mask & STATMOUNT_MNT_POINT) ? stmnt->str + stmnt->mnt_point : "",
+ (stmnt->mask & STATMOUNT_MNT_OPTS) ? stmnt->str + stmnt->mnt_opts : "");
+
+ if (stmnt->mask & STATMOUNT_MNT_UIDMAP) {
+ const char *idmap = stmnt->str + stmnt->mnt_uidmap;
+
+ for (size_t idx = 0; idx < stmnt->mnt_uidmap_num; idx++) {
+ printf("mnt_uidmap[%zu]:\t%s\n", idx, idmap);
+ idmap += strlen(idmap) + 1;
+ }
+ }
+
+ if (stmnt->mask & STATMOUNT_MNT_GIDMAP) {
+ const char *idmap = stmnt->str + stmnt->mnt_gidmap;
+
+ for (size_t idx = 0; idx < stmnt->mnt_gidmap_num; idx++) {
+ printf("mnt_gidmap[%zu]:\t%s\n", idx, idmap);
+ idmap += strlen(idmap) + 1;
+ }
+ }
+
+ printf("\n");
+
free(stmnt);
}
}