[RFC v1 11/14] bus1: implement message transmission

2016-10-26 Thread David Herrmann
From: Tom Gundersen 

While notifications already work and simply require linking bus1_handle
objects into the destination queue, real messages require proper
payloads. This implements two core objects: Message objects and
factories.

The message factory is similar to transaction contexts, and lives
completely on the stack. It is used to import the parameters given by
user-space in a SEND ioctl. It parses and validates them. With this
message factors we can now instantiate many messages, one for each
destination of a multicast.

Messages need to carry a bunch of data, mainly:
  - metadata: This just matches what Unix-sockets do (uid, gid, pid,
  tid, and secctx)
  - payload: Random memory passed in as iovec-array by user-space
  - files: Set of file-descriptors, very similar to SCM_RIGHTS
  - handles: Set of local handles to transfer to the destination

Signed-off-by: Tom Gundersen 
Signed-off-by: David Herrmann 
---
 ipc/bus1/Makefile  |   1 +
 ipc/bus1/message.c | 613 +
 ipc/bus1/message.h | 171 +++
 ipc/bus1/peer.c|   2 +
 ipc/bus1/peer.h|   2 +
 ipc/bus1/util.c| 162 ++
 ipc/bus1/util.h|   7 +
 7 files changed, 958 insertions(+)
 create mode 100644 ipc/bus1/message.c
 create mode 100644 ipc/bus1/message.h

diff --git a/ipc/bus1/Makefile b/ipc/bus1/Makefile
index b87cddb..05434bda 100644
--- a/ipc/bus1/Makefile
+++ b/ipc/bus1/Makefile
@@ -1,6 +1,7 @@
 bus1-y :=  \
