[RFC v1 02/14] bus1: provide stub cdev /dev/bus1

From: David Herrmann
Date: Wed Oct 26 2016 - 15:24:58 EST


From: Tom Gundersen <teg@xxxxxxx>

Add the CONFIG_BUS1 option to enable the bus1 kernel messaging bus. If
enabled, provide the bus1.ko module with a stub cdev /dev/bus1. So far
it does not expose any API, but the full intended uapi is provided in
include/uapi/linux/bus1.h already.

Signed-off-by: Tom Gundersen <teg@xxxxxxx>
Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxx>
---
include/uapi/linux/bus1.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++
init/Kconfig | 17 ++++++
ipc/Makefile | 1 +
ipc/bus1/Makefile | 6 ++
ipc/bus1/main.c | 80 +++++++++++++++++++++++++++
ipc/bus1/main.h | 74 +++++++++++++++++++++++++
ipc/bus1/tests.c | 19 +++++++
ipc/bus1/tests.h | 32 +++++++++++
8 files changed, 367 insertions(+)
create mode 100644 include/uapi/linux/bus1.h
create mode 100644 ipc/bus1/Makefile
create mode 100644 ipc/bus1/main.c
create mode 100644 ipc/bus1/main.h
create mode 100644 ipc/bus1/tests.c
create mode 100644 ipc/bus1/tests.h

diff --git a/include/uapi/linux/bus1.h b/include/uapi/linux/bus1.h
new file mode 100644
index 0000000..8ec3357
--- /dev/null
+++ b/include/uapi/linux/bus1.h
@@ -0,0 +1,138 @@
+#ifndef _UAPI_LINUX_BUS1_H
+#define _UAPI_LINUX_BUS1_H
+
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define BUS1_FD_MAX (256)
+
+#define BUS1_IOCTL_MAGIC 0x96
+#define BUS1_HANDLE_INVALID ((__u64)-1)
+#define BUS1_OFFSET_INVALID ((__u64)-1)
+
+enum {
+ BUS1_HANDLE_FLAG_MANAGED = 1ULL << 0,
+ BUS1_HANDLE_FLAG_REMOTE = 1ULL << 1,
+};
+
+enum {
+ BUS1_PEER_FLAG_WANT_SECCTX = 1ULL << 0,
+};
+
+enum {
+ BUS1_PEER_RESET_FLAG_FLUSH = 1ULL << 0,
+ BUS1_PEER_RESET_FLAG_FLUSH_SEED = 1ULL << 1,
+};
+
+struct bus1_cmd_peer_reset {
+ __u64 flags;
+ __u64 peer_flags;
+ __u32 max_slices;
+ __u32 max_handles;
+ __u32 max_inflight_bytes;
+ __u32 max_inflight_fds;
+} __attribute__((__aligned__(8)));
+
+struct bus1_cmd_handle_transfer {
+ __u64 flags;
+ __u64 src_handle;
+ __u64 dst_fd;
+ __u64 dst_handle;
+} __attribute__((__aligned__(8)));
+
+enum {
+ BUS1_NODES_DESTROY_FLAG_RELEASE_HANDLES = 1ULL << 0,
+};
+
+struct bus1_cmd_nodes_destroy {
+ __u64 flags;
+ __u64 ptr_nodes;
+ __u64 n_nodes;
+} __attribute__((__aligned__(8)));
+
+enum {
+ BUS1_SEND_FLAG_CONTINUE = 1ULL << 0,
+ BUS1_SEND_FLAG_SEED = 1ULL << 1,
+};
+
+struct bus1_cmd_send {
+ __u64 flags;
+ __u64 ptr_destinations;
+ __u64 ptr_errors;
+ __u64 n_destinations;
+ __u64 ptr_vecs;
+ __u64 n_vecs;
+ __u64 ptr_handles;
+ __u64 n_handles;
+ __u64 ptr_fds;
+ __u64 n_fds;
+} __attribute__((__aligned__(8)));
+
+enum {
+ BUS1_RECV_FLAG_PEEK = 1ULL << 0,
+ BUS1_RECV_FLAG_SEED = 1ULL << 1,
+ BUS1_RECV_FLAG_INSTALL_FDS = 1ULL << 2,
+};
+
+enum {
+ BUS1_MSG_NONE,
+ BUS1_MSG_DATA,
+ BUS1_MSG_NODE_DESTROY,
+ BUS1_MSG_NODE_RELEASE,
+};
+
+enum {
+ BUS1_MSG_FLAG_HAS_SECCTX = 1ULL << 0,
+ BUS1_MSG_FLAG_CONTINUE = 1ULL << 1,
+};
+
+struct bus1_cmd_recv {
+ __u64 flags;
+ __u64 max_offset;
+ struct {
+ __u64 type;
+ __u64 flags;
+ __u64 destination;
+ __u32 uid;
+ __u32 gid;
+ __u32 pid;
+ __u32 tid;
+ __u64 offset;
+ __u64 n_bytes;
+ __u64 n_handles;
+ __u64 n_fds;
+ __u64 n_secctx;
+ } __attribute__((__aligned__(8))) msg;
+} __attribute__((__aligned__(8)));
+
+enum {
+ BUS1_CMD_PEER_DISCONNECT = _IOWR(BUS1_IOCTL_MAGIC, 0x00,
+ __u64),
+ BUS1_CMD_PEER_QUERY = _IOWR(BUS1_IOCTL_MAGIC, 0x01,
+ struct bus1_cmd_peer_reset),
+ BUS1_CMD_PEER_RESET = _IOWR(BUS1_IOCTL_MAGIC, 0x02,
+ struct bus1_cmd_peer_reset),
+ BUS1_CMD_HANDLE_RELEASE = _IOWR(BUS1_IOCTL_MAGIC, 0x10,
+ __u64),
+ BUS1_CMD_HANDLE_TRANSFER = _IOWR(BUS1_IOCTL_MAGIC, 0x11,
+ struct bus1_cmd_handle_transfer),
+ BUS1_CMD_NODES_DESTROY = _IOWR(BUS1_IOCTL_MAGIC, 0x20,
+ struct bus1_cmd_nodes_destroy),
+ BUS1_CMD_SLICE_RELEASE = _IOWR(BUS1_IOCTL_MAGIC, 0x30,
+ __u64),
+ BUS1_CMD_SEND = _IOWR(BUS1_IOCTL_MAGIC, 0x40,
+ struct bus1_cmd_send),
+ BUS1_CMD_RECV = _IOWR(BUS1_IOCTL_MAGIC, 0x50,
+ struct bus1_cmd_recv),
+};
+
+#endif /* _UAPI_LINUX_BUS1_H */
diff --git a/init/Kconfig b/init/Kconfig
index 34407f1..04c7daf 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -273,6 +273,23 @@ config POSIX_MQUEUE_SYSCTL
depends on SYSCTL
default y

+config BUS1
+ tristate "Bus1 Kernel Message Bus"
+ help
+ The Bus1 Kernel Message Bus defines and implements a distributed
+ object model. It provides a capability-based IPC system for machine
+ local communication.
+
+ The Bus1 IPC system is exposed via /dev/bus1. If debugfs is enabled,
+ bus1 exposes additional debug information there.
+
+config BUS1_TESTS
+ bool "Bus1 Self-Tests"
+ depends on BUS1
+ help
+ Enable and run the bus1 self-tests before loading the module. The
+ overhead is minimal, so there is generally no harm in enabling it.
+
config CROSS_MEMORY_ATTACH
bool "Enable process_vm_readv/writev syscalls"
depends on MMU
diff --git a/ipc/Makefile b/ipc/Makefile
index 86c7300..eee12d1 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -9,4 +9,5 @@ obj_mq-$(CONFIG_COMPAT) += compat_mq.o
obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
obj-$(CONFIG_IPC_NS) += namespace.o
obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
+obj-$(CONFIG_BUS1) += bus1/

diff --git a/ipc/bus1/Makefile b/ipc/bus1/Makefile
new file mode 100644
index 0000000..d3a4491
--- /dev/null
+++ b/ipc/bus1/Makefile
@@ -0,0 +1,6 @@
+bus1-y := \
+ main.o
+
+obj-$(CONFIG_BUS1) += bus1.o
+
+bus1-$(CONFIG_BUS1_TESTS) += tests.o
diff --git a/ipc/bus1/main.c b/ipc/bus1/main.c
new file mode 100644
index 0000000..02412a7
--- /dev/null
+++ b/ipc/bus1/main.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include "main.h"
+#include "tests.h"
+
+static int bus1_fop_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int bus1_fop_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+const struct file_operations bus1_fops = {
+ .owner = THIS_MODULE,
+ .open = bus1_fop_open,
+ .release = bus1_fop_release,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice bus1_misc = {
+ .fops = &bus1_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = KBUILD_MODNAME,
+ .mode = S_IRUGO | S_IWUGO,
+};
+
+struct dentry *bus1_debugdir;
+
+static int __init bus1_modinit(void)
+{
+ int r;
+
+ r = bus1_tests_run();
+ if (r < 0)
+ return r;
+
+ bus1_debugdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!bus1_debugdir)
+ pr_err("cannot create debugfs root\n");
+
+ r = misc_register(&bus1_misc);
+ if (r < 0)
+ goto error;
+
+ pr_info("loaded\n");
+ return 0;
+
+error:
+ debugfs_remove(bus1_debugdir);
+ return r;
+}
+
+static void __exit bus1_modexit(void)
+{
+ misc_deregister(&bus1_misc);
+ debugfs_remove(bus1_debugdir);
+ pr_info("unloaded\n");
+}
+
+module_init(bus1_modinit);
+module_exit(bus1_modexit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Bus based interprocess communication");
diff --git a/ipc/bus1/main.h b/ipc/bus1/main.h
new file mode 100644
index 0000000..76fce66
--- /dev/null
+++ b/ipc/bus1/main.h
@@ -0,0 +1,74 @@
+#ifndef __BUS1_MAIN_H
+#define __BUS1_MAIN_H
+
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+/**
+ * DOC: Bus1 Overview
+ *
+ * bus1 is a local IPC system, which provides a decentralized infrastructure to
+ * share objects between local peers. The main building blocks are nodes and
+ * handles. Nodes represent objects of a local peer, while handles represent
+ * descriptors that point to a node. Nodes can be created and destroyed by any
+ * peer, and they will always remain owned by their respective creator. Handles,
+ * on the other hand, are used to refer to nodes and can be passed around with
+ * messages as auxiliary data. Whenever a handle is transferred, the receiver
+ * will get its own handle allocated, pointing to the same node as the original
+ * handle.
+ *
+ * Any peer can send messages directed at one of their handles. This will
+ * transfer the message to the owner of the node the handle points to. If a
+ * peer does not posess a handle to a given node, it will not be able to send a
+ * message to that node. That is, handles provide exclusive access management.
+ * Anyone that somehow acquired a handle to a node is privileged to further
+ * send this handle to other peers. As such, access management is transitive.
+ * Once a peer acquired a handle, it cannot be revoked again. However, a node
+ * owner can, at anytime, destroy a node. This will effectively unbind all
+ * existing handles to that node on any peer, notifying each one of the
+ * destruction.
+ *
+ * Unlike nodes and handles, peers cannot be addressed directly. In fact, peers
+ * are completely disconnected entities. A peer is merely an anchor of a set of
+ * nodes and handles, including an incoming message queue for any of those.
+ * Whether multiple nodes are all part of the same peer, or part of different
+ * peers does not affect the remote view of those. Peers solely exist as
+ * management entity and command dispatcher to local processes.
+ *
+ * The set of actors on a system is completely decentralized. There is no
+ * global component involved that provides a central registry or discovery
+ * mechanism. Furthermore, communication between peers only involves those
+ * peers, and does not affect any other peer in any way. No global
+ * communication lock is taken. However, any communication is still globally
+ * ordered, including unicasts, multicasts, and notifications.
+ */
+
+struct dentry;
+struct file_operations;
+
+/**
+ * bus1_fops - file-operations of bus1 character devices
+ *
+ * All bus1 peers are backed by a character device with @bus1_fops used as
+ * file-operations. That is, a file is a bus1 peer if, and only if, its f_op
+ * pointer contains @bus1_fops.
+ */
+extern const struct file_operations bus1_fops;
+
+/**
+ * bus1_debugdir - debugfs root directory
+ *
+ * If debugfs is enabled, this is set to point to the debugfs root directory
+ * for this module. If debugfs is disabled, or if the root directory could not
+ * be created, this is set to NULL or ERR_PTR (which debugfs functions can deal
+ * with seamlessly).
+ */
+extern struct dentry *bus1_debugdir;
+
+#endif /* __BUS1_MAIN_H */
diff --git a/ipc/bus1/tests.c b/ipc/bus1/tests.c
new file mode 100644
index 0000000..6fd2946
--- /dev/null
+++ b/ipc/bus1/tests.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include "tests.h"
+
+int bus1_tests_run(void)
+{
+ pr_info("run selftests..\n");
+ return 0;
+}
diff --git a/ipc/bus1/tests.h b/ipc/bus1/tests.h
new file mode 100644
index 0000000..fb554e2
--- /dev/null
+++ b/ipc/bus1/tests.h
@@ -0,0 +1,32 @@
+#ifndef __BUS1_TESTS_H
+#define __BUS1_TESTS_H
+
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+/**
+ * Kernel Selftests
+ *
+ * These tests are built into the kernel module itself if, and only if, the
+ * required configuration is selected. On every module load, the selftests will
+ * be run. On production builds, this option should not be selected.
+ */
+
+#include <linux/kernel.h>
+
+#if IS_ENABLED(CONFIG_BUS1_TESTS)
+int bus1_tests_run(void);
+#else
+static inline int bus1_tests_run(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* __BUS1_TESTS_H */
--
2.10.1