handle.o\
main.o  \
+   message.o   \
peer.o  \
tx.o\
user.o  \
diff --git a/ipc/bus1/message.c b/ipc/bus1/message.c
new file mode 100644
index 000..4c5c905
--- /dev/null
+++ b/ipc/bus1/message.c
@@ -0,0 +1,613 @@
+/*
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "handle.h"
+#include "message.h"
+#include "peer.h"
+#include "tx.h"
+#include "user.h"
+#include "util.h"
+#include "util/flist.h"
+#include "util/pool.h"
+#include "util/queue.h"
+
+static size_t bus1_factory_size(struct bus1_cmd_send *param)
+{
+   /* make sure @size cannot overflow */
+   BUILD_BUG_ON(UIO_MAXIOV > U16_MAX);
+   BUILD_BUG_ON(BUS1_FD_MAX > U16_MAX);
+
+   /* make sure we do not violate alignment rules */
+   BUILD_BUG_ON(__alignof(struct bus1_flist) < __alignof(struct iovec));
+   BUILD_BUG_ON(__alignof(struct iovec) < __alignof(struct file *));
+
+   return sizeof(struct bus1_factory) +
+  bus1_flist_inline_size(param->n_handles) +
+  param->n_vecs * sizeof(struct iovec) +
+  param->n_fds * sizeof(struct file *);
+}
+
+/**
+ * bus1_factory_new() - create new message factory
+ * @peer:  peer to operate as
+ * @param: factory parameters
+ * @stack: optional stack for factory, or NULL
+ * @n_stack:   size of space at @stack
+ *
+ * This allocates a new message factory. It imports data from @param and
+ * prepares the factory for a transaction. From this factory, messages can be
+ * instantiated. This is used both for unicasts and multicasts.
+ *
+ * If @stack is given, this tries to place the factory on the specified stack
+ * space. The caller must guarantee that the factory does not outlive the stack
+ * frame. If this is not wanted, pass 0 as @n_stack.
+ * In either case, if the stack frame is too small, this will allocate the
+ * factory on the heap.
+ *
+ * Return: Pointer to factory, or ERR_PTR on failure.
+ */
+struct bus1_factory *bus1_factory_new(struct bus1_peer *peer,
+ struct bus1_cmd_send *param,
+ void *stack,
+ size_t n_stack)
+{
+   const struct iovec __user *ptr_vecs;
+   const u64 __user *ptr_handles;
+   const int __user *ptr_fds;
+   struct bus1_factory *f;
+   struct bus1_flist *e;
+   struct file *file;
+   size_t i, size;
+   bool is_new;
+   int r, fd;
+   u32 sid;
+   u64 id;
+
+   lockdep_assert_held(>local.lock);
+
+   size = bus1_factory_size(param);
+   if (unlikely(size > n_stack)) {
+   f = kmalloc(size, GFP_TEMPORARY);
+   if (!f)
+   return ERR_PTR(-ENOMEM);
+
+   f->on_stack = false;
+  

[RFC v1 11/14] bus1: implement message transmission

2016-10-26 Thread David Herrmann
From: Tom Gundersen 

While notifications already work and simply require linking bus1_handle
objects into the destination queue, real messages require proper
payloads. This implements two core objects: Message objects and
factories.

The message factory is similar to transaction contexts, and lives
completely on the stack. It is used to import the parameters given by
user-space in a SEND ioctl. It parses and validates them. With this
message factors we can now instantiate many messages, one for each
destination of a multicast.

Messages need to carry a bunch of data, mainly:
  - metadata: This just matches what Unix-sockets do (uid, gid, pid,
  tid, and secctx)
  - payload: Random memory passed in as iovec-array by user-space
  - files: Set of file-descriptors, very similar to SCM_RIGHTS
  - handles: Set of local handles to transfer to the destination

Signed-off-by: Tom Gundersen 
Signed-off-by: David Herrmann 
---
 ipc/bus1/Makefile  |   1 +
 ipc/bus1/message.c | 613 +
 ipc/bus1/message.h | 171 +++
 ipc/bus1/peer.c|   2 +
 ipc/bus1/peer.h|   2 +
 ipc/bus1/util.c| 162 ++
 ipc/bus1/util.h|   7 +
 7 files changed, 958 insertions(+)
 create mode 100644 ipc/bus1/message.c
 create mode 100644 ipc/bus1/message.h

diff --git a/ipc/bus1/Makefile b/ipc/bus1/Makefile
index b87cddb..05434bda 100644
--- a/ipc/bus1/Makefile
+++ b/ipc/bus1/Makefile
@@ -1,6 +1,7 @@
 bus1-y :=  \
handle.o\
main.o  \
+   message.o   \
peer.o  \
tx.o\
user.o  \
diff --git a/ipc/bus1/message.c b/ipc/bus1/message.c
new file mode 100644
index 000..4c5c905
--- /dev/null
+++ b/ipc/bus1/message.c
@@ -0,0 +1,613 @@
+/*
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "handle.h"
+#include "message.h"
+#include "peer.h"
+#include "tx.h"
+#include "user.h"
+#include "util.h"
+#include "util/flist.h"
+#include "util/pool.h"
+#include "util/queue.h"
+
+static size_t bus1_factory_size(struct bus1_cmd_send *param)
+{
+   /* make sure @size cannot overflow */
+   BUILD_BUG_ON(UIO_MAXIOV > U16_MAX);
+   BUILD_BUG_ON(BUS1_FD_MAX > U16_MAX);
+
+   /* make sure we do not violate alignment rules */
+   BUILD_BUG_ON(__alignof(struct bus1_flist) < __alignof(struct iovec));
+   BUILD_BUG_ON(__alignof(struct iovec) < __alignof(struct file *));
+
+   return sizeof(struct bus1_factory) +
+  bus1_flist_inline_size(param->n_handles) +
+  param->n_vecs * sizeof(struct iovec) +
+  param->n_fds * sizeof(struct file *);
+}
+
+/**
+ * bus1_factory_new() - create new message factory
+ * @peer:  peer to operate as
+ * @param: factory parameters
+ * @stack: optional stack for factory, or NULL
+ * @n_stack:   size of space at @stack
+ *
+ * This allocates a new message factory. It imports data from @param and
+ * prepares the factory for a transaction. From this factory, messages can be
+ * instantiated. This is used both for unicasts and multicasts.
+ *
+ * If @stack is given, this tries to place the factory on the specified stack
+ * space. The caller must guarantee that the factory does not outlive the stack
+ * frame. If this is not wanted, pass 0 as @n_stack.
+ * In either case, if the stack frame is too small, this will allocate the
+ * factory on the heap.
+ *
+ * Return: Pointer to factory, or ERR_PTR on failure.
+ */
+struct bus1_factory *bus1_factory_new(struct bus1_peer *peer,
+ struct bus1_cmd_send *param,
+ void *stack,
+ size_t n_stack)
+{
+   const struct iovec __user *ptr_vecs;
+   const u64 __user *ptr_handles;
+   const int __user *ptr_fds;
+   struct bus1_factory *f;
+   struct bus1_flist *e;
+   struct file *file;
+   size_t i, size;
+   bool is_new;
+   int r, fd;
+   u32 sid;
+   u64 id;
+
+   lockdep_assert_held(>local.lock);
+
+   size = bus1_factory_size(param);
+   if (unlikely(size > n_stack)) {
+   f = kmalloc(size, GFP_TEMPORARY);
+   if (!f)
+   return ERR_PTR(-ENOMEM);
+
+   f->on_stack = false;
+   } else {
+   f = stack;
+