summaryrefslogtreecommitdiffstats
path: root/kdbus.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2015-07-15 09:11:25 -0400
committerJosh Boyer <jwboyer@fedoraproject.org>2015-07-15 09:11:25 -0400
commit2079802473df0b249968a32467dbf43f2076fa87 (patch)
tree98ea883873e77b19dd7a2ddc7d8944a4c3d6d009 /kdbus.patch
parentc3a494ca7b138539d5e74d2d0ab894dccae9bcfe (diff)
downloadkernel-2079802473df0b249968a32467dbf43f2076fa87.tar.gz
kernel-2079802473df0b249968a32467dbf43f2076fa87.tar.xz
kernel-2079802473df0b249968a32467dbf43f2076fa87.zip
Update kdbus to latest upstream kdbus-next
Grab the larger rework and fixes from David Herrmann (up to commit eee8b5b3ceaeca1b1b998552cd6c9f9dea8938e5)
Diffstat (limited to 'kdbus.patch')
-rw-r--r--kdbus.patch8579
1 files changed, 8579 insertions, 0 deletions
diff --git a/kdbus.patch b/kdbus.patch
index 896819d9c..a37878c26 100644
--- a/kdbus.patch
+++ b/kdbus.patch
@@ -40479,3 +40479,8582 @@ index 707be05..9993753 100644
}
--
2.4.3
+From 7d894da303164a38522eaac6e95ee558423b9272 Mon Sep 17 00:00:00 2001
+From: Markus Elfring <elfring@users.sourceforge.net>
+Date: Wed, 24 Jun 2015 14:30:17 +0200
+Subject: [PATCH 01/34] kdbus: delete unnecessary check before
+ kdbus_domain_unref
+
+The kdbus_domain_unref() function tests whether its argument is NULL
+and then returns immediately. Thus the test around the call is not needed.
+
+This issue was detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
+(shorten commit-message-head slightly)
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/fs.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c
+index d01f33baaa0d..205a3adaa2ab 100644
+--- a/ipc/kdbus/fs.c
++++ b/ipc/kdbus/fs.c
+@@ -325,9 +325,7 @@ static void fs_super_kill(struct super_block *sb)
+ }
+
+ kill_anon_super(sb);
+-
+- if (domain)
+- kdbus_domain_unref(domain);
++ kdbus_domain_unref(domain);
+ }
+
+ static int fs_super_set(struct super_block *sb, void *data)
+--
+2.4.3
+
+
+From b57a271a7a2c5bac0fdfa848481bca55dc1d1336 Mon Sep 17 00:00:00 2001
+From: Sergei Zviagintsev <sergei@s15v.net>
+Date: Sun, 28 Jun 2015 16:17:30 +0300
+Subject: [PATCH 02/34] kdbus: fix typos in kdbus_conn_quota_inc()
+
+Signed-off-by: Sergei Zviagintsev <sergei@s15v.net>
+Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 9993753d11de..df072487e23c 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -646,7 +646,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u,
+ * allocation schemes. Furthermore, resource utilization should be
+ * maximized, so only minimal resources stay reserved. However, we need
+ * to adapt to a dynamic number of users, as we cannot know how many
+- * users will talk to a connection. Therefore, the current allocations
++ * users will talk to a connection. Therefore, the current allocation
+ * works like this:
+ * We limit the number of bytes in a destination's pool per sending
+ * user. The space available for a user is 33% of the unused pool space
+@@ -688,7 +688,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u,
+
+ /*
+ * Pool owner slices are un-accounted slices; they can claim more
+- * than 50% of the queue. However, the slice we're dealing with here
++ * than 50% of the queue. However, the slices we're dealing with here
+ * belong to the incoming queue, hence they are 'accounted' slices
+ * to which the 50%-limit applies.
+ */
+--
+2.4.3
+
+
+From c1bddc44862c977384e66aea1d2be7ded9fb0f0e Mon Sep 17 00:00:00 2001
+From: Sergei Zviagintsev <sergei@s15v.net>
+Date: Sun, 28 Jun 2015 16:17:31 +0300
+Subject: [PATCH 03/34] kdbus: use standard kernel types in struct kdbus_quota
+
+uint{8,16,32}_t -> u{8,16,32}
+
+Signed-off-by: Sergei Zviagintsev <sergei@s15v.net>
+Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index df072487e23c..af044f93c14f 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -606,9 +606,9 @@ bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name)
+ }
+
+ struct kdbus_quota {
+- uint32_t memory;
+- uint16_t msgs;
+- uint8_t fds;
++ u32 memory;
++ u16 msgs;
++ u8 fds;
+ };
+
+ /**
+--
+2.4.3
+
+
+From eb526cf227f121c8320275dde32d18495631a622 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Tue, 9 Jun 2015 09:41:40 +0200
+Subject: [PATCH 04/34] kdbus/selftests: fix CAP translation tests
+
+We now support CAP translations. Make sure our tests reflect that. So far
+they made sure we drop CAPS on namespace borders. This is wrong, though.
+We really need to just make sure that no _or_ the correctly translated
+caps are returned. Fix this.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ tools/testing/selftests/kdbus/test-metadata-ns.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c
+index ccdfae06922b..1f6edc09008a 100644
+--- a/tools/testing/selftests/kdbus/test-metadata-ns.c
++++ b/tools/testing/selftests/kdbus/test-metadata-ns.c
+@@ -168,9 +168,8 @@ static int __kdbus_clone_userns_test(const char *bus,
+ ASSERT_EXIT(ret == 0);
+ ASSERT_EXIT(msg->dst_id == userns_conn->id);
+
+- /* Different namespaces no CAPS */
+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
+- ASSERT_EXIT(item == NULL);
++ ASSERT_EXIT(item);
+
+ /* uid/gid not mapped, so we have unpriv cached creds */
+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
+@@ -196,9 +195,8 @@ static int __kdbus_clone_userns_test(const char *bus,
+ ASSERT_EXIT(ret == 0);
+ ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
+
+- /* Different namespaces no CAPS */
+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
+- ASSERT_EXIT(item == NULL);
++ ASSERT_EXIT(item);
+
+ /* uid/gid not mapped, so we have unpriv cached creds */
+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
+@@ -358,9 +356,8 @@ static int kdbus_clone_userns_test(const char *bus,
+
+ userns_conn_id = msg->src_id;
+
+- /* We do not share the userns, os no KDBUS_ITEM_CAPS */
+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
+- ASSERT_RETURN(item == NULL);
++ ASSERT_RETURN(item);
+
+ /*
+ * Compare received items, creds must be translated into
+--
+2.4.3
+
+
+From 42c6f60d15f3a359e0d779f7af4a8ee51144e16d Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 15 Jun 2015 12:20:28 +0200
+Subject: [PATCH 05/34] kdbus: drop redundant KDBUS_MSG_MAX_ITEMS
+
+We already limit the size of the message object, there's no reason to add
+an arbitrary additional limit on the number of items. We don't do this for
+other item-arrays, so lets stop restricting the messages in this way.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/limits.h | 3 ---
+ ipc/kdbus/message.c | 12 ++++--------
+ 2 files changed, 4 insertions(+), 11 deletions(-)
+
+diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h
+index 6450f58cffcf..c54925a25971 100644
+--- a/ipc/kdbus/limits.h
++++ b/ipc/kdbus/limits.h
+@@ -19,9 +19,6 @@
+ /* maximum size of message header and items */
+ #define KDBUS_MSG_MAX_SIZE SZ_8K
+
+-/* maximum number of message items */
+-#define KDBUS_MSG_MAX_ITEMS 128
+-
+ /* maximum number of memfd items per message */
+ #define KDBUS_MSG_MAX_MEMFD_ITEMS 16
+
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 066e816dfdea..e9da67229eb1 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -214,7 +214,7 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg,
+ struct kdbus_msg_resources *res = kmsg->res;
+ const struct kdbus_msg *msg = &kmsg->msg;
+ const struct kdbus_item *item;
+- size_t n, n_vecs, n_memfds;
++ size_t n_res, n_vecs, n_memfds;
+ bool has_bloom = false;
+ bool has_name = false;
+ bool has_fds = false;
+@@ -243,9 +243,9 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg,
+ }
+ }
+
+- n = n_vecs + n_memfds;
+- if (n > 0) {
+- res->data = kcalloc(n, sizeof(*res->data), GFP_KERNEL);
++ n_res = n_vecs + n_memfds;
++ if (n_res > 0) {
++ res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL);
+ if (!res->data)
+ return -ENOMEM;
+ }
+@@ -257,15 +257,11 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg,
+ }
+
+ /* import data payloads */
+- n = 0;
+ vec_size = 0;
+ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) {
+ size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item);
+ struct iovec *iov = kmsg->iov + kmsg->iov_count;
+
+- if (++n > KDBUS_MSG_MAX_ITEMS)
+- return -E2BIG;
+-
+ switch (item->type) {
+ case KDBUS_ITEM_PAYLOAD_VEC: {
+ struct kdbus_msg_data *d = res->data + res->data_count;
+--
+2.4.3
+
+
+From 80c15dbf8b5eff74a41ceae7d83e9fcf8abf9df9 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 17:08:08 +0200
+Subject: [PATCH 06/34] kdbus: drop unused 'bloom_generation' field
+
+This field is never used, drop it.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/message.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index cdaa65c4e6ae..3b733474f335 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -88,7 +88,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
+ * @notify_name: Short-cut for faster lookup
+ * @dst_name_id: Short-cut to msg for faster lookup
+ * @bloom_filter: Bloom filter to match message properties
+- * @bloom_generation: Generation of bloom element set
+ * @notify_entry: List of kernel-generated notifications
+ * @iov: Array of iovec, describing the payload to copy
+ * @iov_count: Number of array members in @iov
+@@ -107,7 +106,6 @@ struct kdbus_kmsg {
+
+ u64 dst_name_id;
+ const struct kdbus_bloom_filter *bloom_filter;
+- u64 bloom_generation;
+ struct list_head notify_entry;
+
+ struct iovec *iov;
+--
+2.4.3
+
+
+From fb1fa875dc1df36250e92085b914d9d5c5e952d3 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 5 Jun 2015 15:30:40 +0200
+Subject: [PATCH 07/34] kdbus: drop support for required attach-flags on buses
+
+This drops the KDBUS_ITEM_ATTACH_FLAGS_RECV item from KDBUS_CMD_BUS_MAKE.
+This item was used to provide an attach-flags mask which defines metadata
+items that all connections must have in their send-mask. Hence,
+effectively forcing the transmission of such items in case the receiver
+wants them.
+
+This was never used by any code and is of questionable use. With our new
+effort to make sure metadata items are only transmitted if the receiver
+has actual access to the same data via /proc, this is no longer needed.
+Drop support for this item now.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ Documentation/kdbus/kdbus.bus.xml | 15 ---------------
+ Documentation/kdbus/kdbus.connection.xml | 8 +-------
+ ipc/kdbus/bus.c | 10 ----------
+ ipc/kdbus/bus.h | 2 --
+ ipc/kdbus/connection.c | 10 ----------
+ tools/testing/selftests/kdbus/kdbus-test.c | 1 -
+ tools/testing/selftests/kdbus/kdbus-util.c | 20 +++++++-------------
+ tools/testing/selftests/kdbus/kdbus-util.h | 3 +--
+ tools/testing/selftests/kdbus/test-connection.c | 9 ---------
+ 9 files changed, 9 insertions(+), 69 deletions(-)
+
+diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml
+index 4b9a0ac1b351..83f1198bc6a1 100644
+--- a/Documentation/kdbus/kdbus.bus.xml
++++ b/Documentation/kdbus/kdbus.bus.xml
+@@ -198,21 +198,6 @@ struct kdbus_cmd {
+ </varlistentry>
+
+ <varlistentry>
+- <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term>
+- <listitem>
+- <para>
+- An optional item that contains a set of required attach flags
+- that connections must allow. This item is used as a
+- negotiation measure during connection creation. If connections
+- do not satisfy the bus requirements, they are not allowed on
+- the bus. If not set, the bus does not require any metadata to
+- be attached; in this case connections are free to set their
+- own attach flags.
+- </para>
+- </listitem>
+- </varlistentry>
+-
+- <varlistentry>
+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term>
+ <listitem>
+ <para>
+diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml
+index cefb419f1093..4bb5f30f379a 100644
+--- a/Documentation/kdbus/kdbus.connection.xml
++++ b/Documentation/kdbus/kdbus.connection.xml
+@@ -355,13 +355,7 @@ struct kdbus_cmd_hello {
+ Set the bits for metadata this connection permits to be sent to the
+ receiving peer. Only metadata items that are both allowed to be sent
+ by the sender and that are requested by the receiver will be attached
+- to the message. Note, however, that the bus may optionally require
+- some of those bits to be set. If the match fails, the ioctl will fail
+- with <varname>errno</varname> set to
+- <constant>ECONNREFUSED</constant>. In either case, when returning the
+- field will be set to the mask of metadata items that are enforced by
+- the bus with the <constant>KDBUS_FLAGS_KERNEL</constant> bit set as
+- well.
++ to the message.
+ </para></listitem>
+ </varlistentry>
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index bbdf0f2f391e..7d2c336213ad 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -66,23 +66,16 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
+ const char *name,
+ struct kdbus_bloom_parameter *bloom,
+ const u64 *pattach_owner,
+- const u64 *pattach_recv,
+ u64 flags, kuid_t uid, kgid_t gid)
+ {
+ struct kdbus_bus *b;
+ u64 attach_owner;
+- u64 attach_recv;
+ int ret;
+
+ if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE ||
+ !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1)
+ return ERR_PTR(-EINVAL);
+
+- ret = kdbus_sanitize_attach_flags(pattach_recv ? *pattach_recv : 0,
+- &attach_recv);
+- if (ret < 0)
+- return ERR_PTR(ret);
+-
+ ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0,
+ &attach_owner);
+ if (ret < 0)
+@@ -111,7 +104,6 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
+
+ b->id = atomic64_inc_return(&domain->last_id);
+ b->bus_flags = flags;
+- b->attach_flags_req = attach_recv;
+ b->attach_flags_owner = attach_owner;
+ generate_random_uuid(b->id128);
+ b->bloom = *bloom;
+@@ -380,7 +372,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain,
+ { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true },
+ { .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true },
+ { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND },
+- { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV },
+ };
+ struct kdbus_args args = {
+ .allowed_flags = KDBUS_FLAG_NEGOTIATE |
+@@ -399,7 +390,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain,
+ bus = kdbus_bus_new(domain,
+ argv[1].item->str, &argv[2].item->bloom_parameter,
+ argv[3].item ? argv[3].item->data64 : NULL,
+- argv[4].item ? argv[4].item->data64 : NULL,
+ cmd->flags, current_euid(), current_egid());
+ if (IS_ERR(bus)) {
+ ret = PTR_ERR(bus);
+diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
+index 5bea5ef768f1..e019ef34534c 100644
+--- a/ipc/kdbus/bus.h
++++ b/ipc/kdbus/bus.h
+@@ -37,7 +37,6 @@ struct kdbus_user;
+ * @node: kdbus_node
+ * @id: ID of this bus in the domain
+ * @bus_flags: Simple pass-through flags from userspace to userspace
+- * @attach_flags_req: KDBUS_ATTACH_* flags required by connecting peers
+ * @attach_flags_owner: KDBUS_ATTACH_* flags of bus creator that other
+ * connections can see or query
+ * @id128: Unique random 128 bit ID of this bus
+@@ -60,7 +59,6 @@ struct kdbus_bus {
+ /* static */
+ u64 id;
+ u64 bus_flags;
+- u64 attach_flags_req;
+ u64 attach_flags_owner;
+ u8 id128[16];
+ struct kdbus_bloom_parameter bloom;
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index af044f93c14f..02e3ce735034 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -112,10 +112,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+- /* The attach flags must always satisfy the bus requirements. */
+- if (bus->attach_flags_req & ~attach_flags_send)
+- return ERR_PTR(-ECONNREFUSED);
+-
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ return ERR_PTR(-ENOMEM);
+@@ -1835,7 +1831,6 @@ exit:
+ */
+ int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp)
+ {
+- struct kdbus_bus *bus = conn->ep->bus;
+ struct kdbus_item *item_policy;
+ u64 *item_attach_send = NULL;
+ u64 *item_attach_recv = NULL;
+@@ -1876,11 +1871,6 @@ int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp)
+ &attach_send);
+ if (ret < 0)
+ goto exit;
+-
+- if (bus->attach_flags_req & ~attach_send) {
+- ret = -EINVAL;
+- goto exit;
+- }
+ }
+
+ if (item_attach_recv) {
+diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c
+index 294e82a83ab6..db732e59650a 100644
+--- a/tools/testing/selftests/kdbus/kdbus-test.c
++++ b/tools/testing/selftests/kdbus/kdbus-test.c
+@@ -299,7 +299,6 @@ static int test_prepare_env(const struct kdbus_test *t,
+
+ ret = kdbus_create_bus(env->control_fd,
+ args->busname ?: n,
+- _KDBUS_ATTACH_ALL,
+ _KDBUS_ATTACH_ALL, &s);
+ free(n);
+ ASSERT_RETURN(ret == 0);
+diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c
+index 29a0cb1aace2..a5e54ca3a492 100644
+--- a/tools/testing/selftests/kdbus/kdbus-util.c
++++ b/tools/testing/selftests/kdbus/kdbus-util.c
+@@ -114,8 +114,7 @@ int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask)
+ }
+
+ int kdbus_create_bus(int control_fd, const char *name,
+- uint64_t req_meta, uint64_t owner_meta,
+- char **path)
++ uint64_t owner_meta, char **path)
+ {
+ struct {
+ struct kdbus_cmd cmd;
+@@ -127,12 +126,12 @@ int kdbus_create_bus(int control_fd, const char *name,
+ struct kdbus_bloom_parameter bloom;
+ } bp;
+
+- /* required and owner metadata items */
++ /* owner metadata items */
+ struct {
+ uint64_t size;
+ uint64_t type;
+ uint64_t flags;
+- } attach[2];
++ } attach;
+
+ /* name item */
+ struct {
+@@ -152,13 +151,9 @@ int kdbus_create_bus(int control_fd, const char *name,
+ snprintf(bus_make.name.str, sizeof(bus_make.name.str),
+ "%u-%s", getuid(), name);
+
+- bus_make.attach[0].type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
+- bus_make.attach[0].size = sizeof(bus_make.attach[0]);
+- bus_make.attach[0].flags = req_meta;
+-
+- bus_make.attach[1].type = KDBUS_ITEM_ATTACH_FLAGS_SEND;
+- bus_make.attach[1].size = sizeof(bus_make.attach[0]);
+- bus_make.attach[1].flags = owner_meta;
++ bus_make.attach.type = KDBUS_ITEM_ATTACH_FLAGS_SEND;
++ bus_make.attach.size = sizeof(bus_make.attach);
++ bus_make.attach.flags = owner_meta;
+
+ bus_make.name.type = KDBUS_ITEM_MAKE_NAME;
+ bus_make.name.size = KDBUS_ITEM_HEADER_SIZE +
+@@ -167,8 +162,7 @@ int kdbus_create_bus(int control_fd, const char *name,
+ bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD;
+ bus_make.cmd.size = sizeof(bus_make.cmd) +
+ bus_make.bp.size +
+- bus_make.attach[0].size +
+- bus_make.attach[1].size +
++ bus_make.attach.size +
+ bus_make.name.size;
+
+ kdbus_printf("Creating bus with name >%s< on control fd %d ...\n",
+diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h
+index d1a0f1b4d0eb..e1e18b92f425 100644
+--- a/tools/testing/selftests/kdbus/kdbus-util.h
++++ b/tools/testing/selftests/kdbus/kdbus-util.h
+@@ -168,8 +168,7 @@ int kdbus_free(const struct kdbus_conn *conn, uint64_t offset);
+ int kdbus_msg_dump(const struct kdbus_conn *conn,
+ const struct kdbus_msg *msg);
+ int kdbus_create_bus(int control_fd, const char *name,
+- uint64_t req_meta, uint64_t owner_meta,
+- char **path);
++ uint64_t owner_meta, char **path);
+ int kdbus_msg_send(const struct kdbus_conn *conn, const char *name,
+ uint64_t cookie, uint64_t flags, uint64_t timeout,
+ int64_t priority, uint64_t dst_id);
+diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c
+index e7c486621b04..4688ce8ec40b 100644
+--- a/tools/testing/selftests/kdbus/test-connection.c
++++ b/tools/testing/selftests/kdbus/test-connection.c
+@@ -70,15 +70,6 @@ int kdbus_test_hello(struct kdbus_test_env *env)
+
+ hello.pool_size = POOL_SIZE;
+
+- /*
+- * The connection created by the core requires ALL meta flags
+- * to be sent. An attempt to send less than that should result in
+- * -ECONNREFUSED.
+- */
+- hello.attach_flags_send = _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP;
+- ret = kdbus_cmd_hello(fd, &hello);
+- ASSERT_RETURN(ret == -ECONNREFUSED);
+-
+ hello.attach_flags_send = _KDBUS_ATTACH_ALL;
+ hello.offset = (__u64)-1;
+
+--
+2.4.3
+
+
+From c2bc012ac7da42acdeb079cc1ef4ea25b67d0b74 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Tue, 9 Jun 2015 09:43:47 +0200
+Subject: [PATCH 08/34] kdbus: pin namespaces on HELLO
+
+Whenever we send messages to a target connection, all we know about the
+target is the 'struct file' associated with the kdbus connection. Hence,
+we cannot know which namespaces a receiving process will be in when it
+calls KDBUS_CMD_RECV on the message. So far, we pinned all metadata we
+wanna send and translate it on RECV-time, since we then know the exact
+namespaces to translate into.
+
+This has several drawbacks:
+ - Depending on the process calling RECV, the behavior is different (as
+ multiple processes might be in different namespaces but share the same
+ fd). This is unwanted behavior, as described by Eric here:
+ http://www.spinics.net/lists/netdev/msg329322.html
+ - We need to pin metadata with a message instead of translating it right
+ away.
+ - We cannot prep a message at SEND time as we don't know the size of the
+ translated metadata. Hence, we need to do all that at RECV time.
+
+This patch changes the namespace behavior. Instead of using the namespaces
+at RECV time, we now pin the namespaces at HELLO (i.e., open()). So
+regardless who calls RECV on this file-descriptor, the same namespaces
+will be used.
+This gives us the advantage that we now always know the target namespaces
+for a message. Hence, we can now properly prep a message at SEND time and
+never have to carry any metadata pins around.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 2 +-
+ ipc/kdbus/connection.c | 8 +++++++-
+ ipc/kdbus/connection.h | 6 ++++++
+ ipc/kdbus/metadata.c | 54 ++++++++++++++++++++++++++------------------------
+ ipc/kdbus/metadata.h | 1 +
+ ipc/kdbus/queue.c | 1 +
+ 6 files changed, 44 insertions(+), 28 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 7d2c336213ad..8fffc2f594a8 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -507,7 +507,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(bus->creator_meta, NULL, attach_flags,
++ ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags,
+ slice, hdr_size, &meta_size);
+ if (ret < 0)
+ goto exit;
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 02e3ce735034..ca241fcf19f7 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -130,6 +130,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+ atomic_set(&conn->lost_count, 0);
+ INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
+ conn->cred = get_current_cred();
++ conn->user_ns = get_user_ns(current_user_ns());
++ conn->pid_ns = get_pid_ns(task_active_pid_ns(current));
++ get_fs_root(current->fs, &conn->root_path);
+ init_waitqueue_head(&conn->wait);
+ kdbus_queue_init(&conn->queue);
+ conn->privileged = privileged;
+@@ -271,6 +274,9 @@ static void __kdbus_conn_free(struct kref *kref)
+ kdbus_match_db_free(conn->match_db);
+ kdbus_pool_free(conn->pool);
+ kdbus_ep_unref(conn->ep);
++ path_put(&conn->root_path);
++ put_pid_ns(conn->pid_ns);
++ put_user_ns(conn->user_ns);
+ put_cred(conn->cred);
+ kfree(conn->description);
+ kfree(conn->quota);
+@@ -1792,7 +1798,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(owner_conn->meta, conn_meta, attach_flags,
++ ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags,
+ slice, sizeof(info), &meta_size);
+ if (ret < 0)
+ goto exit;
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index d1ffe909cb31..226f3ff60e31 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -59,6 +59,9 @@ struct kdbus_kmsg;
+ * @pool: The user's buffer to receive messages
+ * @user: Owner of the connection
+ * @cred: The credentials of the connection at creation time
++ * @user_ns: User namespace at creation time
++ * @pid_ns: Pid namespace at creation time
++ * @root_path: Root path at creation time
+ * @name_count: Number of owned well-known names
+ * @request_count: Number of pending requests issued by this
+ * connection that are waiting for replies from
+@@ -97,6 +100,9 @@ struct kdbus_conn {
+ struct kdbus_pool *pool;
+ struct kdbus_user *user;
+ const struct cred *cred;
++ struct user_namespace *user_ns;
++ struct pid_namespace *pid_ns;
++ struct path root_path;
+ atomic_t name_count;
+ atomic_t request_count;
+ atomic_t lost_count;
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index c36b9cc67637..79f0e8c7f4a3 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -888,7 +888,8 @@ static int kdbus_meta_push_kvec(struct kvec *kvec,
+ }
+
+ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
+- struct kdbus_meta_proc *mp)
++ struct kdbus_meta_proc *mp,
++ struct user_namespace *user_ns)
+ {
+ struct user_namespace *iter;
+ const struct cred *cred = mp->cred;
+@@ -896,18 +897,18 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
+ int i;
+
+ /*
+- * This translates the effective capabilities of 'cred' into the current
+- * user-namespace. If the current user-namespace is a child-namespace of
++ * This translates the effective capabilities of 'cred' into the given
++ * user-namespace. If the given user-namespace is a child-namespace of
+ * the user-namespace of 'cred', the mask can be copied verbatim. If
+ * not, the mask is cleared.
+ * There's one exception: If 'cred' is the owner of any user-namespace
+- * in the path between the current user-namespace and the user-namespace
++ * in the path between the given user-namespace and the user-namespace
+ * of 'cred', then it has all effective capabilities set. This means,
+ * the user who created a user-namespace always has all effective
+ * capabilities in any child namespaces. Note that this is based on the
+ * uid of the namespace creator, not the task hierarchy.
+ */
+- for (iter = current_user_ns(); iter; iter = iter->parent) {
++ for (iter = user_ns; iter; iter = iter->parent) {
+ if (iter == cred->user_ns) {
+ parent = true;
+ break;
+@@ -951,23 +952,22 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
+ }
+
+ /* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */
+-static uid_t kdbus_from_kuid_keep(kuid_t uid)
++static uid_t kdbus_from_kuid_keep(struct user_namespace *ns, kuid_t uid)
+ {
+- return uid_valid(uid) ?
+- from_kuid_munged(current_user_ns(), uid) : ((uid_t)-1);
++ return uid_valid(uid) ? from_kuid_munged(ns, uid) : ((uid_t)-1);
+ }
+
+ /* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */
+-static gid_t kdbus_from_kgid_keep(kgid_t gid)
++static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid)
+ {
+- return gid_valid(gid) ?
+- from_kgid_munged(current_user_ns(), gid) : ((gid_t)-1);
++ return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1);
+ }
+
+ /**
+ * kdbus_meta_export() - export information from metadata into a slice
+ * @mp: Process metadata, or NULL
+ * @mc: Connection metadata, or NULL
++ * @conn: Target connection to translate metadata into
+ * @mask: Mask of KDBUS_ATTACH_* flags to export
+ * @slice: The slice to export to
+ * @offset: The offset inside @slice to write to
+@@ -983,18 +983,19 @@ static gid_t kdbus_from_kgid_keep(kgid_t gid)
+ * kdbus_meta_export_prepare(); depending on the namespaces in question, it
+ * might use up less than that.
+ *
+- * All information will be translated using the current namespaces.
++ * All information will be translated using the namespaces of @conn.
+ *
+ * Return: 0 on success, negative error number otherwise.
+ */
+ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_conn *mc,
++ struct kdbus_conn *conn,
+ u64 mask,
+ struct kdbus_pool_slice *slice,
+ off_t offset,
+ size_t *real_size)
+ {
+- struct user_namespace *user_ns = current_user_ns();
++ struct user_namespace *user_ns = conn->user_ns;
+ struct kdbus_item_header item_hdr[13], *hdr;
+ char *exe_pathname = NULL;
+ struct kdbus_creds creds;
+@@ -1016,23 +1017,23 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ /* process metadata */
+
+ if (mp && (mask & KDBUS_ATTACH_CREDS)) {
+- creds.uid = kdbus_from_kuid_keep(mp->uid);
+- creds.euid = kdbus_from_kuid_keep(mp->euid);
+- creds.suid = kdbus_from_kuid_keep(mp->suid);
+- creds.fsuid = kdbus_from_kuid_keep(mp->fsuid);
+- creds.gid = kdbus_from_kgid_keep(mp->gid);
+- creds.egid = kdbus_from_kgid_keep(mp->egid);
+- creds.sgid = kdbus_from_kgid_keep(mp->sgid);
+- creds.fsgid = kdbus_from_kgid_keep(mp->fsgid);
++ creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid);
++ creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid);
++ creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid);
++ creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid);
++ creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid);
++ creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid);
++ creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid);
++ creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid);
+
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
+ &creds, sizeof(creds), &size);
+ }
+
+ if (mp && (mask & KDBUS_ATTACH_PIDS)) {
+- pids.pid = pid_vnr(mp->tgid);
+- pids.tid = pid_vnr(mp->pid);
+- pids.ppid = pid_vnr(mp->ppid);
++ pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns);
++ pids.tid = pid_nr_ns(mp->pid, conn->pid_ns);
++ pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns);
+
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS,
+ &pids, sizeof(pids), &size);
+@@ -1078,7 +1079,8 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ */
+
+ get_fs_root(current->fs, &p);
+- if (path_equal(&p, &mp->root_path)) {
++ if (path_equal(&p, &mp->root_path) &&
++ path_equal(&p, &conn->root_path)) {
+ exe_page = (void *)__get_free_page(GFP_TEMPORARY);
+ if (!exe_page) {
+ path_put(&p);
+@@ -1116,7 +1118,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ if (mp && (mask & KDBUS_ATTACH_CAPS)) {
+ struct kdbus_meta_caps caps = {};
+
+- kdbus_meta_export_caps(&caps, mp);
++ kdbus_meta_export_caps(&caps, mp, user_ns);
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+ KDBUS_ITEM_CAPS, &caps,
+ sizeof(caps), &size);
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index 79b6ac31c8ad..2dbbb3d78d97 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -46,6 +46,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ u64 *mask, size_t *sz);
+ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_conn *mc,
++ struct kdbus_conn *conn,
+ u64 mask,
+ struct kdbus_pool_slice *slice,
+ off_t offset, size_t *real_size);
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+index 25bb3ad66b98..6650b7804d87 100644
+--- a/ipc/kdbus/queue.c
++++ b/ipc/kdbus/queue.c
+@@ -479,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
+
+ ret = kdbus_meta_export(entry->proc_meta,
+ entry->conn_meta,
++ conn_dst,
+ entry->attach_flags,
+ entry->slice,
+ entry->meta_offset,
+--
+2.4.3
+
+
+From 539d66c50c22a40a29c97c8f1e497769de75c078 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Wed, 1 Jul 2015 17:15:14 +0200
+Subject: [PATCH 09/34] kdbus: fix NULL-deref in activator cleanup
+
+Right now, we always assume an activator has a valid name and
+conn->activator_of is set. However, this assumption is not true if the
+setup of the activator fails. In those cases, the ->flags field indicates
+an activator, but the name might not have been claimed, yet.
+
+Fix the destructor of connections to not assume all activators have
+claimed names.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/names.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c
+index d77ee08afeda..057f8061c20f 100644
+--- a/ipc/kdbus/names.c
++++ b/ipc/kdbus/names.c
+@@ -444,7 +444,7 @@ void kdbus_name_release_all(struct kdbus_name_registry *reg,
+
+ down_write(&reg->rwlock);
+
+- if (kdbus_conn_is_activator(conn)) {
++ if (conn->activator_of) {
+ activator = conn->activator_of->activator;
+ conn->activator_of->activator = NULL;
+ }
+--
+2.4.3
+
+
+From 3c18b8a477e0eda28b3390cf9168dbdb3c7fdd56 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 3 Jul 2015 11:10:22 +0200
+Subject: [PATCH 10/34] kdbus: allow building development modules
+
+If you run your system on kdbus.ko, but you want to run tests on your
+development version of kdbus, you will have a hard-time debugging as you
+need to boot your machine with it. You either have to boot with legacy
+dbus-daemon or boot without dbus entirely (eg., /bin/sh).
+
+The kdbus module always used KBUILD_MODNAME as base for all exported
+objects (like kdbusfs and file-system paths). Hence, we can easily build
+kdbus2.ko and get an independent module of the first one. This patch makes
+the kdbus Makefile read KDBUS_EXT= and appends it to the module name.
+
+Now you can get an independent kdbus2.ko, by simply running:
+ make KDBUS_EXT=2 M=ipc/kdbus
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/Makefile | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile
+index 7ee9271e1449..66663a124104 100644
+--- a/ipc/kdbus/Makefile
++++ b/ipc/kdbus/Makefile
+@@ -1,4 +1,15 @@
+-kdbus-y := \
++#
++# By setting KDBUS_EXT=2, the kdbus module will be built as kdbus2.ko, and
++# KBUILD_MODNAME=kdbus2. This has the effect that all exported objects have
++# different names than usually (kdbus2fs, /sys/fs/kdbus2/) and you can run
++# your test-infrastructure against the kdbus2.ko, while running your system
++# on kdbus.ko.
++#
++# To just build the module, use:
++# make KDBUS_EXT=2 M=ipc/kdbus
++#
++
++kdbus$(KDBUS_EXT)-y := \
+ bus.o \
+ connection.o \
+ endpoint.o \
+@@ -19,4 +30,4 @@ kdbus-y := \
+ queue.o \
+ util.o
+
+-obj-$(CONFIG_KDBUS) += kdbus.o
++obj-$(CONFIG_KDBUS) += kdbus$(KDBUS_EXT).o
+--
+2.4.3
+
+
+From f8253aa89c645d1d979aa4743ebabe005f54f7df Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 15 Jun 2015 20:49:21 +0200
+Subject: [PATCH 11/34] kdbus: split off faked metadata into separate object
+
+Right now we treat faked metadata the same as process metadata. This has
+the downside, that we cannot use "struct cred" to pin normal process
+credentials, as we don't want to fake such structure for faked
+credentials.
+
+Splitt off handling of faked metadata into a separate kdbus_meta_fake
+object. As a side effect, faked metadata is now handled explicitly instead
+of hidden in the process metadata.
+
+In follow-up patches, the kdbus_meta_proc state-tracking can be reduced
+significantly by pinning "struct cred" instead of copying each field
+individually.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 6 +-
+ ipc/kdbus/connection.c | 37 +++++----
+ ipc/kdbus/connection.h | 9 +--
+ ipc/kdbus/message.c | 2 +-
+ ipc/kdbus/metadata.c | 216 ++++++++++++++++++++++++++++++-------------------
+ ipc/kdbus/metadata.h | 43 +++++++++-
+ ipc/kdbus/queue.c | 2 +
+ 7 files changed, 206 insertions(+), 109 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 8fffc2f594a8..dd1e600b8f01 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -484,7 +484,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+
+ attach_flags &= bus->attach_flags_owner;
+
+- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL,
++ ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL,
+ &attach_flags, &meta_size);
+ if (ret < 0)
+ goto exit;
+@@ -507,8 +507,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags,
+- slice, hdr_size, &meta_size);
++ ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn,
++ attach_flags, slice, hdr_size, &meta_size);
+ if (ret < 0)
+ goto exit;
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index ca241fcf19f7..8976bb32ab69 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -172,22 +172,28 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+ BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128));
+ memcpy(hello->id128, bus->id128, sizeof(hello->id128));
+
+- conn->meta = kdbus_meta_proc_new();
+- if (IS_ERR(conn->meta)) {
+- ret = PTR_ERR(conn->meta);
+- conn->meta = NULL;
+- goto exit_unref;
+- }
+-
+ /* privileged processes can impersonate somebody else */
+ if (creds || pids || seclabel) {
+- ret = kdbus_meta_proc_fake(conn->meta, creds, pids, seclabel);
+- if (ret < 0)
++ conn->meta_fake = kdbus_meta_fake_new();
++ if (IS_ERR(conn->meta_fake)) {
++ ret = PTR_ERR(conn->meta_fake);
++ conn->meta_fake = NULL;
+ goto exit_unref;
++ }
+
+- conn->faked_meta = true;
++ ret = kdbus_meta_fake_collect(conn->meta_fake,
++ creds, pids, seclabel);
++ if (ret < 0)
++ goto exit_unref;
+ } else {
+- ret = kdbus_meta_proc_collect(conn->meta,
++ conn->meta_proc = kdbus_meta_proc_new();
++ if (IS_ERR(conn->meta_proc)) {
++ ret = PTR_ERR(conn->meta_proc);
++ conn->meta_proc = NULL;
++ goto exit_unref;
++ }
++
++ ret = kdbus_meta_proc_collect(conn->meta_proc,
+ KDBUS_ATTACH_CREDS |
+ KDBUS_ATTACH_PIDS |
+ KDBUS_ATTACH_AUXGROUPS |
+@@ -270,7 +276,8 @@ static void __kdbus_conn_free(struct kref *kref)
+ kdbus_user_unref(conn->user);
+ }
+
+- kdbus_meta_proc_unref(conn->meta);
++ kdbus_meta_fake_free(conn->meta_fake);
++ kdbus_meta_proc_unref(conn->meta_proc);
+ kdbus_match_db_free(conn->match_db);
+ kdbus_pool_free(conn->pool);
+ kdbus_ep_unref(conn->ep);
+@@ -1785,7 +1792,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ if (ret < 0)
+ goto exit;
+
+- ret = kdbus_meta_export_prepare(owner_conn->meta, conn_meta,
++ ret = kdbus_meta_export_prepare(owner_conn->meta_proc,
++ owner_conn->meta_fake, conn_meta,
+ &attach_flags, &meta_size);
+ if (ret < 0)
+ goto exit;
+@@ -1798,7 +1806,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags,
++ ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake,
++ conn_meta, conn, attach_flags,
+ slice, sizeof(info), &meta_size);
+ if (ret < 0)
+ goto exit;
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index 226f3ff60e31..0eb3d2e70a5e 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -54,8 +54,8 @@ struct kdbus_kmsg;
+ * @work: Delayed work to handle timeouts
+ * activator for
+ * @match_db: Subscription filter to broadcast messages
+- * @meta: Active connection creator's metadata/credentials,
+- * either from the handle or from HELLO
++ * @meta_proc: Process metadata of connection creator, or NULL
++ * @meta_fake: Faked metadata, or NULL
+ * @pool: The user's buffer to receive messages
+ * @user: Owner of the connection
+ * @cred: The credentials of the connection at creation time
+@@ -75,7 +75,6 @@ struct kdbus_kmsg;
+ * @names_list: List of well-known names
+ * @names_queue_list: Well-known names this connection waits for
+ * @privileged: Whether this connection is privileged on the bus
+- * @faked_meta: Whether the metadata was faked on HELLO
+ */
+ struct kdbus_conn {
+ struct kref kref;
+@@ -96,7 +95,8 @@ struct kdbus_conn {
+ struct list_head reply_list;
+ struct delayed_work work;
+ struct kdbus_match_db *match_db;
+- struct kdbus_meta_proc *meta;
++ struct kdbus_meta_proc *meta_proc;
++ struct kdbus_meta_fake *meta_fake;
+ struct kdbus_pool *pool;
+ struct kdbus_user *user;
+ const struct cred *cred;
+@@ -118,7 +118,6 @@ struct kdbus_conn {
+ struct list_head names_queue_list;
+
+ bool privileged:1;
+- bool faked_meta:1;
+ };
+
+ struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn);
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index e9da67229eb1..55e432397b93 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -626,7 +626,7 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src,
+ int ret;
+
+ attach = kdbus_meta_calc_attach_flags(src, dst);
+- if (!src->faked_meta) {
++ if (!src->meta_fake) {
+ ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach);
+ if (ret < 0)
+ return ret;
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index 79f0e8c7f4a3..ac4135c507c4 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -494,101 +494,116 @@ exit_unlock:
+ }
+
+ /**
+- * kdbus_meta_proc_fake() - Fill process metadata from faked credentials
+- * @mp: Metadata
++ * kdbus_meta_fake_new() - Create fake metadata object
++ *
++ * Return: Pointer to new object on success, ERR_PTR on failure.
++ */
++struct kdbus_meta_fake *kdbus_meta_fake_new(void)
++{
++ struct kdbus_meta_fake *mf;
++
++ mf = kzalloc(sizeof(*mf), GFP_KERNEL);
++ if (!mf)
++ return ERR_PTR(-ENOMEM);
++
++ return mf;
++}
++
++/**
++ * kdbus_meta_fake_free() - Free fake metadata object
++ * @mf: Fake metadata object
++ *
++ * Return: NULL
++ */
++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf)
++{
++ if (mf) {
++ put_pid(mf->ppid);
++ put_pid(mf->tgid);
++ put_pid(mf->pid);
++ kfree(mf->seclabel);
++ kfree(mf);
++ }
++
++ return NULL;
++}
++
++/**
++ * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials
++ * @mf: Fake metadata object
+ * @creds: Creds to set, may be %NULL
+ * @pids: PIDs to set, may be %NULL
+ * @seclabel: Seclabel to set, may be %NULL
+ *
+ * This function takes information stored in @creds, @pids and @seclabel and
+- * resolves them to kernel-representations, if possible. A call to this function
+- * is considered an alternative to calling kdbus_meta_add_current(), which
+- * derives the same information from the 'current' task.
+- *
+- * This call uses the current task's namespaces to resolve the given
+- * information.
++ * resolves them to kernel-representations, if possible. This call uses the
++ * current task's namespaces to resolve the given information.
+ *
+- * Return: 0 on success, negative error number otherwise.
++ * Return: 0 on success, negative error code on failure.
+ */
+-int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp,
+- const struct kdbus_creds *creds,
+- const struct kdbus_pids *pids,
+- const char *seclabel)
++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf,
++ const struct kdbus_creds *creds,
++ const struct kdbus_pids *pids,
++ const char *seclabel)
+ {
+- int ret;
+-
+- if (!mp)
+- return 0;
+-
+- mutex_lock(&mp->lock);
++ if (mf->valid)
++ return -EALREADY;
+
+- if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) {
++ if (creds) {
+ struct user_namespace *ns = current_user_ns();
+
+- mp->uid = make_kuid(ns, creds->uid);
+- mp->euid = make_kuid(ns, creds->euid);
+- mp->suid = make_kuid(ns, creds->suid);
+- mp->fsuid = make_kuid(ns, creds->fsuid);
+-
+- mp->gid = make_kgid(ns, creds->gid);
+- mp->egid = make_kgid(ns, creds->egid);
+- mp->sgid = make_kgid(ns, creds->sgid);
+- mp->fsgid = make_kgid(ns, creds->fsgid);
+-
+- if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) ||
+- (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) ||
+- (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) ||
+- (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) ||
+- (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) ||
+- (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) ||
+- (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) ||
+- (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) {
+- ret = -EINVAL;
+- goto exit_unlock;
+- }
+-
+- mp->valid |= KDBUS_ATTACH_CREDS;
+- mp->collected |= KDBUS_ATTACH_CREDS;
++ mf->uid = make_kuid(ns, creds->uid);
++ mf->euid = make_kuid(ns, creds->euid);
++ mf->suid = make_kuid(ns, creds->suid);
++ mf->fsuid = make_kuid(ns, creds->fsuid);
++
++ mf->gid = make_kgid(ns, creds->gid);
++ mf->egid = make_kgid(ns, creds->egid);
++ mf->sgid = make_kgid(ns, creds->sgid);
++ mf->fsgid = make_kgid(ns, creds->fsgid);
++
++ if ((creds->uid != (uid_t)-1 && !uid_valid(mf->uid)) ||
++ (creds->euid != (uid_t)-1 && !uid_valid(mf->euid)) ||
++ (creds->suid != (uid_t)-1 && !uid_valid(mf->suid)) ||
++ (creds->fsuid != (uid_t)-1 && !uid_valid(mf->fsuid)) ||
++ (creds->gid != (gid_t)-1 && !gid_valid(mf->gid)) ||
++ (creds->egid != (gid_t)-1 && !gid_valid(mf->egid)) ||
++ (creds->sgid != (gid_t)-1 && !gid_valid(mf->sgid)) ||
++ (creds->fsgid != (gid_t)-1 && !gid_valid(mf->fsgid)))
++ return -EINVAL;
++
++ mf->valid |= KDBUS_ATTACH_CREDS;
+ }
+
+- if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) {
+- mp->pid = get_pid(find_vpid(pids->tid));
+- mp->tgid = get_pid(find_vpid(pids->pid));
+- mp->ppid = get_pid(find_vpid(pids->ppid));
+-
+- if ((pids->tid != 0 && !mp->pid) ||
+- (pids->pid != 0 && !mp->tgid) ||
+- (pids->ppid != 0 && !mp->ppid)) {
+- put_pid(mp->pid);
+- put_pid(mp->tgid);
+- put_pid(mp->ppid);
+- mp->pid = NULL;
+- mp->tgid = NULL;
+- mp->ppid = NULL;
+- ret = -EINVAL;
+- goto exit_unlock;
++ if (pids) {
++ mf->pid = get_pid(find_vpid(pids->tid));
++ mf->tgid = get_pid(find_vpid(pids->pid));
++ mf->ppid = get_pid(find_vpid(pids->ppid));
++
++ if ((pids->tid != 0 && !mf->pid) ||
++ (pids->pid != 0 && !mf->tgid) ||
++ (pids->ppid != 0 && !mf->ppid)) {
++ put_pid(mf->pid);
++ put_pid(mf->tgid);
++ put_pid(mf->ppid);
++ mf->pid = NULL;
++ mf->tgid = NULL;
++ mf->ppid = NULL;
++ return -EINVAL;
+ }
+
+- mp->valid |= KDBUS_ATTACH_PIDS;
+- mp->collected |= KDBUS_ATTACH_PIDS;
++ mf->valid |= KDBUS_ATTACH_PIDS;
+ }
+
+- if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) {
+- mp->seclabel = kstrdup(seclabel, GFP_KERNEL);
+- if (!mp->seclabel) {
+- ret = -ENOMEM;
+- goto exit_unlock;
+- }
++ if (seclabel) {
++ mf->seclabel = kstrdup(seclabel, GFP_KERNEL);
++ if (!mf->seclabel)
++ return -ENOMEM;
+
+- mp->valid |= KDBUS_ATTACH_SECLABEL;
+- mp->collected |= KDBUS_ATTACH_SECLABEL;
++ mf->valid |= KDBUS_ATTACH_SECLABEL;
+ }
+
+- ret = 0;
+-
+-exit_unlock:
+- mutex_unlock(&mp->lock);
+- return ret;
++ return 0;
+ }
+
+ /**
+@@ -768,6 +783,7 @@ exit_unlock:
+ /*
+ * kdbus_meta_export_prepare() - Prepare metadata for export
+ * @mp: Process metadata, or NULL
++ * @mf: Fake metadata, or NULL
+ * @mc: Connection metadata, or NULL
+ * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export
+ * @sz: Pointer to return the size needed by the metadata
+@@ -783,6 +799,7 @@ exit_unlock:
+ * Return: 0 on success, negative error number otherwise.
+ */
+ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
+ struct kdbus_meta_conn *mc,
+ u64 *mask, size_t *sz)
+ {
+@@ -792,6 +809,12 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ u64 valid = 0;
+ int ret = 0;
+
++ if (WARN_ON(mf && mp))
++ mp = NULL;
++
++ if (mf)
++ valid |= mf->valid;
++
+ if (mp) {
+ mutex_lock(&mp->lock);
+ valid |= mp->valid;
+@@ -811,10 +834,10 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+
+ /* process metadata */
+
+- if (mp && (*mask & KDBUS_ATTACH_CREDS))
++ if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS))
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
+
+- if (mp && (*mask & KDBUS_ATTACH_PIDS))
++ if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS))
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
+
+ if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS))
+@@ -852,8 +875,9 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ if (mp && (*mask & KDBUS_ATTACH_CAPS))
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps));
+
+- if (mp && (*mask & KDBUS_ATTACH_SECLABEL))
+- size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1);
++ if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL))
++ size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel
++ : mf->seclabel) + 1);
+
+ if (mp && (*mask & KDBUS_ATTACH_AUDIT))
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
+@@ -966,6 +990,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid)
+ /**
+ * kdbus_meta_export() - export information from metadata into a slice
+ * @mp: Process metadata, or NULL
++ * @mf: Fake metadata, or NULL
+ * @mc: Connection metadata, or NULL
+ * @conn: Target connection to translate metadata into
+ * @mask: Mask of KDBUS_ATTACH_* flags to export
+@@ -988,6 +1013,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid)
+ * Return: 0 on success, negative error number otherwise.
+ */
+ int kdbus_meta_export(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
+ struct kdbus_meta_conn *mc,
+ struct kdbus_conn *conn,
+ u64 mask,
+@@ -1007,6 +1033,9 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ u64 size = 0;
+ int ret = 0;
+
++ if (WARN_ON(mf && mp))
++ mp = NULL;
++
+ hdr = &item_hdr[0];
+
+ if (mask == 0) {
+@@ -1016,7 +1045,19 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+
+ /* process metadata */
+
+- if (mp && (mask & KDBUS_ATTACH_CREDS)) {
++ if (mf && (mask & KDBUS_ATTACH_CREDS)) {
++ creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid);
++ creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid);
++ creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid);
++ creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid);
++ creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid);
++ creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid);
++ creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid);
++ creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid);
++
++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
++ &creds, sizeof(creds), &size);
++ } else if (mp && (mask & KDBUS_ATTACH_CREDS)) {
+ creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid);
+ creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid);
+ creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid);
+@@ -1030,7 +1071,14 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ &creds, sizeof(creds), &size);
+ }
+
+- if (mp && (mask & KDBUS_ATTACH_PIDS)) {
++ if (mf && (mask & KDBUS_ATTACH_PIDS)) {
++ pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns);
++ pids.tid = pid_nr_ns(mf->pid, conn->pid_ns);
++ pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns);
++
++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS,
++ &pids, sizeof(pids), &size);
++ } else if (mp && (mask & KDBUS_ATTACH_PIDS)) {
+ pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns);
+ pids.tid = pid_nr_ns(mp->pid, conn->pid_ns);
+ pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns);
+@@ -1124,7 +1172,11 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ sizeof(caps), &size);
+ }
+
+- if (mp && (mask & KDBUS_ATTACH_SECLABEL))
++ if (mf && (mask & KDBUS_ATTACH_SECLABEL))
++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
++ KDBUS_ITEM_SECLABEL, mf->seclabel,
++ strlen(mf->seclabel) + 1, &size);
++ else if (mp && (mask & KDBUS_ATTACH_SECLABEL))
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+ KDBUS_ITEM_SECLABEL, mp->seclabel,
+ strlen(mp->seclabel) + 1, &size);
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index 2dbbb3d78d97..2fb04dad38d4 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -24,14 +24,47 @@ struct kdbus_pool_slice;
+ struct kdbus_meta_proc;
+ struct kdbus_meta_conn;
+
++/**
++ * struct kdbus_meta_fake - Fake metadata
++ * @valid: Bitmask of collected and valid items
++ * @uid: UID of process
++ * @euid: EUID of process
++ * @suid: SUID of process
++ * @fsuid: FSUID of process
++ * @gid: GID of process
++ * @egid: EGID of process
++ * @sgid: SGID of process
++ * @fsgid: FSGID of process
++ * @pid: PID of process
++ * @tgid: TGID of process
++ * @ppid: PPID of process
++ * @seclabel: Seclabel
++ */
++struct kdbus_meta_fake {
++ u64 valid;
++
++ /* KDBUS_ITEM_CREDS */
++ kuid_t uid, euid, suid, fsuid;
++ kgid_t gid, egid, sgid, fsgid;
++
++ /* KDBUS_ITEM_PIDS */
++ struct pid *pid, *tgid, *ppid;
++
++ /* KDBUS_ITEM_SECLABEL */
++ char *seclabel;
++};
++
+ struct kdbus_meta_proc *kdbus_meta_proc_new(void);
+ struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp);
+ struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp);
+ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what);
+-int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp,
+- const struct kdbus_creds *creds,
+- const struct kdbus_pids *pids,
+- const char *seclabel);
++
++struct kdbus_meta_fake *kdbus_meta_fake_new(void);
++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf);
++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf,
++ const struct kdbus_creds *creds,
++ const struct kdbus_pids *pids,
++ const char *seclabel);
+
+ struct kdbus_meta_conn *kdbus_meta_conn_new(void);
+ struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc);
+@@ -42,9 +75,11 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+ u64 what);
+
+ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
+ struct kdbus_meta_conn *mc,
+ u64 *mask, size_t *sz);
+ int kdbus_meta_export(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
+ struct kdbus_meta_conn *mc,
+ struct kdbus_conn *conn,
+ u64 mask,
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+index 6650b7804d87..1e7916155036 100644
+--- a/ipc/kdbus/queue.c
++++ b/ipc/kdbus/queue.c
+@@ -251,6 +251,7 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst,
+ atomic64_read(&conn_dst->attach_flags_recv);
+
+ ret = kdbus_meta_export_prepare(entry->proc_meta,
++ NULL,
+ entry->conn_meta,
+ &entry->attach_flags,
+ &meta_size);
+@@ -478,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
+ size_t meta_size;
+
+ ret = kdbus_meta_export(entry->proc_meta,
++ NULL,
+ entry->conn_meta,
+ conn_dst,
+ entry->attach_flags,
+--
+2.4.3
+
+
+From 2bec5609205bc69f57c7bd27834b2637aa656f6d Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 15 Jun 2015 21:25:39 +0200
+Subject: [PATCH 12/34] kdbus: pin 'struct cred' in process metadata
+
+Instead of copying over all data from 'struct cred', pin it directly. This
+reduces the memory footprint of kdbus_meta_proc considerably and speeds
+up the fast-path.
+
+There's no change in behavior. We just change the level we pin data at.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/metadata.c | 131 +++++++++++++--------------------------------------
+ 1 file changed, 34 insertions(+), 97 deletions(-)
+
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index ac4135c507c4..1bac0dda72e0 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -44,26 +44,16 @@
+ * @lock: Object lock
+ * @collected: Bitmask of collected items
+ * @valid: Bitmask of collected and valid items
+- * @uid: UID of process
+- * @euid: EUID of process
+- * @suid: SUID of process
+- * @fsuid: FSUID of process
+- * @gid: GID of process
+- * @egid: EGID of process
+- * @sgid: SGID of process
+- * @fsgid: FSGID of process
++ * @cred: Credentials
+ * @pid: PID of process
+ * @tgid: TGID of process
+ * @ppid: PPID of process
+- * @auxgrps: Auxiliary groups
+- * @n_auxgrps: Number of items in @auxgrps
+ * @tid_comm: TID comm line
+ * @pid_comm: PID comm line
+ * @exe_path: Executable path
+ * @root_path: Root-FS path
+ * @cmdline: Command-line
+ * @cgroup: Full cgroup path
+- * @cred: Credentials
+ * @seclabel: Seclabel
+ * @audit_loginuid: Audit login-UID
+ * @audit_sessionid: Audit session-ID
+@@ -75,18 +65,15 @@ struct kdbus_meta_proc {
+ u64 valid;
+
+ /* KDBUS_ITEM_CREDS */
+- kuid_t uid, euid, suid, fsuid;
+- kgid_t gid, egid, sgid, fsgid;
++ /* KDBUS_ITEM_AUXGROUPS */
++ /* KDBUS_ITEM_CAPS */
++ const struct cred *cred;
+
+ /* KDBUS_ITEM_PIDS */
+ struct pid *pid;
+ struct pid *tgid;
+ struct pid *ppid;
+
+- /* KDBUS_ITEM_AUXGROUPS */
+- kgid_t *auxgrps;
+- size_t n_auxgrps;
+-
+ /* KDBUS_ITEM_TID_COMM */
+ char tid_comm[TASK_COMM_LEN];
+ /* KDBUS_ITEM_PID_COMM */
+@@ -102,9 +89,6 @@ struct kdbus_meta_proc {
+ /* KDBUS_ITEM_CGROUP */
+ char *cgroup;
+
+- /* KDBUS_ITEM_CAPS */
+- const struct cred *cred;
+-
+ /* KDBUS_ITEM_SECLABEL */
+ char *seclabel;
+
+@@ -182,7 +166,6 @@ static void kdbus_meta_proc_free(struct kref *kref)
+ put_pid(mp->pid);
+
+ kfree(mp->seclabel);
+- kfree(mp->auxgrps);
+ kfree(mp->cmdline);
+ kfree(mp->cgroup);
+ kfree(mp);
+@@ -214,21 +197,6 @@ struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp)
+ return NULL;
+ }
+
+-static void kdbus_meta_proc_collect_creds(struct kdbus_meta_proc *mp)
+-{
+- mp->uid = current_uid();
+- mp->euid = current_euid();
+- mp->suid = current_suid();
+- mp->fsuid = current_fsuid();
+-
+- mp->gid = current_gid();
+- mp->egid = current_egid();
+- mp->sgid = current_sgid();
+- mp->fsgid = current_fsgid();
+-
+- mp->valid |= KDBUS_ATTACH_CREDS;
+-}
+-
+ static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp)
+ {
+ struct task_struct *parent;
+@@ -244,30 +212,6 @@ static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp)
+ mp->valid |= KDBUS_ATTACH_PIDS;
+ }
+
+-static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp)
+-{
+- const struct group_info *info;
+- size_t i;
+-
+- /* no need to lock/ref, current creds cannot change */
+- info = current_cred()->group_info;
+-
+- if (info->ngroups > 0) {
+- mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t),
+- GFP_KERNEL);
+- if (!mp->auxgrps)
+- return -ENOMEM;
+-
+- for (i = 0; i < info->ngroups; i++)
+- mp->auxgrps[i] = GROUP_AT(info, i);
+- }
+-
+- mp->n_auxgrps = info->ngroups;
+- mp->valid |= KDBUS_ATTACH_AUXGROUPS;
+-
+- return 0;
+-}
+-
+ static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp)
+ {
+ get_task_comm(mp->tid_comm, current);
+@@ -340,12 +284,6 @@ static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp)
+ return 0;
+ }
+
+-static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp)
+-{
+- mp->cred = get_current_cred();
+- mp->valid |= KDBUS_ATTACH_CAPS;
+-}
+-
+ static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
+ {
+ #ifdef CONFIG_SECURITY
+@@ -412,10 +350,17 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what)
+
+ mutex_lock(&mp->lock);
+
+- if ((what & KDBUS_ATTACH_CREDS) &&
+- !(mp->collected & KDBUS_ATTACH_CREDS)) {
+- kdbus_meta_proc_collect_creds(mp);
+- mp->collected |= KDBUS_ATTACH_CREDS;
++ /* creds, auxgrps and caps share "struct cred" as context */
++ {
++ const u64 m_cred = KDBUS_ATTACH_CREDS |
++ KDBUS_ATTACH_AUXGROUPS |
++ KDBUS_ATTACH_CAPS;
++
++ if ((what & m_cred) && !(mp->collected & m_cred)) {
++ mp->cred = get_current_cred();
++ mp->valid |= m_cred;
++ mp->collected |= m_cred;
++ }
+ }
+
+ if ((what & KDBUS_ATTACH_PIDS) &&
+@@ -424,14 +369,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what)
+ mp->collected |= KDBUS_ATTACH_PIDS;
+ }
+
+- if ((what & KDBUS_ATTACH_AUXGROUPS) &&
+- !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) {
+- ret = kdbus_meta_proc_collect_auxgroups(mp);
+- if (ret < 0)
+- goto exit_unlock;
+- mp->collected |= KDBUS_ATTACH_AUXGROUPS;
+- }
+-
+ if ((what & KDBUS_ATTACH_TID_COMM) &&
+ !(mp->collected & KDBUS_ATTACH_TID_COMM)) {
+ kdbus_meta_proc_collect_tid_comm(mp);
+@@ -466,12 +403,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what)
+ mp->collected |= KDBUS_ATTACH_CGROUP;
+ }
+
+- if ((what & KDBUS_ATTACH_CAPS) &&
+- !(mp->collected & KDBUS_ATTACH_CAPS)) {
+- kdbus_meta_proc_collect_caps(mp);
+- mp->collected |= KDBUS_ATTACH_CAPS;
+- }
+-
+ if ((what & KDBUS_ATTACH_SECLABEL) &&
+ !(mp->collected & KDBUS_ATTACH_SECLABEL)) {
+ ret = kdbus_meta_proc_collect_seclabel(mp);
+@@ -841,7 +772,8 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
+
+ if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS))
+- size += KDBUS_ITEM_SIZE(mp->n_auxgrps * sizeof(u64));
++ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups *
++ sizeof(u64));
+
+ if (mp && (*mask & KDBUS_ATTACH_TID_COMM))
+ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1);
+@@ -1058,14 +990,16 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
+ &creds, sizeof(creds), &size);
+ } else if (mp && (mask & KDBUS_ATTACH_CREDS)) {
+- creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid);
+- creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid);
+- creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid);
+- creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid);
+- creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid);
+- creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid);
+- creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid);
+- creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid);
++ const struct cred *c = mp->cred;
++
++ creds.uid = kdbus_from_kuid_keep(user_ns, c->uid);
++ creds.euid = kdbus_from_kuid_keep(user_ns, c->euid);
++ creds.suid = kdbus_from_kuid_keep(user_ns, c->suid);
++ creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid);
++ creds.gid = kdbus_from_kgid_keep(user_ns, c->gid);
++ creds.egid = kdbus_from_kgid_keep(user_ns, c->egid);
++ creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid);
++ creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid);
+
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
+ &creds, sizeof(creds), &size);
+@@ -1088,17 +1022,20 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ }
+
+ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) {
+- size_t payload_size = mp->n_auxgrps * sizeof(u64);
+- int i;
++ const struct group_info *info = mp->cred->group_info;
++ size_t i, n, payload_size;
+
++ n = info->ngroups;
++ payload_size = n * sizeof(u64);
+ auxgrps = kmalloc(payload_size, GFP_KERNEL);
+ if (!auxgrps) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+- for (i = 0; i < mp->n_auxgrps; i++)
+- auxgrps[i] = from_kgid_munged(user_ns, mp->auxgrps[i]);
++ for (i = 0; i < n; ++i)
++ auxgrps[i] = from_kgid_munged(user_ns,
++ GROUP_AT(info, i));
+
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+ KDBUS_ITEM_AUXGROUPS,
+--
+2.4.3
+
+
+From 46a0b5df61b398fc58897aaeb3c1e57f210057a7 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 15:33:34 +0200
+Subject: [PATCH 13/34] kdbus: pass msg-seqnum directly into meta-conn
+
+Instead of passing the kmsg object into kdbus_meta_conn_collect(), pass
+the message sequence number directly. It is the only field that is used
+there, so avoid introducing a "kdbus_kmsg" dependency from metadata.h.
+
+This is also a preparation for an upcoming change to drop 'kdbus_kmsg'.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 3 +--
+ ipc/kdbus/message.c | 2 +-
+ ipc/kdbus/metadata.c | 18 +++++++++---------
+ ipc/kdbus/metadata.h | 4 +---
+ ipc/kdbus/notify.c | 2 +-
+ 5 files changed, 13 insertions(+), 16 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 8976bb32ab69..8fcff17ae2b6 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -1787,8 +1787,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- ret = kdbus_meta_conn_collect(conn_meta, NULL, owner_conn,
+- attach_flags);
++ ret = kdbus_meta_conn_collect(conn_meta, owner_conn, 0, attach_flags);
+ if (ret < 0)
+ goto exit;
+
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 55e432397b93..974e8c4f6039 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -632,5 +632,5 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src,
+ return ret;
+ }
+
+- return kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach);
++ return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach);
+ }
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index 1bac0dda72e0..dcb603798aba 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -589,13 +589,13 @@ struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc)
+ }
+
+ static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc,
+- struct kdbus_kmsg *kmsg)
++ u64 msg_seqnum)
+ {
+ mc->ts.monotonic_ns = ktime_get_ns();
+ mc->ts.realtime_ns = ktime_get_real_ns();
+
+- if (kmsg)
+- mc->ts.seqnum = kmsg->seq;
++ if (msg_seqnum)
++ mc->ts.seqnum = msg_seqnum;
+
+ mc->valid |= KDBUS_ATTACH_TIMESTAMP;
+ }
+@@ -657,11 +657,12 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc,
+ /**
+ * kdbus_meta_conn_collect() - Collect connection metadata
+ * @mc: Message metadata object
+- * @kmsg: Kmsg to collect data from
+ * @conn: Connection to collect data from
++ * @msg_seqnum: Sequence number of the message to send
+ * @what: Attach flags to collect
+ *
+- * This collects connection metadata from @kmsg and @conn and saves it in @mc.
++ * This collects connection metadata from @msg_seqnum and @conn and saves it
++ * in @mc.
+ *
+ * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must
+ * hold the name-registry read-lock of conn->ep->bus->registry.
+@@ -669,9 +670,8 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc,
+ * Return: 0 on success, negative error code on failure.
+ */
+ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+- struct kdbus_kmsg *kmsg,
+ struct kdbus_conn *conn,
+- u64 what)
++ u64 msg_seqnum, u64 what)
+ {
+ int ret;
+
+@@ -682,9 +682,9 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+
+ mutex_lock(&mc->lock);
+
+- if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) &&
++ if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) &&
+ !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) {
+- kdbus_meta_conn_collect_timestamp(mc, kmsg);
++ kdbus_meta_conn_collect_timestamp(mc, msg_seqnum);
+ mc->collected |= KDBUS_ATTACH_TIMESTAMP;
+ }
+
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index 2fb04dad38d4..c33315d0b82b 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -18,7 +18,6 @@
+ #include <linux/kernel.h>
+
+ struct kdbus_conn;
+-struct kdbus_kmsg;
+ struct kdbus_pool_slice;
+
+ struct kdbus_meta_proc;
+@@ -70,9 +69,8 @@ struct kdbus_meta_conn *kdbus_meta_conn_new(void);
+ struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc);
+ struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc);
+ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+- struct kdbus_kmsg *kmsg,
+ struct kdbus_conn *conn,
+- u64 what);
++ u64 msg_seqnum, u64 what);
+
+ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_fake *mf,
+diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c
+index e4a454222f09..216720fc26ff 100644
+--- a/ipc/kdbus/notify.c
++++ b/ipc/kdbus/notify.c
+@@ -209,7 +209,7 @@ void kdbus_notify_flush(struct kdbus_bus *bus)
+ spin_unlock(&bus->notify_lock);
+
+ list_for_each_entry_safe(kmsg, tmp, &notify_list, notify_entry) {
+- kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, NULL,
++ kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq,
+ KDBUS_ATTACH_TIMESTAMP);
+
+ if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) {
+--
+2.4.3
+
+
+From 9b7d557456bf4528daaad686b545cd6285602d69 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 15:37:03 +0200
+Subject: [PATCH 14/34] kdbus: don't include padding in mc->owned_names_size
+
+Whenever we deal with kdbus-items, we have to distinguish the size of the
+items (as written in item->size) and the offset of the next item (which
+includes any padding). The KDBUS_ITEM_SIZE() macro always computes the
+size *plus* padding, which is a bit misleading. In most cases it's what
+you want, but in case of mc->owned_names_size it is not.
+
+Right now, mc->owned_names_size includes the padding after the last item,
+even though that is not strictly part of the items. Furthermore, since we
+merge all the OWNED_NAME items into an array, it is not possible to
+compute the actual size (minus padding) in O(1). Therefore, change the
+collector to *NOT* include the final padding.
+
+The reason we need this is to make sure msg->size does never include the
+padding after the last item. Right now it does, which will be fixed in
+follow-up patches. This patch just makes sure we actually know the real
+size of the owned_names_items array.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/metadata.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index dcb603798aba..beb7dbb73d08 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -610,14 +610,16 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc,
+ lockdep_assert_held(&conn->ep->bus->name_registry->rwlock);
+
+ size = 0;
++ /* open-code length calculation to avoid final padding */
+ list_for_each_entry(e, &conn->names_list, conn_entry)
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) +
+- strlen(e->name) + 1);
++ size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE +
++ sizeof(struct kdbus_name) + strlen(e->name) + 1;
+
+ if (!size)
+ return 0;
+
+- item = kmalloc(size, GFP_KERNEL);
++ /* make sure we include zeroed padding for convenience helpers */
++ item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL);
+ if (!item)
+ return -ENOMEM;
+
+@@ -634,7 +636,8 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc,
+ }
+
+ /* sanity check: the buffer should be completely written now */
+- WARN_ON((u8 *)item != (u8 *)mc->owned_names_items + size);
++ WARN_ON((u8 *)item !=
++ (u8 *)mc->owned_names_items + KDBUS_ALIGN8(size));
+
+ mc->valid |= KDBUS_ATTACH_NAMES;
+ return 0;
+@@ -817,7 +820,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+ /* connection metadata */
+
+ if (mc && (*mask & KDBUS_ATTACH_NAMES))
+- size += mc->owned_names_size;
++ size += KDBUS_ALIGN8(mc->owned_names_size);
+
+ if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1);
+@@ -1132,7 +1135,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+
+ if (mc && (mask & KDBUS_ATTACH_NAMES))
+ kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items,
+- mc->owned_names_size, &size);
++ KDBUS_ALIGN8(mc->owned_names_size), &size);
+
+ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+--
+2.4.3
+
+
+From 8c9a45e352f84382e773cec71e8ce5e936f01db5 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 16:16:30 +0200
+Subject: [PATCH 15/34] kdbus: re-introduce metadata buffers
+
+This re-introduces the old way of managing metadata. The new
+kdbus_meta_emit() function takes metadata sources from the caller and
+emits an item buffer of the requested metadata items. The buffer is
+allocated dynamically and can be directly used to copy the metadata items
+into the pool slice.
+
+Unlike kdbus_meta_export(), this new function avoids calling into
+kdbus_pool_slice and as such the metadata items can be integrated into the
+copy-operation of the surrounding objects. We trade one slice-copy for one
+kmalloc(), which should speed up most use-cases we care about
+significantly.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/metadata.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ ipc/kdbus/metadata.h | 7 +
+ 2 files changed, 374 insertions(+), 1 deletion(-)
+
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index beb7dbb73d08..70ce5d15fc98 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -847,7 +847,7 @@ static int kdbus_meta_push_kvec(struct kvec *kvec,
+ }
+
+ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
+- struct kdbus_meta_proc *mp,
++ const struct kdbus_meta_proc *mp,
+ struct user_namespace *user_ns)
+ {
+ struct user_namespace *iter;
+@@ -1161,6 +1161,372 @@ exit:
+ return ret;
+ }
+
++struct kdbus_meta_staging {
++ const struct kdbus_meta_proc *mp;
++ const struct kdbus_meta_fake *mf;
++ const struct kdbus_meta_conn *mc;
++ const struct kdbus_conn *conn;
++ u64 mask;
++
++ void *exe;
++ const char *exe_path;
++};
++
++static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging)
++{
++ const struct kdbus_meta_proc *mp = staging->mp;
++ const struct kdbus_meta_fake *mf = staging->mf;
++ const struct kdbus_meta_conn *mc = staging->mc;
++ const u64 mask = staging->mask;
++ size_t size = 0;
++
++ /* process metadata */
++
++ if (mf && (mask & KDBUS_ATTACH_CREDS))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
++ else if (mp && (mask & KDBUS_ATTACH_CREDS))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
++
++ if (mf && (mask & KDBUS_ATTACH_PIDS))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
++ else if (mp && (mask & KDBUS_ATTACH_PIDS))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
++
++ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS))
++ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups *
++ sizeof(u64));
++
++ if (mp && (mask & KDBUS_ATTACH_TID_COMM))
++ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1);
++
++ if (mp && (mask & KDBUS_ATTACH_PID_COMM))
++ size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1);
++
++ if (staging->exe_path && (mask & KDBUS_ATTACH_EXE))
++ size += KDBUS_ITEM_SIZE(strlen(staging->exe_path) + 1);
++
++ if (mp && (mask & KDBUS_ATTACH_CMDLINE))
++ size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1);
++
++ if (mp && (mask & KDBUS_ATTACH_CGROUP))
++ size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1);
++
++ if (mp && (mask & KDBUS_ATTACH_CAPS))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps));
++
++ if (mf && (mask & KDBUS_ATTACH_SECLABEL))
++ size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1);
++ else if (mp && (mask & KDBUS_ATTACH_SECLABEL))
++ size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1);
++
++ if (mp && (mask & KDBUS_ATTACH_AUDIT))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
++
++ /* connection metadata */
++
++ if (mc && (mask & KDBUS_ATTACH_NAMES))
++ size += KDBUS_ALIGN8(mc->owned_names_size);
++
++ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
++ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1);
++
++ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP))
++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp));
++
++ return size;
++}
++
++static struct kdbus_item *kdbus_write_head(struct kdbus_item **iter,
++ u64 type, u64 size)
++{
++ struct kdbus_item *item = *iter;
++ size_t padding;
++
++ item->type = type;
++ item->size = KDBUS_ITEM_HEADER_SIZE + size;
++
++ /* clear padding */
++ padding = KDBUS_ALIGN8(item->size) - item->size;
++ if (padding)
++ memset(item->data + size, 0, padding);
++
++ *iter = KDBUS_ITEM_NEXT(item);
++ return item;
++}
++
++static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter,
++ u64 type, u64 size, const void *data)
++{
++ struct kdbus_item *item;
++
++ item = kdbus_write_head(iter, type, size);
++ memcpy(item->data, data, size);
++ return item;
++}
++
++static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem,
++ size_t size)
++{
++ struct user_namespace *user_ns = staging->conn->user_ns;
++ struct pid_namespace *pid_ns = staging->conn->pid_ns;
++ struct kdbus_item *item = NULL, *items = mem;
++ u8 *end, *owned_names_end = NULL;
++
++ /* process metadata */
++
++ if (staging->mf && (staging->mask & KDBUS_ATTACH_CREDS)) {
++ const struct kdbus_meta_fake *mf = staging->mf;
++
++ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS,
++ sizeof(struct kdbus_creds));
++ item->creds = (struct kdbus_creds){
++ .uid = kdbus_from_kuid_keep(user_ns, mf->uid),
++ .euid = kdbus_from_kuid_keep(user_ns, mf->euid),
++ .suid = kdbus_from_kuid_keep(user_ns, mf->suid),
++ .fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid),
++ .gid = kdbus_from_kgid_keep(user_ns, mf->gid),
++ .egid = kdbus_from_kgid_keep(user_ns, mf->egid),
++ .sgid = kdbus_from_kgid_keep(user_ns, mf->sgid),
++ .fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid),
++ };
++ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_CREDS)) {
++ const struct cred *c = staging->mp->cred;
++
++ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS,
++ sizeof(struct kdbus_creds));
++ item->creds = (struct kdbus_creds){
++ .uid = kdbus_from_kuid_keep(user_ns, c->uid),
++ .euid = kdbus_from_kuid_keep(user_ns, c->euid),
++ .suid = kdbus_from_kuid_keep(user_ns, c->suid),
++ .fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid),
++ .gid = kdbus_from_kgid_keep(user_ns, c->gid),
++ .egid = kdbus_from_kgid_keep(user_ns, c->egid),
++ .sgid = kdbus_from_kgid_keep(user_ns, c->sgid),
++ .fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid),
++ };
++ }
++
++ if (staging->mf && (staging->mask & KDBUS_ATTACH_PIDS)) {
++ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS,
++ sizeof(struct kdbus_pids));
++ item->pids = (struct kdbus_pids){
++ .pid = pid_nr_ns(staging->mf->tgid, pid_ns),
++ .tid = pid_nr_ns(staging->mf->pid, pid_ns),
++ .ppid = pid_nr_ns(staging->mf->ppid, pid_ns),
++ };
++ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_PIDS)) {
++ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS,
++ sizeof(struct kdbus_pids));
++ item->pids = (struct kdbus_pids){
++ .pid = pid_nr_ns(staging->mp->tgid, pid_ns),
++ .tid = pid_nr_ns(staging->mp->pid, pid_ns),
++ .ppid = pid_nr_ns(staging->mp->ppid, pid_ns),
++ };
++ }
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUXGROUPS)) {
++ const struct group_info *info = staging->mp->cred->group_info;
++ size_t i;
++
++ item = kdbus_write_head(&items, KDBUS_ITEM_AUXGROUPS,
++ info->ngroups * sizeof(u64));
++ for (i = 0; i < info->ngroups; ++i)
++ item->data64[i] = from_kgid_munged(user_ns,
++ GROUP_AT(info, i));
++ }
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_TID_COMM))
++ item = kdbus_write_full(&items, KDBUS_ITEM_TID_COMM,
++ strlen(staging->mp->tid_comm) + 1,
++ staging->mp->tid_comm);
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_PID_COMM))
++ item = kdbus_write_full(&items, KDBUS_ITEM_PID_COMM,
++ strlen(staging->mp->pid_comm) + 1,
++ staging->mp->pid_comm);
++
++ if (staging->exe_path && (staging->mask & KDBUS_ATTACH_EXE))
++ item = kdbus_write_full(&items, KDBUS_ITEM_EXE,
++ strlen(staging->exe_path) + 1,
++ staging->exe_path);
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CMDLINE))
++ item = kdbus_write_full(&items, KDBUS_ITEM_CMDLINE,
++ strlen(staging->mp->cmdline) + 1,
++ staging->mp->cmdline);
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CGROUP))
++ item = kdbus_write_full(&items, KDBUS_ITEM_CGROUP,
++ strlen(staging->mp->cgroup) + 1,
++ staging->mp->cgroup);
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CAPS)) {
++ item = kdbus_write_head(&items, KDBUS_ITEM_CAPS,
++ sizeof(struct kdbus_meta_caps));
++ kdbus_meta_export_caps((void*)&item->caps, staging->mp,
++ user_ns);
++ }
++
++ if (staging->mf && (staging->mask & KDBUS_ATTACH_SECLABEL))
++ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
++ strlen(staging->mf->seclabel) + 1,
++ staging->mf->seclabel);
++ else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL))
++ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
++ strlen(staging->mp->seclabel) + 1,
++ staging->mp->seclabel);
++
++ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) {
++ item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT,
++ sizeof(struct kdbus_audit));
++ item->audit = (struct kdbus_audit){
++ .loginuid = from_kuid(user_ns,
++ staging->mp->audit_loginuid),
++ .sessionid = staging->mp->audit_sessionid,
++ };
++ }
++
++ /* connection metadata */
++
++ if (staging->mc && (staging->mask & KDBUS_ATTACH_NAMES)) {
++ memcpy(items, staging->mc->owned_names_items,
++ KDBUS_ALIGN8(staging->mc->owned_names_size));
++ owned_names_end = (u8 *)items + staging->mc->owned_names_size;
++ items = (void *)KDBUS_ALIGN8((unsigned long)owned_names_end);
++ }
++
++ if (staging->mc && (staging->mask & KDBUS_ATTACH_CONN_DESCRIPTION))
++ item = kdbus_write_full(&items, KDBUS_ITEM_CONN_DESCRIPTION,
++ strlen(staging->mc->conn_description) + 1,
++ staging->mc->conn_description);
++
++ if (staging->mc && (staging->mask & KDBUS_ATTACH_TIMESTAMP))
++ item = kdbus_write_full(&items, KDBUS_ITEM_TIMESTAMP,
++ sizeof(staging->mc->ts),
++ &staging->mc->ts);
++
++ /*
++ * Return real size (minus trailing padding). In case of 'owned_names'
++ * we cannot deduce it from item->size, so treat it special.
++ */
++
++ if (items == (void *)KDBUS_ALIGN8((unsigned long)owned_names_end))
++ end = owned_names_end;
++ else if (item)
++ end = (u8 *)item + item->size;
++ else
++ end = mem;
++
++ WARN_ON((u8 *)items - (u8 *)mem != size);
++ WARN_ON((void *)KDBUS_ALIGN8((unsigned long)end) != (void *)items);
++
++ return end - (u8 *)mem;
++}
++
++int kdbus_meta_emit(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
++ struct kdbus_meta_conn *mc,
++ struct kdbus_conn *conn,
++ u64 mask,
++ struct kdbus_item **out_items,
++ size_t *out_size)
++{
++ struct kdbus_meta_staging staging = {};
++ struct kdbus_item *items = NULL;
++ size_t size = 0;
++ int ret;
++
++ if (WARN_ON(mf && mp))
++ mp = NULL;
++
++ staging.mp = mp;
++ staging.mf = mf;
++ staging.mc = mc;
++ staging.conn = conn;
++
++ /* get mask of valid items */
++ if (mf)
++ staging.mask |= mf->valid;
++ if (mp) {
++ mutex_lock(&mp->lock);
++ staging.mask |= mp->valid;
++ mutex_unlock(&mp->lock);
++ }
++ if (mc) {
++ mutex_lock(&mc->lock);
++ staging.mask |= mc->valid;
++ mutex_unlock(&mc->lock);
++ }
++
++ staging.mask &= mask;
++
++ if (!staging.mask) { /* bail out if nothing to do */
++ ret = 0;
++ goto exit;
++ }
++
++ /* EXE is special as it needs a temporary page to assemble */
++ if (mp && (staging.mask & KDBUS_ATTACH_EXE)) {
++ struct path p;
++
++ /*
++ * XXX: We need access to __d_path() so we can write the path
++ * relative to conn->root_path. Once upstream, we need
++ * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that
++ * takes the root path directly. Until then, we drop this item
++ * if the root-paths differ.
++ */
++
++ get_fs_root(current->fs, &p);
++ if (path_equal(&p, &conn->root_path)) {
++ staging.exe = (void *)__get_free_page(GFP_TEMPORARY);
++ if (!staging.exe) {
++ path_put(&p);
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ staging.exe_path = d_path(&mp->exe_path, staging.exe,
++ PAGE_SIZE);
++ if (IS_ERR(staging.exe_path)) {
++ path_put(&p);
++ ret = PTR_ERR(staging.exe_path);
++ goto exit;
++ }
++ }
++ path_put(&p);
++ }
++
++ size = kdbus_meta_measure(&staging);
++ if (!size) { /* bail out if nothing to do */
++ ret = 0;
++ goto exit;
++ }
++
++ items = kmalloc(size, GFP_KERNEL);
++ if (!items) {
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ size = kdbus_meta_write(&staging, items, size);
++ if (!size) {
++ kfree(items);
++ items = NULL;
++ }
++
++ ret = 0;
++
++exit:
++ if (staging.exe)
++ free_page((unsigned long)staging.exe);
++ if (ret >= 0) {
++ *out_items = items;
++ *out_size = size;
++ }
++ return ret;
++}
++
+ /**
+ * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender
+ * and a receiver
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index c33315d0b82b..a30b0ad26af2 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -83,6 +83,13 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp,
+ u64 mask,
+ struct kdbus_pool_slice *slice,
+ off_t offset, size_t *real_size);
++int kdbus_meta_emit(struct kdbus_meta_proc *mp,
++ struct kdbus_meta_fake *mf,
++ struct kdbus_meta_conn *mc,
++ struct kdbus_conn *conn,
++ u64 mask,
++ struct kdbus_item **out_items,
++ size_t *out_size);
+ u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
+ const struct kdbus_conn *receiver);
+
+--
+2.4.3
+
+
+From fd856bf056f3737c73aefe34f55799b34919699b Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 16:46:30 +0200
+Subject: [PATCH 16/34] kdbus: speed up KDBUS_CMD_*_INFO by using meta_emit()
+
+Avoid using kdbus_meta_export*() and switch to kdbus_meta_emit(). This
+adds one kmalloc(), but on the other hand drops a call to
+kdbus_pool_slice_copy_kvec(). As the latter is way more expensive, this
+speeds up KDBUS_CMD_*_INFO ioctls by approx. 10%.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 40 +++++++++++++++++++---------------------
+ ipc/kdbus/connection.c | 42 +++++++++++++++++++++---------------------
+ 2 files changed, 40 insertions(+), 42 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index dd1e600b8f01..82b7171f1fdb 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -456,13 +456,12 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_bus *bus = conn->ep->bus;
+ struct kdbus_pool_slice *slice = NULL;
++ struct kdbus_item *meta_items = NULL;
+ struct kdbus_item_header item_hdr;
+ struct kdbus_info info = {};
+- size_t meta_size, name_len;
+- struct kvec kvec[5];
+- u64 hdr_size = 0;
+- u64 attach_flags;
+- size_t cnt = 0;
++ size_t meta_size, name_len, cnt = 0;
++ struct kvec kvec[6];
++ u64 attach_flags, size = 0;
+ int ret;
+
+ struct kdbus_arg argv[] = {
+@@ -484,8 +483,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+
+ attach_flags &= bus->attach_flags_owner;
+
+- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL,
+- &attach_flags, &meta_size);
++ ret = kdbus_meta_emit(bus->creator_meta, NULL, NULL, conn,
++ attach_flags, &meta_items, &meta_size);
+ if (ret < 0)
+ goto exit;
+
+@@ -495,26 +494,25 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+ item_hdr.type = KDBUS_ITEM_MAKE_NAME;
+ item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len;
+
+- kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &hdr_size);
+- kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &hdr_size);
+- kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &hdr_size);
+- cnt += !!kdbus_kvec_pad(&kvec[cnt], &hdr_size);
++ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size);
++ kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &size);
++ kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &size);
++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++ if (meta_size > 0) {
++ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size);
++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++ }
++
++ info.size = size;
+
+- slice = kdbus_pool_slice_alloc(conn->pool, hdr_size + meta_size, false);
++ slice = kdbus_pool_slice_alloc(conn->pool, size, false);
+ if (IS_ERR(slice)) {
+ ret = PTR_ERR(slice);
+ slice = NULL;
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn,
+- attach_flags, slice, hdr_size, &meta_size);
+- if (ret < 0)
+- goto exit;
+-
+- info.size = hdr_size + meta_size;
+-
+- ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, hdr_size);
++ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size);
+ if (ret < 0)
+ goto exit;
+
+@@ -527,6 +525,6 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp)
+
+ exit:
+ kdbus_pool_slice_release(slice);
+-
++ kfree(meta_items);
+ return kdbus_args_clear(&args, ret);
+ }
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 8fcff17ae2b6..7b800b299caf 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -1718,13 +1718,14 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ struct kdbus_pool_slice *slice = NULL;
+ struct kdbus_name_entry *entry = NULL;
+ struct kdbus_conn *owner_conn = NULL;
++ struct kdbus_item *meta_items = NULL;
+ struct kdbus_info info = {};
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_bus *bus = conn->ep->bus;
+- struct kvec kvec;
+- size_t meta_size;
++ struct kvec kvec[3];
++ size_t meta_size, cnt = 0;
+ const char *name;
+- u64 attach_flags;
++ u64 attach_flags, size = 0;
+ int ret;
+
+ struct kdbus_arg argv[] = {
+@@ -1774,10 +1775,6 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ goto exit;
+ }
+
+- info.id = owner_conn->id;
+- info.flags = owner_conn->flags;
+- kdbus_kvec_set(&kvec, &info, sizeof(info), &info.size);
+-
+ attach_flags &= atomic64_read(&owner_conn->attach_flags_send);
+
+ conn_meta = kdbus_meta_conn_new();
+@@ -1791,29 +1788,31 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ if (ret < 0)
+ goto exit;
+
+- ret = kdbus_meta_export_prepare(owner_conn->meta_proc,
+- owner_conn->meta_fake, conn_meta,
+- &attach_flags, &meta_size);
++ ret = kdbus_meta_emit(owner_conn->meta_proc, owner_conn->meta_fake,
++ conn_meta, conn, attach_flags,
++ &meta_items, &meta_size);
+ if (ret < 0)
+ goto exit;
+
+- slice = kdbus_pool_slice_alloc(conn->pool,
+- info.size + meta_size, false);
++ info.id = owner_conn->id;
++ info.flags = owner_conn->flags;
++
++ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size);
++ if (meta_size > 0) {
++ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size);
++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size);
++ }
++
++ info.size = size;
++
++ slice = kdbus_pool_slice_alloc(conn->pool, size, false);
+ if (IS_ERR(slice)) {
+ ret = PTR_ERR(slice);
+ slice = NULL;
+ goto exit;
+ }
+
+- ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake,
+- conn_meta, conn, attach_flags,
+- slice, sizeof(info), &meta_size);
+- if (ret < 0)
+- goto exit;
+-
+- info.size += meta_size;
+-
+- ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, sizeof(info));
++ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size);
+ if (ret < 0)
+ goto exit;
+
+@@ -1831,6 +1830,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp)
+ exit:
+ up_read(&bus->name_registry->rwlock);
+ kdbus_pool_slice_release(slice);
++ kfree(meta_items);
+ kdbus_meta_conn_unref(conn_meta);
+ kdbus_conn_unref(owner_conn);
+ return kdbus_args_clear(&args, ret);
+--
+2.4.3
+
+
+From b410b7c6a9e90977dd14d6da72f8e5fd39f04e0b Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 21:34:08 +0200
+Subject: [PATCH 17/34] kdbus: simplify kdbus_match_rules()
+
+Split up the huge kdbus_match_rules() helper into 3 helper functions. This
+reduces the code size almost by half, as we no longer have to maintain 4
+levels of indentation.
+
+No functional change.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/match.c | 123 +++++++++++++++++++++---------------------------------
+ 1 file changed, 48 insertions(+), 75 deletions(-)
+
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+index cc083b4211de..869a9fbce37d 100644
+--- a/ipc/kdbus/match.c
++++ b/ipc/kdbus/match.c
+@@ -204,87 +204,60 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter,
+ return true;
+ }
+
+-static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
+- struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg)
++static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
++ struct kdbus_conn *c,
++ const struct kdbus_kmsg *kmsg)
+ {
+- struct kdbus_match_rule *r;
+-
+- if (conn_src)
+- lockdep_assert_held(&conn_src->ep->bus->name_registry->rwlock);
+-
+- /*
+- * Walk all the rules and bail out immediately
+- * if any of them is unsatisfied.
+- */
+-
+- list_for_each_entry(r, &entry->rules_list, rules_entry) {
+- if (conn_src) {
+- /* messages from userspace */
+-
+- switch (r->type) {
+- case KDBUS_ITEM_BLOOM_MASK:
+- if (!kdbus_match_bloom(kmsg->bloom_filter,
+- &r->bloom_mask,
+- conn_src))
+- return false;
+- break;
+-
+- case KDBUS_ITEM_ID:
+- if (r->src_id != conn_src->id &&
+- r->src_id != KDBUS_MATCH_ID_ANY)
+- return false;
+-
+- break;
++ lockdep_assert_held(&c->ep->bus->name_registry->rwlock);
+
+- case KDBUS_ITEM_NAME:
+- if (!kdbus_conn_has_name(conn_src, r->name))
+- return false;
+-
+- break;
+-
+- default:
+- return false;
+- }
+- } else {
+- /* kernel notifications */
+-
+- if (kmsg->notify_type != r->type)
+- return false;
+-
+- switch (r->type) {
+- case KDBUS_ITEM_ID_ADD:
+- if (r->new_id != KDBUS_MATCH_ID_ANY &&
+- r->new_id != kmsg->notify_new_id)
+- return false;
+-
+- break;
+-
+- case KDBUS_ITEM_ID_REMOVE:
+- if (r->old_id != KDBUS_MATCH_ID_ANY &&
+- r->old_id != kmsg->notify_old_id)
+- return false;
++ switch (r->type) {
++ case KDBUS_ITEM_BLOOM_MASK:
++ return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c);
++ case KDBUS_ITEM_ID:
++ return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY;
++ case KDBUS_ITEM_NAME:
++ return kdbus_conn_has_name(c, r->name);
++ default:
++ return false;
++ }
++}
+
+- break;
++static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r,
++ const struct kdbus_kmsg *kmsg)
++{
++ if (kmsg->notify_type != r->type)
++ return false;
+
+- case KDBUS_ITEM_NAME_ADD:
+- case KDBUS_ITEM_NAME_CHANGE:
+- case KDBUS_ITEM_NAME_REMOVE:
+- if ((r->old_id != KDBUS_MATCH_ID_ANY &&
+- r->old_id != kmsg->notify_old_id) ||
+- (r->new_id != KDBUS_MATCH_ID_ANY &&
+- r->new_id != kmsg->notify_new_id) ||
+- (r->name && kmsg->notify_name &&
+- strcmp(r->name, kmsg->notify_name) != 0))
+- return false;
++ switch (r->type) {
++ case KDBUS_ITEM_ID_ADD:
++ return r->new_id == KDBUS_MATCH_ID_ANY ||
++ r->new_id == kmsg->notify_new_id;
++ case KDBUS_ITEM_ID_REMOVE:
++ return r->old_id == KDBUS_MATCH_ID_ANY ||
++ r->old_id == kmsg->notify_old_id;
++ case KDBUS_ITEM_NAME_ADD:
++ case KDBUS_ITEM_NAME_CHANGE:
++ case KDBUS_ITEM_NAME_REMOVE:
++ return (r->old_id == KDBUS_MATCH_ID_ANY ||
++ r->old_id == kmsg->notify_old_id) &&
++ (r->new_id == KDBUS_MATCH_ID_ANY ||
++ r->new_id == kmsg->notify_new_id) &&
++ (!r->name || !strcmp(r->name, kmsg->notify_name));
++ default:
++ return false;
++ }
++}
+
+- break;
++static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
++ struct kdbus_conn *c,
++ const struct kdbus_kmsg *kmsg)
++{
++ struct kdbus_match_rule *r;
+
+- default:
+- return false;
+- }
+- }
+- }
++ list_for_each_entry(r, &entry->rules_list, rules_entry)
++ if ((c && !kdbus_match_rule_conn(r, c, kmsg)) ||
++ (!c && !kdbus_match_rule_kernel(r, kmsg)))
++ return false;
+
+ return true;
+ }
+--
+2.4.3
+
+
+From c4146fd608177530fb3f6c6ad6e395d3fb0eee4e Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 21:39:25 +0200
+Subject: [PATCH 18/34] kdbus: pass notification details directly into policy
+ wrapper
+
+Avoid passing the kmsg into the policy wrapper, but pass the notification
+details directly. This reduces the scope of 'struct kdbus_kmsg' and avoids
+accessing its members directly. This will ease the introduction of the
+kmsg rework later on.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 3 ++-
+ ipc/kdbus/connection.c | 18 ++++++++----------
+ ipc/kdbus/connection.h | 2 +-
+ 3 files changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 82b7171f1fdb..3c33339cf332 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -298,7 +298,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * notification
+ */
+ if (!kdbus_conn_policy_see_notification(conn_dst, NULL,
+- kmsg))
++ kmsg->notify_type,
++ kmsg->notify_name))
+ continue;
+ }
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 7b800b299caf..73cad58d2acd 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -1542,19 +1542,18 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn,
+ * receive a given kernel notification
+ * @conn: Connection
+ * @conn_creds: Credentials of @conn to use for policy check
+- * @kmsg: The message carrying the notification
++ * @type: Type of notification
++ * @name: Well-known name this notification is about, or NULL
+ *
+- * This checks whether @conn is allowed to see the kernel notification @kmsg.
++ * This checks whether @conn is allowed to see the kernel notification of type
++ * @type for well-known name @name.
+ *
+ * Return: true if allowed, false if not.
+ */
+ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ const struct cred *conn_creds,
+- const struct kdbus_kmsg *kmsg)
++ u64 type, const char *name)
+ {
+- if (WARN_ON(kmsg->msg.src_id != KDBUS_SRC_ID_KERNEL))
+- return false;
+-
+ /*
+ * Depending on the notification type, broadcasted kernel notifications
+ * have to be filtered:
+@@ -1567,12 +1566,11 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ * broadcast to everyone, to allow tracking peers.
+ */
+
+- switch (kmsg->notify_type) {
++ switch (type) {
+ case KDBUS_ITEM_NAME_ADD:
+ case KDBUS_ITEM_NAME_REMOVE:
+ case KDBUS_ITEM_NAME_CHANGE:
+- return kdbus_conn_policy_see_name(conn, conn_creds,
+- kmsg->notify_name);
++ return kdbus_conn_policy_see_name(conn, conn_creds, name);
+
+ case KDBUS_ITEM_ID_ADD:
+ case KDBUS_ITEM_ID_REMOVE:
+@@ -1580,7 +1578,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+
+ default:
+ WARN(1, "Invalid type for notification broadcast: %llu\n",
+- (unsigned long long)kmsg->notify_type);
++ (unsigned long long)type);
+ return false;
+ }
+ }
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index 0eb3d2e70a5e..aa4234a4e3e4 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -152,7 +152,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn,
+ const char *name);
+ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ const struct cred *curr_creds,
+- const struct kdbus_kmsg *kmsg);
++ u64 type, const char *name);
+
+ /* command dispatcher */
+ struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
+--
+2.4.3
+
+
+From bdac38baecf3b1af14b647f791a795a91ef7f6c6 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 21:46:39 +0200
+Subject: [PATCH 19/34] kdbus: pass source connection to queue handling
+
+Make sure we always pass the source-connection of a message along. Right
+now we drop it for queue allocation, which prevents us from accessing any
+source details in the queue helpers. We work around this, by passing
+everything manually, but that just makes things more complex.
+
+Pass the source connection down to the queue helpers to allow further
+cleanups in follow up patches.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 15 +++++++--------
+ ipc/kdbus/queue.c | 9 +++++----
+ ipc/kdbus/queue.h | 6 +++---
+ 3 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 73cad58d2acd..f1667df70b7f 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -779,9 +779,9 @@ void kdbus_conn_lost_message(struct kdbus_conn *c)
+
+ /* Callers should take the conn_dst lock */
+ static struct kdbus_queue_entry *
+-kdbus_conn_entry_make(struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
+- struct kdbus_user *user)
++kdbus_conn_entry_make(struct kdbus_conn *conn_src,
++ struct kdbus_conn *conn_dst,
++ const struct kdbus_kmsg *kmsg)
+ {
+ /* The remote connection was disconnected */
+ if (!kdbus_conn_active(conn_dst))
+@@ -799,7 +799,7 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_dst,
+ kmsg->res && kmsg->res->fds_count > 0)
+ return ERR_PTR(-ECOMM);
+
+- return kdbus_queue_entry_new(conn_dst, kmsg, user);
++ return kdbus_queue_entry_new(conn_src, conn_dst, kmsg);
+ }
+
+ /*
+@@ -822,8 +822,8 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ * entry and attach it to the reply object
+ */
+ if (reply_wake->waiting) {
+- entry = kdbus_conn_entry_make(conn_dst, kmsg,
+- reply_wake->reply_src->user);
++ entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst,
++ kmsg);
+ if (IS_ERR(entry))
+ ret = PTR_ERR(entry);
+ else
+@@ -879,8 +879,7 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+
+ kdbus_conn_lock2(conn_src, conn_dst);
+
+- entry = kdbus_conn_entry_make(conn_dst, kmsg,
+- conn_src ? conn_src->user : NULL);
++ entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg);
+ if (IS_ERR(entry)) {
+ ret = PTR_ERR(entry);
+ goto exit_unlock;
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+index 1e7916155036..43824c93fb03 100644
+--- a/ipc/kdbus/queue.c
++++ b/ipc/kdbus/queue.c
+@@ -171,9 +171,9 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry)
+
+ /**
+ * kdbus_queue_entry_new() - allocate a queue entry
++ * @conn_src: source connection
+ * @conn_dst: destination connection
+ * @kmsg: kmsg object the queue entry should track
+- * @user: user to account message on (or NULL for kernel messages)
+ *
+ * Allocates a queue entry based on a given kmsg and allocate space for
+ * the message payload and the requested metadata in the connection's pool.
+@@ -181,10 +181,11 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry)
+ *
+ * Return: the allocated entry on success, or an ERR_PTR on failures.
+ */
+-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
+- struct kdbus_user *user)
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src,
++ struct kdbus_conn *conn_dst,
++ const struct kdbus_kmsg *kmsg)
+ {
++ struct kdbus_user *user = conn_src ? conn_src->user : NULL;
+ struct kdbus_msg_resources *res = kmsg->res;
+ const struct kdbus_msg *msg = &kmsg->msg;
+ struct kdbus_queue_entry *entry;
+diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h
+index 7f2db96fe308..ac471d0c809d 100644
+--- a/ipc/kdbus/queue.h
++++ b/ipc/kdbus/queue.h
+@@ -78,9 +78,9 @@ void kdbus_queue_init(struct kdbus_queue *queue);
+ struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue,
+ s64 priority, bool use_priority);
+
+-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
+- struct kdbus_user *user);
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src,
++ struct kdbus_conn *conn_dst,
++ const struct kdbus_kmsg *kmsg);
+ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry);
+ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
+ u64 *return_flags, bool install_fds);
+--
+2.4.3
+
+
+From 5347bdd081c75f847c9739fc50e43f71440687bb Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 21:56:25 +0200
+Subject: [PATCH 20/34] kdbus: remove redundant kmsg->dst_name_id
+
+Right now we store the dst_name_id in "struct kdbus_kmsg" just to make
+sure it's available when we allocate the "struct kdbus_queue_entry". This
+is really not needed and we can easily get rid of this field by passing
+the kdbus_name_entry to the queue allocator.
+
+No change in behavior.
+
+This change allows us to make "kmsg" constant in kdbus_pin_dst() and avoid
+touching it ever outside of kmsg-allocation.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 6 ++++--
+ ipc/kdbus/connection.c | 29 ++++++++++++++++-------------
+ ipc/kdbus/connection.h | 3 ++-
+ ipc/kdbus/message.h | 2 --
+ ipc/kdbus/notify.c | 3 ++-
+ ipc/kdbus/queue.c | 1 -
+ 6 files changed, 24 insertions(+), 20 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 3c33339cf332..16f69acfec8a 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -303,7 +303,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ continue;
+ }
+
+- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL);
++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL,
++ NULL);
+ if (ret < 0)
+ kdbus_conn_lost_message(conn_dst);
+ }
+@@ -346,7 +347,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
+ }
+ }
+
+- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL);
++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL,
++ NULL);
+ if (ret < 0)
+ kdbus_conn_lost_message(conn_dst);
+ }
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index f1667df70b7f..2ce63ccca3b4 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -866,13 +866,15 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ * @conn_dst: The connection to queue into
+ * @kmsg: The kmsg to queue
+ * @reply: The reply tracker to attach to the queue entry
++ * @name: Destination name this msg is sent to, or NULL
+ *
+ * Return: 0 on success. negative error otherwise.
+ */
+ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ struct kdbus_conn *conn_dst,
+ const struct kdbus_kmsg *kmsg,
+- struct kdbus_reply *reply)
++ struct kdbus_reply *reply,
++ const struct kdbus_name_entry *name)
+ {
+ struct kdbus_queue_entry *entry;
+ int ret;
+@@ -891,6 +893,14 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ schedule_delayed_work(&conn_src->work, 0);
+ }
+
++ /*
++ * Record the sequence number of the registered name; it will
++ * be remembered by the queue, in case messages addressed to a
++ * name need to be moved from or to an activator.
++ */
++ if (name)
++ entry->dst_name_id = name->name_id;
++
+ kdbus_queue_entry_enqueue(entry, reply);
+ wake_up_interruptible(&conn_dst->wait);
+
+@@ -1023,14 +1033,14 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src,
+ }
+
+ static int kdbus_pin_dst(struct kdbus_bus *bus,
+- struct kdbus_kmsg *kmsg,
++ const struct kdbus_kmsg *kmsg,
+ struct kdbus_name_entry **out_name,
+ struct kdbus_conn **out_dst)
+ {
+ struct kdbus_msg_resources *res = kmsg->res;
++ const struct kdbus_msg *msg = &kmsg->msg;
+ struct kdbus_name_entry *name = NULL;
+ struct kdbus_conn *dst = NULL;
+- struct kdbus_msg *msg = &kmsg->msg;
+ int ret;
+
+ if (WARN_ON(!res))
+@@ -1075,13 +1085,6 @@ static int kdbus_pin_dst(struct kdbus_bus *bus,
+ ret = -EADDRNOTAVAIL;
+ goto error;
+ }
+-
+- /*
+- * Record the sequence number of the registered name; it will
+- * be passed on to the queue, in case messages addressed to a
+- * name need to be moved from or to an activator.
+- */
+- kmsg->dst_name_id = name->name_id;
+ }
+
+ *out_name = name;
+@@ -1142,7 +1145,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+ if (wake)
+ ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake);
+ else
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL);
++ ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name);
+
+ exit:
+ up_read(&bus->name_registry->rwlock);
+@@ -1217,7 +1220,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+
+ kdbus_bus_eavesdrop(bus, src, kmsg);
+
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait);
++ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name);
+ if (ret < 0)
+ goto exit;
+
+@@ -1287,7 +1290,7 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+ if (!is_signal)
+ kdbus_bus_eavesdrop(bus, src, kmsg);
+
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait);
++ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name);
+ if (ret < 0 && !is_signal)
+ goto exit;
+
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index aa4234a4e3e4..8cffba94a564 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -135,7 +135,8 @@ void kdbus_conn_lost_message(struct kdbus_conn *c);
+ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ struct kdbus_conn *conn_dst,
+ const struct kdbus_kmsg *kmsg,
+- struct kdbus_reply *reply);
++ struct kdbus_reply *reply,
++ const struct kdbus_name_entry *name);
+ void kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
+ struct kdbus_conn *conn_src,
+ u64 name_id);
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index 3b733474f335..88e2366e49b6 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -86,7 +86,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
+ * @notify_old_id: Short-cut for faster lookup
+ * @notify_new_id: Short-cut for faster lookup
+ * @notify_name: Short-cut for faster lookup
+- * @dst_name_id: Short-cut to msg for faster lookup
+ * @bloom_filter: Bloom filter to match message properties
+ * @notify_entry: List of kernel-generated notifications
+ * @iov: Array of iovec, describing the payload to copy
+@@ -104,7 +103,6 @@ struct kdbus_kmsg {
+ u64 notify_new_id;
+ const char *notify_name;
+
+- u64 dst_name_id;
+ const struct kdbus_bloom_filter *bloom_filter;
+ struct list_head notify_entry;
+
+diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c
+index 216720fc26ff..bcf7555e386a 100644
+--- a/ipc/kdbus/notify.c
++++ b/ipc/kdbus/notify.c
+@@ -218,7 +218,8 @@ void kdbus_notify_flush(struct kdbus_bus *bus)
+ conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id);
+ if (conn) {
+ kdbus_bus_eavesdrop(bus, NULL, kmsg);
+- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL);
++ kdbus_conn_entry_insert(NULL, conn, kmsg, NULL,
++ NULL);
+ kdbus_conn_unref(conn);
+ }
+ } else {
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+index 43824c93fb03..4749b23a4f14 100644
+--- a/ipc/kdbus/queue.c
++++ b/ipc/kdbus/queue.c
+@@ -203,7 +203,6 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src,
+
+ INIT_LIST_HEAD(&entry->entry);
+ entry->priority = msg->priority;
+- entry->dst_name_id = kmsg->dst_name_id;
+ entry->msg_res = kdbus_msg_resources_ref(res);
+ entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta);
+ entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta);
+--
+2.4.3
+
+
+From 462d196d27840d84e1ff686c481fbbd99509864e Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 23:04:49 +0200
+Subject: [PATCH 21/34] kdbus: simplify collecting metadata on messages
+
+Instead of collecting metadata on the call-side for each message origin,
+move it to the core: Handle it directly before allocating the message
+slice.
+
+The number of times we call into the helper stays exactly the same, but
+the code paths are reduced significantly.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 16 ----------------
+ ipc/kdbus/connection.c | 31 ++++++++++++-------------------
+ ipc/kdbus/message.c | 4 ++--
+ ipc/kdbus/message.h | 4 ++--
+ 4 files changed, 16 insertions(+), 39 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 16f69acfec8a..bc3c3c0383cb 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -284,13 +284,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ */
+ if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src))
+ continue;
+-
+- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src,
+- conn_dst);
+- if (ret < 0) {
+- kdbus_conn_lost_message(conn_dst);
+- continue;
+- }
+ } else {
+ /*
+ * Check if there is a policy db that prevents the
+@@ -338,15 +331,6 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
+
+ down_read(&bus->conn_rwlock);
+ list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) {
+- if (conn_src) {
+- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src,
+- conn_dst);
+- if (ret < 0) {
+- kdbus_conn_lost_message(conn_dst);
+- continue;
+- }
+- }
+-
+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL,
+ NULL);
+ if (ret < 0)
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 2ce63ccca3b4..25e49455b24b 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -813,7 +813,12 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ {
+ struct kdbus_queue_entry *entry;
+ int remote_ret;
+- int ret = 0;
++ int ret;
++
++ ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src,
++ conn_dst);
++ if (ret < 0)
++ return ret;
+
+ mutex_lock(&reply_wake->reply_dst->lock);
+
+@@ -879,6 +884,12 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ struct kdbus_queue_entry *entry;
+ int ret;
+
++ if (conn_src) {
++ ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst);
++ if (ret < 0)
++ return ret;
++ }
++
+ kdbus_conn_lock2(conn_src, conn_dst);
+
+ entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg);
+@@ -1132,12 +1143,6 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+ goto exit;
+ }
+
+- /* attach metadata */
+-
+- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst);
+- if (ret < 0)
+- goto exit;
+-
+ /* send message */
+
+ kdbus_bus_eavesdrop(bus, src, kmsg);
+@@ -1210,12 +1215,6 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+ goto exit;
+ }
+
+- /* attach metadata */
+-
+- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst);
+- if (ret < 0)
+- goto exit;
+-
+ /* send message */
+
+ kdbus_bus_eavesdrop(bus, src, kmsg);
+@@ -1279,12 +1278,6 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+ }
+ }
+
+- /* attach metadata */
+-
+- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst);
+- if (ret < 0)
+- goto exit;
+-
+ /* send message */
+
+ if (!is_signal)
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 974e8c4f6039..9346a04e10ef 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -619,8 +619,8 @@ exit_free:
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+-int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src,
+- struct kdbus_conn *dst)
++int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
++ struct kdbus_conn *src, struct kdbus_conn *dst)
+ {
+ u64 attach;
+ int ret;
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index 88e2366e49b6..9a11389d9f27 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -125,7 +125,7 @@ struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size);
+ struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn,
+ struct kdbus_cmd_send *cmd_send);
+ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg);
+-int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src,
+- struct kdbus_conn *dst);
++int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
++ struct kdbus_conn *src, struct kdbus_conn *dst);
+
+ #endif
+--
+2.4.3
+
+
+From 6d75879b543c4eeb9544547e87174bba1be3a173 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 23:38:19 +0200
+Subject: [PATCH 22/34] kdbus: simplify notification shortcuts
+
+Right now, we have a bunch of shortcuts in "struct kdbus_kmsg" that cache
+the values of the first kdbus-item, _iff_ the message is a kernel
+notification. These are then used during match-db lookups and policy
+lookups.
+
+These shortcuts make the actually more complex and in no way faster. Drop
+them in favor of a simple "struct kdbus_item *notify" shortcut which
+points to the notification item (to distinguish it from normal
+user-supplied messages). This way, we save a bunch of code and can even
+simplify the notification message setup (as it is now fully generic).
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 3 +-
+ ipc/kdbus/connection.c | 15 +++++-----
+ ipc/kdbus/connection.h | 2 +-
+ ipc/kdbus/match.c | 14 +++++----
+ ipc/kdbus/message.c | 54 ++++++++++++++++++----------------
+ ipc/kdbus/message.h | 14 ++++-----
+ ipc/kdbus/notify.c | 78 ++++++++++++--------------------------------------
+ 7 files changed, 69 insertions(+), 111 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index bc3c3c0383cb..4f51723f8780 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -291,8 +291,7 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * notification
+ */
+ if (!kdbus_conn_policy_see_notification(conn_dst, NULL,
+- kmsg->notify_type,
+- kmsg->notify_name))
++ &kmsg->msg))
+ continue;
+ }
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 25e49455b24b..29b99c023bfe 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -1537,17 +1537,15 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn,
+ * receive a given kernel notification
+ * @conn: Connection
+ * @conn_creds: Credentials of @conn to use for policy check
+- * @type: Type of notification
+- * @name: Well-known name this notification is about, or NULL
++ * @msg: Notification message
+ *
+- * This checks whether @conn is allowed to see the kernel notification of type
+- * @type for well-known name @name.
++ * This checks whether @conn is allowed to see the kernel notification.
+ *
+ * Return: true if allowed, false if not.
+ */
+ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ const struct cred *conn_creds,
+- u64 type, const char *name)
++ const struct kdbus_msg *msg)
+ {
+ /*
+ * Depending on the notification type, broadcasted kernel notifications
+@@ -1561,11 +1559,12 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ * broadcast to everyone, to allow tracking peers.
+ */
+
+- switch (type) {
++ switch (msg->items[0].type) {
+ case KDBUS_ITEM_NAME_ADD:
+ case KDBUS_ITEM_NAME_REMOVE:
+ case KDBUS_ITEM_NAME_CHANGE:
+- return kdbus_conn_policy_see_name(conn, conn_creds, name);
++ return kdbus_conn_policy_see_name(conn, conn_creds,
++ msg->items[0].name_change.name);
+
+ case KDBUS_ITEM_ID_ADD:
+ case KDBUS_ITEM_ID_REMOVE:
+@@ -1573,7 +1572,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+
+ default:
+ WARN(1, "Invalid type for notification broadcast: %llu\n",
+- (unsigned long long)type);
++ (unsigned long long)msg->items[0].type);
+ return false;
+ }
+ }
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index 8cffba94a564..90c1bcc91fe6 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -153,7 +153,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn,
+ const char *name);
+ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn,
+ const struct cred *curr_creds,
+- u64 type, const char *name);
++ const struct kdbus_msg *msg);
+
+ /* command dispatcher */
+ struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged,
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+index 869a9fbce37d..3f86e4c81468 100644
+--- a/ipc/kdbus/match.c
++++ b/ipc/kdbus/match.c
+@@ -225,24 +225,26 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
+ static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r,
+ const struct kdbus_kmsg *kmsg)
+ {
+- if (kmsg->notify_type != r->type)
++ struct kdbus_item *n = kmsg->notify;
++
++ if (WARN_ON(!n) || n->type != r->type)
+ return false;
+
+ switch (r->type) {
+ case KDBUS_ITEM_ID_ADD:
+ return r->new_id == KDBUS_MATCH_ID_ANY ||
+- r->new_id == kmsg->notify_new_id;
++ r->new_id == n->id_change.id;
+ case KDBUS_ITEM_ID_REMOVE:
+ return r->old_id == KDBUS_MATCH_ID_ANY ||
+- r->old_id == kmsg->notify_old_id;
++ r->old_id == n->id_change.id;
+ case KDBUS_ITEM_NAME_ADD:
+ case KDBUS_ITEM_NAME_CHANGE:
+ case KDBUS_ITEM_NAME_REMOVE:
+ return (r->old_id == KDBUS_MATCH_ID_ANY ||
+- r->old_id == kmsg->notify_old_id) &&
++ r->old_id == n->name_change.old_id.id) &&
+ (r->new_id == KDBUS_MATCH_ID_ANY ||
+- r->new_id == kmsg->notify_new_id) &&
+- (!r->name || !strcmp(r->name, kmsg->notify_name));
++ r->new_id == n->name_change.new_id.id) &&
++ (!r->name || !strcmp(r->name, n->name_change.name));
+ default:
+ return false;
+ }
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 9346a04e10ef..7f23e5c857dd 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -124,46 +124,50 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg)
+ kfree(kmsg);
+ }
+
+-/**
+- * kdbus_kmsg_new() - allocate message
+- * @bus: Bus this message is allocated on
+- * @extra_size: Additional size to reserve for data
+- *
+- * Return: new kdbus_kmsg on success, ERR_PTR on failure.
+- */
+-struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size)
++struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus,
++ u64 dst, u64 cookie_timeout,
++ size_t it_size, size_t it_type)
+ {
+- struct kdbus_kmsg *m;
++ struct kdbus_kmsg *kmsg;
+ size_t size;
+ int ret;
+
+- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(extra_size);
+- m = kzalloc(size, GFP_KERNEL);
+- if (!m)
++ size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size);
++ kmsg = kzalloc(size, GFP_KERNEL);
++ if (!kmsg)
+ return ERR_PTR(-ENOMEM);
+
+- m->seq = atomic64_inc_return(&bus->domain->last_id);
+- m->msg.size = size - KDBUS_KMSG_HEADER_SIZE;
+- m->msg.items[0].size = KDBUS_ITEM_SIZE(extra_size);
++ kmsg->seq = atomic64_inc_return(&bus->domain->last_id);
+
+- m->proc_meta = kdbus_meta_proc_new();
+- if (IS_ERR(m->proc_meta)) {
+- ret = PTR_ERR(m->proc_meta);
+- m->proc_meta = NULL;
++ kmsg->proc_meta = kdbus_meta_proc_new();
++ if (IS_ERR(kmsg->proc_meta)) {
++ ret = PTR_ERR(kmsg->proc_meta);
++ kmsg->proc_meta = NULL;
+ goto exit;
+ }
+
+- m->conn_meta = kdbus_meta_conn_new();
+- if (IS_ERR(m->conn_meta)) {
+- ret = PTR_ERR(m->conn_meta);
+- m->conn_meta = NULL;
++ kmsg->conn_meta = kdbus_meta_conn_new();
++ if (IS_ERR(kmsg->conn_meta)) {
++ ret = PTR_ERR(kmsg->conn_meta);
++ kmsg->conn_meta = NULL;
+ goto exit;
+ }
+
+- return m;
++ kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE;
++ kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ?
++ KDBUS_MSG_SIGNAL : 0;
++ kmsg->msg.dst_id = dst;
++ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL;
++ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL;
++ kmsg->msg.cookie_reply = cookie_timeout;
++ kmsg->notify = kmsg->msg.items;
++ kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size;
++ kmsg->notify->type = it_type;
++
++ return kmsg;
+
+ exit:
+- kdbus_kmsg_free(m);
++ kdbus_kmsg_free(kmsg);
+ return ERR_PTR(ret);
+ }
+
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index 9a11389d9f27..5755ad4c9fd9 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -82,10 +82,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
+ /**
+ * struct kdbus_kmsg - internal message handling data
+ * @seq: Domain-global message sequence number
+- * @notify_type: Short-cut for faster lookup
+- * @notify_old_id: Short-cut for faster lookup
+- * @notify_new_id: Short-cut for faster lookup
+- * @notify_name: Short-cut for faster lookup
++ * @notify: Short-cut to notify-item for kernel notifications
+ * @bloom_filter: Bloom filter to match message properties
+ * @notify_entry: List of kernel-generated notifications
+ * @iov: Array of iovec, describing the payload to copy
+@@ -98,10 +95,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
+ */
+ struct kdbus_kmsg {
+ u64 seq;
+- u64 notify_type;
+- u64 notify_old_id;
+- u64 notify_new_id;
+- const char *notify_name;
++ struct kdbus_item *notify;
+
+ const struct kdbus_bloom_filter *bloom_filter;
+ struct list_head notify_entry;
+@@ -121,7 +115,9 @@ struct kdbus_kmsg {
+ struct kdbus_bus;
+ struct kdbus_conn;
+
+-struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size);
++struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus,
++ u64 dst, u64 cookie_timeout,
++ size_t it_size, size_t it_type);
+ struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn,
+ struct kdbus_cmd_send *cmd_send);
+ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg);
+diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c
+index bcf7555e386a..a07d242d0470 100644
+--- a/ipc/kdbus/notify.c
++++ b/ipc/kdbus/notify.c
+@@ -39,29 +39,13 @@ static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg,
+ static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id,
+ u64 cookie, u64 msg_type)
+ {
+- struct kdbus_kmsg *kmsg = NULL;
++ struct kdbus_kmsg *kmsg;
+
+- WARN_ON(id == 0);
+-
+- kmsg = kdbus_kmsg_new(bus, 0);
++ kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type);
+ if (IS_ERR(kmsg))
+ return PTR_ERR(kmsg);
+
+- /*
+- * a kernel-generated notification can only contain one
+- * struct kdbus_item, so make a shortcut here for
+- * faster lookup in the match db.
+- */
+- kmsg->notify_type = msg_type;
+- kmsg->msg.flags = KDBUS_MSG_SIGNAL;
+- kmsg->msg.dst_id = id;
+- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL;
+- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL;
+- kmsg->msg.cookie_reply = cookie;
+- kmsg->msg.items[0].type = msg_type;
+-
+ kdbus_notify_add_tail(kmsg, bus);
+-
+ return 0;
+ }
+
+@@ -115,32 +99,24 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
+ u64 old_flags, u64 new_flags,
+ const char *name)
+ {
+- struct kdbus_kmsg *kmsg = NULL;
+ size_t name_len, extra_size;
++ struct kdbus_kmsg *kmsg;
+
+ name_len = strlen(name) + 1;
+ extra_size = sizeof(struct kdbus_notify_name_change) + name_len;
+- kmsg = kdbus_kmsg_new(bus, extra_size);
++
++ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++ extra_size, type);
+ if (IS_ERR(kmsg))
+ return PTR_ERR(kmsg);
+
+- kmsg->msg.flags = KDBUS_MSG_SIGNAL;
+- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST;
+- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL;
+- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL;
+- kmsg->notify_type = type;
+- kmsg->notify_old_id = old_id;
+- kmsg->notify_new_id = new_id;
+- kmsg->msg.items[0].type = type;
+- kmsg->msg.items[0].name_change.old_id.id = old_id;
+- kmsg->msg.items[0].name_change.old_id.flags = old_flags;
+- kmsg->msg.items[0].name_change.new_id.id = new_id;
+- kmsg->msg.items[0].name_change.new_id.flags = new_flags;
+- memcpy(kmsg->msg.items[0].name_change.name, name, name_len);
+- kmsg->notify_name = kmsg->msg.items[0].name_change.name;
++ kmsg->notify->name_change.old_id.id = old_id;
++ kmsg->notify->name_change.old_id.flags = old_flags;
++ kmsg->notify->name_change.new_id.id = new_id;
++ kmsg->notify->name_change.new_id.flags = new_flags;
++ memcpy(kmsg->notify->name_change.name, name, name_len);
+
+ kdbus_notify_add_tail(kmsg, bus);
+-
+ return 0;
+ }
+
+@@ -156,37 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
+ */
+ int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags)
+ {
+- struct kdbus_kmsg *kmsg = NULL;
++ struct kdbus_kmsg *kmsg;
++ size_t extra_size;
+
+- kmsg = kdbus_kmsg_new(bus, sizeof(struct kdbus_notify_id_change));
++ extra_size = sizeof(struct kdbus_notify_id_change);
++ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++ extra_size, type);
+ if (IS_ERR(kmsg))
+ return PTR_ERR(kmsg);
+
+- kmsg->msg.flags = KDBUS_MSG_SIGNAL;
+- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST;
+- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL;
+- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL;
+- kmsg->notify_type = type;
+-
+- switch (type) {
+- case KDBUS_ITEM_ID_ADD:
+- kmsg->notify_new_id = id;
+- break;
+-
+- case KDBUS_ITEM_ID_REMOVE:
+- kmsg->notify_old_id = id;
+- break;
+-
+- default:
+- BUG();
+- }
+-
+- kmsg->msg.items[0].type = type;
+- kmsg->msg.items[0].id_change.id = id;
+- kmsg->msg.items[0].id_change.flags = flags;
++ kmsg->notify->id_change.id = id;
++ kmsg->notify->id_change.flags = flags;
+
+ kdbus_notify_add_tail(kmsg, bus);
+-
+ return 0;
+ }
+
+--
+2.4.3
+
+
+From 2e3c15be5c1f48a9082b47a5cf825dc7c9592b12 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Fri, 19 Jun 2015 23:56:19 +0200
+Subject: [PATCH 23/34] kdbus: rewrite message importer
+
+This is a complete rewrite of the message importer (currently known as
+'kmsg'). I did some benchmarks on the old code, and our many calls into
+kdbus_pool_slice_copy_iovec/kvec() are by far the biggest CPU consumers.
+As it turns out, we can reduce the number of calls into that function to
+*one* (and one additional call per FD-set transmitted). Compared to our
+10x (?) calls we do right now, this reduces the time spent on a message
+transaction significantly.
+
+The new message importer uses a new structure called "struct
+kdbus_staging". This structure is solely used to import the "kdbus_msg"
+object into the kernel, parse it, create some helper data and then use it
+to allocate messages in each receivers pool. The staging object thus is
+only used at SEND time and its sole purpose is to prepare for the real
+message we allocate (as part of the queue_entry). Hence, the rename to
+kdbus_staging, instead of kdbus_kmsg (which was really misleading).
+
+Furthermore, this patch replaces "struct kdbus_msg_resources". The old
+resources contained far more data than was really necessary. There is no
+reason to pin VECs until RECV time. This can all be dropped. All that
+needs to be pinned is memfds and fds.
+
+This patch only introduces the new infrastructure. It is not hooked up,
+yet. Follow-up patches will make sure it's actually used.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/message.c | 990 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ipc/kdbus/message.h | 93 +++++
+ 2 files changed, 1083 insertions(+)
+
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 7f23e5c857dd..f1ec69f3697f 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -638,3 +638,993 @@ int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
+
+ return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach);
+ }
++
++static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds)
++{
++ size_t size_offsets, size_memfds, size_fds, size;
++ struct kdbus_gaps *gaps;
++
++ size_offsets = n_memfds * sizeof(*gaps->memfd_offsets);
++ size_memfds = n_memfds * sizeof(*gaps->memfd_files);
++ size_fds = n_fds * sizeof(*gaps->fd_files);
++ size = sizeof(*gaps) + size_offsets + size_memfds + size_fds;
++
++ gaps = kzalloc(size, GFP_KERNEL);
++ if (!gaps)
++ return ERR_PTR(-ENOMEM);
++
++ kref_init(&gaps->kref);
++ gaps->n_memfds = 0; /* we reserve n_memfds, but don't enforce them */
++ gaps->memfd_offsets = (void *)(gaps + 1);
++ gaps->memfd_files = (void *)((u8 *)gaps->memfd_offsets + size_offsets);
++ gaps->n_fds = 0; /* we reserve n_fds, but don't enforce them */
++ gaps->fd_files = (void *)((u8 *)gaps->memfd_files + size_memfds);
++
++ return gaps;
++}
++
++static void kdbus_gaps_free(struct kref *kref)
++{
++ struct kdbus_gaps *gaps = container_of(kref, struct kdbus_gaps, kref);
++ size_t i;
++
++ for (i = 0; i < gaps->n_fds; ++i)
++ if (gaps->fd_files[i])
++ fput(gaps->fd_files[i]);
++ for (i = 0; i < gaps->n_memfds; ++i)
++ if (gaps->memfd_files[i])
++ fput(gaps->memfd_files[i]);
++
++ kfree(gaps);
++}
++
++/**
++ * kdbus_gaps_ref() - gain reference
++ * @gaps: gaps object
++ *
++ * Return: @gaps is returned
++ */
++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps)
++{
++ if (gaps)
++ kref_get(&gaps->kref);
++ return gaps;
++}
++
++/**
++ * kdbus_gaps_unref() - drop reference
++ * @gaps: gaps object
++ *
++ * Return: NULL
++ */
++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps)
++{
++ if (gaps)
++ kref_put(&gaps->kref, kdbus_gaps_free);
++ return NULL;
++}
++
++/**
++ * kdbus_gaps_install() - install file-descriptors
++ * @gaps: gaps object, or NULL
++ * @slice: pool slice that contains the message
++ * @out_incomplete output variable to note incomplete fds
++ *
++ * This function installs all file-descriptors of @gaps into the current
++ * process and copies the file-descriptor numbers into the target pool slice.
++ *
++ * If the file-descriptors were only partially installed, then @out_incomplete
++ * will be set to true. Otherwise, it's set to false.
++ *
++ * Return: 0 on success, negative error code on failure
++ */
++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice,
++ bool *out_incomplete)
++{
++ bool incomplete_fds = false;
++ struct kvec kvec;
++ size_t i, n_fds;
++ int ret, *fds;
++
++ if (!gaps) {
++ /* nothing to do */
++ *out_incomplete = incomplete_fds;
++ return 0;
++ }
++
++ n_fds = gaps->n_fds + gaps->n_memfds;
++ if (n_fds < 1) {
++ /* nothing to do */
++ *out_incomplete = incomplete_fds;
++ return 0;
++ }
++
++ fds = kmalloc_array(n_fds, sizeof(*fds), GFP_TEMPORARY);
++ n_fds = 0;
++ if (!fds)
++ return -ENOMEM;
++
++ /* 1) allocate fds and copy them over */
++
++ if (gaps->n_fds > 0) {
++ for (i = 0; i < gaps->n_fds; ++i) {
++ int fd;
++
++ fd = get_unused_fd_flags(O_CLOEXEC);
++ if (fd < 0)
++ incomplete_fds = true;
++
++ WARN_ON(!gaps->fd_files[i]);
++
++ fds[n_fds++] = fd < 0 ? -1 : fd;
++ }
++
++ /*
++ * The file-descriptor array can only be present once per
++ * message. Hence, prepare all fds and then copy them over with
++ * a single kvec.
++ */
++
++ WARN_ON(!gaps->fd_offset);
++
++ kvec.iov_base = fds;
++ kvec.iov_len = gaps->n_fds * sizeof(*fds);
++ ret = kdbus_pool_slice_copy_kvec(slice, gaps->fd_offset,
++ &kvec, 1, kvec.iov_len);
++ if (ret < 0)
++ goto exit;
++ }
++
++ for (i = 0; i < gaps->n_memfds; ++i) {
++ int memfd;
++
++ memfd = get_unused_fd_flags(O_CLOEXEC);
++ if (memfd < 0) {
++ incomplete_fds = true;
++ /* memfds are initialized to -1, skip copying it */
++ continue;
++ }
++
++ fds[n_fds++] = memfd;
++
++ /*
++ * memfds have to be copied individually as they each are put
++ * into a separate item. This should not be an issue, though,
++ * as usually there is no need to send more than one memfd per
++ * message.
++ */
++
++ WARN_ON(!gaps->memfd_offsets[i]);
++ WARN_ON(!gaps->memfd_files[i]);
++
++ kvec.iov_base = &memfd;
++ kvec.iov_len = sizeof(memfd);
++ ret = kdbus_pool_slice_copy_kvec(slice, gaps->memfd_offsets[i],
++ &kvec, 1, kvec.iov_len);
++ if (ret < 0)
++ goto exit;
++ }
++
++ /* 2) install fds now that everything was successful */
++
++ for (i = 0; i < gaps->n_fds; ++i)
++ if (fds[i] >= 0)
++ fd_install(fds[i], get_file(gaps->fd_files[i]));
++ for (i = 0; i < gaps->n_memfds; ++i)
++ if (fds[gaps->n_fds + i] >= 0)
++ fd_install(fds[gaps->n_fds + i],
++ get_file(gaps->memfd_files[i]));
++
++ ret = 0;
++
++exit:
++ if (ret < 0)
++ for (i = 0; i < n_fds; ++i)
++ put_unused_fd(fds[i]);
++ kfree(fds);
++ *out_incomplete = incomplete_fds;
++ return ret;
++}
++
++static struct file *kdbus_get_fd(int fd)
++{
++ struct file *f, *ret;
++ struct inode *inode;
++ struct socket *sock;
++
++ if (fd < 0)
++ return ERR_PTR(-EBADF);
++
++ f = fget_raw(fd);
++ if (!f)
++ return ERR_PTR(-EBADF);
++
++ inode = file_inode(f);
++ sock = S_ISSOCK(inode->i_mode) ? SOCKET_I(inode) : NULL;
++
++ if (f->f_mode & FMODE_PATH)
++ ret = f; /* O_PATH is always allowed */
++ else if (f->f_op == &kdbus_handle_ops)
++ ret = ERR_PTR(-EOPNOTSUPP); /* disallow kdbus-fd over kdbus */
++ else if (sock && sock->sk && sock->ops && sock->ops->family == PF_UNIX)
++ ret = ERR_PTR(-EOPNOTSUPP); /* disallow UDS over kdbus */
++ else
++ ret = f; /* all other are allowed */
++
++ if (f != ret)
++ fput(f);
++
++ return ret;
++}
++
++static struct file *kdbus_get_memfd(const struct kdbus_memfd *memfd)
++{
++ const int m = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL;
++ struct file *f, *ret;
++ int s;
++
++ if (memfd->fd < 0)
++ return ERR_PTR(-EBADF);
++
++ f = fget(memfd->fd);
++ if (!f)
++ return ERR_PTR(-EBADF);
++
++ s = shmem_get_seals(f);
++ if (s < 0)
++ ret = ERR_PTR(-EMEDIUMTYPE);
++ else if ((s & m) != m)
++ ret = ERR_PTR(-ETXTBSY);
++ else if (memfd->start + memfd->size > (u64)i_size_read(file_inode(f)))
++ ret = ERR_PTR(-EFAULT);
++ else
++ ret = f;
++
++ if (f != ret)
++ fput(f);
++
++ return ret;
++}
++
++static int kdbus_msg_examine(struct kdbus_msg *msg, struct kdbus_bus *bus,
++ struct kdbus_cmd_send *cmd, size_t *out_n_memfds,
++ size_t *out_n_fds, size_t *out_n_parts)
++{
++ struct kdbus_item *item, *fds = NULL, *bloom = NULL, *dstname = NULL;
++ u64 n_parts, n_memfds, n_fds, vec_size;
++
++ /*
++ * Step 1:
++ * Validate the message and command parameters.
++ */
++
++ /* KDBUS_PAYLOAD_KERNEL is reserved to kernel messages */
++ if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
++ return -EINVAL;
++
++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
++ /* broadcasts must be marked as signals */
++ if (!(msg->flags & KDBUS_MSG_SIGNAL))
++ return -EBADMSG;
++ /* broadcasts cannot have timeouts */
++ if (msg->timeout_ns > 0)
++ return -ENOTUNIQ;
++ }
++
++ if (msg->flags & KDBUS_MSG_EXPECT_REPLY) {
++ /* if you expect a reply, you must specify a timeout */
++ if (msg->timeout_ns == 0)
++ return -EINVAL;
++ /* signals cannot have replies */
++ if (msg->flags & KDBUS_MSG_SIGNAL)
++ return -ENOTUNIQ;
++ } else {
++ /* must expect reply if sent as synchronous call */
++ if (cmd->flags & KDBUS_SEND_SYNC_REPLY)
++ return -EINVAL;
++ /* cannot mark replies as signal */
++ if (msg->cookie_reply && (msg->flags & KDBUS_MSG_SIGNAL))
++ return -EINVAL;
++ }
++
++ /*
++ * Step 2:
++ * Validate all passed items. While at it, select some statistics that
++ * are required to allocate state objects later on.
++ *
++ * Generic item validation has already been done via
++ * kdbus_item_validate(). Furthermore, the number of items is naturally
++ * limited by the maximum message size. Hence, only non-generic item
++ * checks are performed here (mainly integer overflow tests).
++ */
++
++ n_parts = 0;
++ n_memfds = 0;
++ n_fds = 0;
++ vec_size = 0;
++
++ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) {
++ switch (item->type) {
++ case KDBUS_ITEM_PAYLOAD_VEC: {
++ void __force __user *ptr = KDBUS_PTR(item->vec.address);
++ u64 size = item->vec.size;
++
++ if (vec_size + size < vec_size)
++ return -EMSGSIZE;
++ if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
++ return -EMSGSIZE;
++ if (ptr && unlikely(!access_ok(VERIFY_READ, ptr, size)))
++ return -EFAULT;
++
++ if (ptr || size % 8) /* data or padding */
++ ++n_parts;
++ break;
++ }
++ case KDBUS_ITEM_PAYLOAD_MEMFD: {
++ u64 start = item->memfd.start;
++ u64 size = item->memfd.size;
++
++ if (start + size < start)
++ return -EMSGSIZE;
++ if (n_memfds >= KDBUS_MSG_MAX_MEMFD_ITEMS)
++ return -E2BIG;
++
++ ++n_memfds;
++ if (size % 8) /* vec-padding required */
++ ++n_parts;
++ break;
++ }
++ case KDBUS_ITEM_FDS: {
++ if (fds)
++ return -EEXIST;
++
++ fds = item;
++ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int);
++ if (n_fds > KDBUS_CONN_MAX_FDS_PER_USER)
++ return -EMFILE;
++
++ break;
++ }
++ case KDBUS_ITEM_BLOOM_FILTER: {
++ u64 bloom_size;
++
++ if (bloom)
++ return -EEXIST;
++
++ bloom = item;
++ bloom_size = KDBUS_ITEM_PAYLOAD_SIZE(item) -
++ offsetof(struct kdbus_bloom_filter, data);
++ if (!KDBUS_IS_ALIGNED8(bloom_size))
++ return -EFAULT;
++ if (bloom_size != bus->bloom.size)
++ return -EDOM;
++
++ break;
++ }
++ case KDBUS_ITEM_DST_NAME: {
++ if (dstname)
++ return -EEXIST;
++
++ dstname = item;
++ if (!kdbus_name_is_valid(item->str, false))
++ return -EINVAL;
++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST)
++ return -EBADMSG;
++
++ break;
++ }
++ default:
++ return -EINVAL;
++ }
++ }
++
++ /*
++ * Step 3:
++ * Validate that required items were actually passed, and that no item
++ * contradicts the message flags.
++ */
++
++ /* bloom filters must be attached _iff_ it's a signal */
++ if (!(msg->flags & KDBUS_MSG_SIGNAL) != !bloom)
++ return -EBADMSG;
++ /* destination name is required if no ID is given */
++ if (msg->dst_id == KDBUS_DST_ID_NAME && !dstname)
++ return -EDESTADDRREQ;
++ /* cannot send file-descriptors attached to broadcasts */
++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST && fds)
++ return -ENOTUNIQ;
++
++ *out_n_memfds = n_memfds;
++ *out_n_fds = n_fds;
++ *out_n_parts = n_parts;
++
++ return 0;
++}
++
++static bool kdbus_staging_merge_vecs(struct kdbus_staging *staging,
++ struct kdbus_item **prev_item,
++ struct iovec **prev_vec,
++ const struct kdbus_item *merge)
++{
++ void __user *ptr = (void __user *)KDBUS_PTR(merge->vec.address);
++ u64 padding = merge->vec.size % 8;
++ struct kdbus_item *prev = *prev_item;
++ struct iovec *vec = *prev_vec;
++
++ /* XXX: merging is disabled so far */
++ if (0 && prev && prev->type == KDBUS_ITEM_PAYLOAD_OFF &&
++ !merge->vec.address == !prev->vec.address) {
++ /*
++ * If we merge two VECs, we can always drop the second
++ * PAYLOAD_VEC item. Hence, include its size in the previous
++ * one.
++ */
++ prev->vec.size += merge->vec.size;
++
++ if (ptr) {
++ /*
++ * If we merge two data VECs, we need two iovecs to copy
++ * the data. But the items can be easily merged by
++ * summing their lengths.
++ */
++ vec = &staging->parts[staging->n_parts++];
++ vec->iov_len = merge->vec.size;
++ vec->iov_base = ptr;
++ staging->n_payload += vec->iov_len;
++ } else if (padding) {
++ /*
++ * If we merge two 0-vecs with the second 0-vec
++ * requiring padding, we need to insert an iovec to copy
++ * the 0-padding. We try merging it with the previous
++ * 0-padding iovec. This might end up with an
++ * iov_len==0, in which case we simply drop the iovec.
++ */
++ if (vec) {
++ staging->n_payload -= vec->iov_len;
++ vec->iov_len = prev->vec.size % 8;
++ if (!vec->iov_len) {
++ --staging->n_parts;
++ vec = NULL;
++ } else {
++ staging->n_payload += vec->iov_len;
++ }
++ } else {
++ vec = &staging->parts[staging->n_parts++];
++ vec->iov_len = padding;
++ vec->iov_base = (char __user *)zeros;
++ staging->n_payload += vec->iov_len;
++ }
++ } else {
++ /*
++ * If we merge two 0-vecs with the second 0-vec having
++ * no padding, we know the padding of the first stays
++ * the same. Hence, @vec needs no adjustment.
++ */
++ }
++
++ /* successfully merged with previous item */
++ merge = prev;
++ } else {
++ /*
++ * If we cannot merge the payload item with the previous one,
++ * we simply insert a new iovec for the data/padding.
++ */
++ if (ptr) {
++ vec = &staging->parts[staging->n_parts++];
++ vec->iov_len = merge->vec.size;
++ vec->iov_base = ptr;
++ staging->n_payload += vec->iov_len;
++ } else if (padding) {
++ vec = &staging->parts[staging->n_parts++];
++ vec->iov_len = padding;
++ vec->iov_base = (char __user *)zeros;
++ staging->n_payload += vec->iov_len;
++ } else {
++ vec = NULL;
++ }
++ }
++
++ *prev_item = (struct kdbus_item *)merge;
++ *prev_vec = vec;
++
++ return merge == prev;
++}
++
++static int kdbus_staging_import(struct kdbus_staging *staging)
++{
++ struct kdbus_item *it, *item, *last, *prev_payload;
++ struct kdbus_gaps *gaps = staging->gaps;
++ struct kdbus_msg *msg = staging->msg;
++ struct iovec *part, *prev_part;
++ bool drop_item;
++
++ drop_item = false;
++ last = NULL;
++ prev_payload = NULL;
++ prev_part = NULL;
++
++ /*
++ * We modify msg->items along the way; make sure to use @item as offset
++ * to the next item (instead of the iterator @it).
++ */
++ for (it = item = msg->items;
++ it >= msg->items &&
++ (u8 *)it < (u8 *)msg + msg->size &&
++ (u8 *)it + it->size <= (u8 *)msg + msg->size; ) {
++ /*
++ * If we dropped items along the way, move current item to
++ * front. We must not access @it afterwards, but use @item
++ * instead!
++ */
++ if (it != item)
++ memmove(item, it, it->size);
++ it = (void *)((u8 *)it + KDBUS_ALIGN8(item->size));
++
++ switch (item->type) {
++ case KDBUS_ITEM_PAYLOAD_VEC: {
++ size_t offset = staging->n_payload;
++
++ if (kdbus_staging_merge_vecs(staging, &prev_payload,
++ &prev_part, item)) {
++ drop_item = true;
++ } else if (item->vec.address) {
++ /* real offset is patched later on */
++ item->type = KDBUS_ITEM_PAYLOAD_OFF;
++ item->vec.offset = offset;
++ } else {
++ item->type = KDBUS_ITEM_PAYLOAD_OFF;
++ item->vec.offset = ~0ULL;
++ }
++
++ break;
++ }
++ case KDBUS_ITEM_PAYLOAD_MEMFD: {
++ struct file *f;
++
++ f = kdbus_get_memfd(&item->memfd);
++ if (IS_ERR(f))
++ return PTR_ERR(f);
++
++ gaps->memfd_files[gaps->n_memfds] = f;
++ gaps->memfd_offsets[gaps->n_memfds] =
++ (u8 *)&item->memfd.fd - (u8 *)msg;
++ ++gaps->n_memfds;
++
++ /* memfds cannot be merged */
++ prev_payload = item;
++ prev_part = NULL;
++
++ /* insert padding to make following VECs aligned */
++ if (item->memfd.size % 8) {
++ part = &staging->parts[staging->n_parts++];
++ part->iov_len = item->memfd.size % 8;
++ part->iov_base = (char __user *)zeros;
++ staging->n_payload += part->iov_len;
++ }
++
++ break;
++ }
++ case KDBUS_ITEM_FDS: {
++ size_t i, n_fds;
++
++ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int);
++ for (i = 0; i < n_fds; ++i) {
++ struct file *f;
++
++ f = kdbus_get_fd(item->fds[i]);
++ if (IS_ERR(f))
++ return PTR_ERR(f);
++
++ gaps->fd_files[gaps->n_fds++] = f;
++ }
++
++ gaps->fd_offset = (u8 *)item->fds - (u8 *)msg;
++
++ break;
++ }
++ case KDBUS_ITEM_BLOOM_FILTER:
++ staging->bloom_filter = &item->bloom_filter;
++ break;
++ case KDBUS_ITEM_DST_NAME:
++ staging->dst_name = item->str;
++ break;
++ }
++
++ /* drop item if we merged it with a previous one */
++ if (drop_item) {
++ drop_item = false;
++ } else {
++ last = item;
++ item = KDBUS_ITEM_NEXT(item);
++ }
++ }
++
++ /* adjust message size regarding dropped items */
++ msg->size = offsetof(struct kdbus_msg, items);
++ if (last)
++ msg->size += ((u8 *)last - (u8 *)msg->items) + last->size;
++
++ return 0;
++}
++
++static void kdbus_staging_reserve(struct kdbus_staging *staging)
++{
++ struct iovec *part;
++
++ part = &staging->parts[staging->n_parts++];
++ part->iov_base = (void __user *)zeros;
++ part->iov_len = 0;
++}
++
++static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus,
++ size_t n_parts,
++ size_t msg_extra_size)
++{
++ const size_t reserved_parts = 5; /* see below for explanation */
++ struct kdbus_staging *staging;
++ int ret;
++
++ n_parts += reserved_parts;
++
++ staging = kzalloc(sizeof(*staging) + n_parts * sizeof(*staging->parts) +
++ msg_extra_size, GFP_TEMPORARY);
++ if (!staging)
++ return ERR_PTR(-ENOMEM);
++
++ staging->msg_seqnum = atomic64_inc_return(&bus->domain->last_id);
++ staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */
++ staging->parts = (void *)(staging + 1);
++
++ if (msg_extra_size) /* if requested, allocate message, too */
++ staging->msg = (void *)((u8 *)staging->parts +
++ n_parts * sizeof(*staging->parts));
++
++ staging->meta_proc = kdbus_meta_proc_new();
++ if (IS_ERR(staging->meta_proc)) {
++ ret = PTR_ERR(staging->meta_proc);
++ staging->meta_proc = NULL;
++ goto error;
++ }
++
++ staging->meta_conn = kdbus_meta_conn_new();
++ if (IS_ERR(staging->meta_conn)) {
++ ret = PTR_ERR(staging->meta_conn);
++ staging->meta_conn = NULL;
++ goto error;
++ }
++
++ /*
++ * Prepare iovecs to copy the message into the target pool. We use the
++ * following iovecs:
++ * * iovec to copy "kdbus_msg.size"
++ * * iovec to copy "struct kdbus_msg" (minus size) plus items
++ * * iovec for possible padding after the items
++ * * iovec for metadata items
++ * * iovec for possible padding after the items
++ *
++ * Make sure to update @reserved_parts if you add more parts here.
++ */
++
++ kdbus_staging_reserve(staging); /* msg.size */
++ kdbus_staging_reserve(staging); /* msg (minus msg.size) plus items */
++ kdbus_staging_reserve(staging); /* msg padding */
++ kdbus_staging_reserve(staging); /* meta */
++ kdbus_staging_reserve(staging); /* meta padding */
++
++ return staging;
++
++error:
++ kdbus_staging_free(staging);
++ return ERR_PTR(ret);
++}
++
++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus,
++ u64 dst, u64 cookie_timeout,
++ size_t it_size, size_t it_type)
++{
++ struct kdbus_staging *staging;
++ size_t size;
++
++ size = offsetof(struct kdbus_msg, items) +
++ KDBUS_ITEM_HEADER_SIZE + it_size;
++
++ staging = kdbus_staging_new(bus, 0, KDBUS_ALIGN8(size));
++ if (IS_ERR(staging))
++ return ERR_CAST(staging);
++
++ staging->msg->size = size;
++ staging->msg->flags = (dst == KDBUS_DST_ID_BROADCAST) ?
++ KDBUS_MSG_SIGNAL : 0;
++ staging->msg->dst_id = dst;
++ staging->msg->src_id = KDBUS_SRC_ID_KERNEL;
++ staging->msg->payload_type = KDBUS_PAYLOAD_KERNEL;
++ staging->msg->cookie_reply = cookie_timeout;
++ staging->notify = staging->msg->items;
++ staging->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size;
++ staging->notify->type = it_type;
++
++ return staging;
++}
++
++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus,
++ struct kdbus_cmd_send *cmd,
++ struct kdbus_msg *msg)
++{
++ const size_t reserved_parts = 1; /* see below for explanation */
++ size_t n_memfds, n_fds, n_parts;
++ struct kdbus_staging *staging;
++ int ret;
++
++ /*
++ * Examine user-supplied message and figure out how many resources we
++ * need to allocate in our staging area. This requires us to iterate
++ * the message twice, but saves us from re-allocating our resources
++ * all the time.
++ */
++
++ ret = kdbus_msg_examine(msg, bus, cmd, &n_memfds, &n_fds, &n_parts);
++ if (ret < 0)
++ return ERR_PTR(ret);
++
++ n_parts += reserved_parts;
++
++ /*
++ * Allocate staging area with the number of required resources. Make
++ * sure that we have enough iovecs for all required parts pre-allocated
++ * so this will hopefully be the only memory allocation for this
++ * message transaction.
++ */
++
++ staging = kdbus_staging_new(bus, n_parts, 0);
++ if (IS_ERR(staging))
++ return ERR_CAST(staging);
++
++ staging->msg = msg;
++
++ /*
++ * If the message contains memfds or fd items, we need to remember some
++ * state so we can fill in the requested information at RECV time.
++ * File-descriptors cannot be passed at SEND time. Hence, allocate a
++ * gaps-object to remember that state. That gaps object is linked to
++ * from the staging area, but will also be linked to from the message
++ * queue of each peer. Hence, each receiver owns a reference to it, and
++ * it will later be used to fill the 'gaps' in message that couldn't be
++ * filled at SEND time.
++ * Note that the 'gaps' object is read-only once the staging-allocator
++ * returns. There might be connections receiving a queued message while
++ * the sender still broadcasts the message to other receivers.
++ */
++
++ if (n_memfds > 0 || n_fds > 0) {
++ staging->gaps = kdbus_gaps_new(n_memfds, n_fds);
++ if (IS_ERR(staging->gaps)) {
++ ret = PTR_ERR(staging->gaps);
++ staging->gaps = NULL;
++ kdbus_staging_free(staging);
++ return ERR_PTR(ret);
++ }
++ }
++
++ /*
++ * kdbus_staging_new() already reserves parts for message setup. For
++ * user-supplied messages, we add the following iovecs:
++ * ... variable number of iovecs for payload ...
++ * * final iovec for possible padding of payload
++ *
++ * Make sure to update @reserved_parts if you add more parts here.
++ */
++
++ ret = kdbus_staging_import(staging); /* payload */
++ kdbus_staging_reserve(staging); /* payload padding */
++
++ if (ret < 0)
++ goto error;
++
++ return staging;
++
++error:
++ kdbus_staging_free(staging);
++ return ERR_PTR(ret);
++}
++
++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging)
++{
++ if (!staging)
++ return NULL;
++
++ kdbus_meta_conn_unref(staging->meta_conn);
++ kdbus_meta_proc_unref(staging->meta_proc);
++ kdbus_gaps_unref(staging->gaps);
++ kfree(staging);
++
++ return NULL;
++}
++
++static int kdbus_staging_collect_metadata(struct kdbus_staging *staging,
++ struct kdbus_conn *src,
++ struct kdbus_conn *dst,
++ u64 *out_attach)
++{
++ u64 attach;
++ int ret;
++
++ if (src)
++ attach = kdbus_meta_calc_attach_flags(src, dst);
++ else
++ attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */
++
++ if (src && !src->meta_fake) {
++ ret = kdbus_meta_proc_collect(staging->meta_proc, attach);
++ if (ret < 0)
++ return ret;
++ }
++
++ ret = kdbus_meta_conn_collect(staging->meta_conn, src,
++ staging->msg_seqnum, attach);
++ if (ret < 0)
++ return ret;
++
++ *out_attach = attach;
++ return 0;
++}
++
++/**
++ * kdbus_staging_emit() - emit linearized message in target pool
++ * @staging: staging object to create message from
++ * @src: sender of the message (or NULL)
++ * @dst: target connection to allocate message for
++ *
++ * This allocates a pool-slice for @dst and copies the message provided by
++ * @staging into it. The new slice is then returned to the caller for further
++ * processing. It's not linked into any queue, yet.
++ *
++ * Return: Newly allocated slice or ERR_PTR on failure.
++ */
++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging,
++ struct kdbus_conn *src,
++ struct kdbus_conn *dst)
++{
++ struct kdbus_item *item, *meta_items = NULL;
++ struct kdbus_pool_slice *slice = NULL;
++ size_t off, size, msg_size, meta_size;
++ struct iovec *v;
++ u64 attach;
++ int ret;
++
++ /*
++ * Step 1:
++ * Collect metadata from @src depending on the attach-flags allowed for
++ * @dst. Translate it into the namespaces pinned by @dst.
++ */
++
++ ret = kdbus_staging_collect_metadata(staging, src, dst, &attach);
++ if (ret < 0)
++ goto error;
++
++ ret = kdbus_meta_emit(staging->meta_proc, NULL, staging->meta_conn,
++ dst, attach, &meta_items, &meta_size);
++ if (ret < 0)
++ goto error;
++
++ /*
++ * Step 2:
++ * Setup iovecs for the message. See kdbus_staging_new() for allocation
++ * of those iovecs. All reserved iovecs have been initialized with
++ * iov_len=0 + iov_base=zeros. Furthermore, the iovecs to copy the
++ * actual message payload have already been initialized and need not be
++ * touched.
++ */
++
++ v = staging->parts;
++ msg_size = staging->msg->size;
++
++ /* msg.size */
++ v->iov_len = sizeof(msg_size);
++ v->iov_base = &msg_size;
++ ++v;
++
++ /* msg (after msg.size) plus items */
++ v->iov_len = staging->msg->size - sizeof(staging->msg->size);
++ v->iov_base = (void __user *)((u8 *)staging->msg +
++ sizeof(staging->msg->size));
++ ++v;
++
++ /* padding after msg */
++ v->iov_len = KDBUS_ALIGN8(staging->msg->size) - staging->msg->size;
++ v->iov_base = (void __user *)zeros;
++ ++v;
++
++ if (meta_size > 0) {
++ /* metadata items */
++ v->iov_len = meta_size;
++ v->iov_base = meta_items;
++ ++v;
++
++ /* padding after metadata */
++ v->iov_len = KDBUS_ALIGN8(meta_size) - meta_size;
++ v->iov_base = (void __user *)zeros;
++ ++v;
++
++ msg_size = KDBUS_ALIGN8(msg_size) + meta_size;
++ }
++
++ /* ... payload iovecs are already filled in ... */
++
++ /* compute overall size and fill in padding after payload */
++ size = KDBUS_ALIGN8(msg_size);
++
++ if (staging->n_payload > 0) {
++ size += staging->n_payload;
++
++ v = &staging->parts[staging->n_parts - 1];
++ v->iov_len = KDBUS_ALIGN8(size) - size;
++ v->iov_base = (void __user *)zeros;
++
++ size = KDBUS_ALIGN8(size);
++ }
++
++ /*
++ * Step 3:
++ * The PAYLOAD_OFF items in the message contain a relative 'offset'
++ * field that tells the receiver where to find the actual payload. This
++ * offset is relative to the start of the message, and as such depends
++ * on the size of the metadata items we inserted. This size is variable
++ * and changes for each peer we send the message to. Hence, we remember
++ * the last relative offset that was used to calculate the 'offset'
++ * fields. For each message, we re-calculate it and patch all items, in
++ * case it changed.
++ */
++
++ off = KDBUS_ALIGN8(msg_size);
++
++ if (off != staging->i_payload) {
++ KDBUS_ITEMS_FOREACH(item, staging->msg->items,
++ KDBUS_ITEMS_SIZE(staging->msg, items)) {
++ if (item->type != KDBUS_ITEM_PAYLOAD_OFF)
++ continue;
++
++ item->vec.offset -= staging->i_payload;
++ item->vec.offset += off;
++ }
++
++ staging->i_payload = off;
++ }
++
++ /*
++ * Step 4:
++ * Allocate pool slice and copy over all data. Make sure to properly
++ * account on user quota.
++ */
++
++ ret = kdbus_conn_quota_inc(dst, src ? src->user : NULL, size,
++ staging->gaps ? staging->gaps->n_fds : 0);
++ if (ret < 0)
++ goto error;
++
++ slice = kdbus_pool_slice_alloc(dst->pool, size, true);
++ if (IS_ERR(slice)) {
++ ret = PTR_ERR(slice);
++ slice = NULL;
++ goto error;
++ }
++
++ WARN_ON(kdbus_pool_slice_size(slice) != size);
++
++ ret = kdbus_pool_slice_copy_iovec(slice, 0, staging->parts,
++ staging->n_parts, size);
++ if (ret < 0)
++ goto error;
++
++ /* all done, return slice to caller */
++ goto exit;
++
++error:
++ if (slice)
++ kdbus_conn_quota_dec(dst, src ? src->user : NULL, size,
++ staging->gaps ? staging->gaps->n_fds : 0);
++ kdbus_pool_slice_release(slice);
++ slice = ERR_PTR(ret);
++exit:
++ kfree(meta_items);
++ return slice;
++}
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index 5755ad4c9fd9..8fe49a961834 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -124,4 +124,97 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg);
+ int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
+ struct kdbus_conn *src, struct kdbus_conn *dst);
+
++/**
++ * struct kdbus_gaps - gaps in message to be filled later
++ * @kref: Reference counter
++ * @n_memfd_offs: Number of memfds
++ * @memfd_offs: Offsets of kdbus_memfd items in target slice
++ * @n_fds: Number of fds
++ * @fds: Array of sent fds
++ * @fds_offset: Offset of fd-array in target slice
++ *
++ * The 'gaps' object is used to track data that is needed to fill gaps in a
++ * message at RECV time. Usually, we try to compile the whole message at SEND
++ * time. This has the advantage, that we don't have to cache any information and
++ * can keep the memory consumption small. Furthermore, all copy operations can
++ * be combined into a single function call, which speeds up transactions
++ * considerably.
++ * However, things like file-descriptors can only be fully installed at RECV
++ * time. The gaps object tracks this data and pins it until a message is
++ * received. The gaps object is shared between all receivers of the same
++ * message.
++ */
++struct kdbus_gaps {
++ struct kref kref;
++
++ /* state tracking for KDBUS_ITEM_PAYLOAD_MEMFD entries */
++ size_t n_memfds;
++ u64 *memfd_offsets;
++ struct file **memfd_files;
++
++ /* state tracking for KDBUS_ITEM_FDS */
++ size_t n_fds;
++ struct file **fd_files;
++ u64 fd_offset;
++};
++
++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps);
++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps);
++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice,
++ bool *out_incomplete);
++
++/**
++ * struct kdbus_staging - staging area to import messages
++ * @msg: User-supplied message
++ * @gaps: Gaps-object created during import (or NULL if empty)
++ * @msg_seqnum: Message sequence number
++ * @notify_entry: Entry into list of kernel-generated notifications
++ * @i_payload: Current relative index of start of payload
++ * @n_payload: Total number of bytes needed for payload
++ * @n_parts: Number of parts
++ * @parts: Array of iovecs that make up the whole message
++ * @meta_proc: Process metadata of the sender (or NULL if empty)
++ * @meta_conn: Connection metadata of the sender (or NULL if empty)
++ * @bloom_filter: Pointer to the bloom-item in @msg, or NULL
++ * @dst_name: Pointer to the dst-name-item in @msg, or NULL
++ * @notify: Pointer to the notification item in @msg, or NULL
++ *
++ * The kdbus_staging object is a temporary staging area to import user-supplied
++ * messages into the kernel. It is only used during SEND and dropped once the
++ * message is queued. Any data that cannot be collected during SEND, is
++ * collected in a kdbus_gaps object and attached to the message queue.
++ */
++struct kdbus_staging {
++ struct kdbus_msg *msg;
++ struct kdbus_gaps *gaps;
++ u64 msg_seqnum;
++ struct list_head notify_entry;
++
++ /* crafted iovecs to copy the message */
++ size_t i_payload;
++ size_t n_payload;
++ size_t n_parts;
++ struct iovec *parts;
++
++ /* metadata state */
++ struct kdbus_meta_proc *meta_proc;
++ struct kdbus_meta_conn *meta_conn;
++
++ /* cached pointers into @msg */
++ const struct kdbus_bloom_filter *bloom_filter;
++ const char *dst_name;
++ struct kdbus_item *notify;
++};
++
++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus,
++ u64 dst, u64 cookie_timeout,
++ size_t it_size, size_t it_type);
++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus,
++ struct kdbus_cmd_send *cmd,
++ struct kdbus_msg *msg);
++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging);
++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging,
++ struct kdbus_conn *src,
++ struct kdbus_conn *dst);
++
+ #endif
+--
+2.4.3
+
+
+From 5eb3ea76d55f52ff6f5abdb88f925e2a695c2732 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Sat, 20 Jun 2015 00:53:58 +0200
+Subject: [PATCH 24/34] kdbus: remove unused code
+
+kdbus_item_get() and kdbus_item_get_str() are not used anywhere. Drop
+them. They probably got obsoleted during the introduction of kdbus_args.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/item.c | 41 -----------------------------------------
+ ipc/kdbus/item.h | 3 ---
+ 2 files changed, 44 deletions(-)
+
+diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c
+index 1ee72c2ad7c3..e763083cc16c 100644
+--- a/ipc/kdbus/item.c
++++ b/ipc/kdbus/item.c
+@@ -260,47 +260,6 @@ int kdbus_items_validate(const struct kdbus_item *items, size_t items_size)
+ return 0;
+ }
+
+-static struct kdbus_item *kdbus_items_get(const struct kdbus_item *items,
+- size_t items_size,
+- unsigned int item_type)
+-{
+- const struct kdbus_item *iter, *found = NULL;
+-
+- KDBUS_ITEMS_FOREACH(iter, items, items_size) {
+- if (iter->type == item_type) {
+- if (found)
+- return ERR_PTR(-EEXIST);
+- found = iter;
+- }
+- }
+-
+- return (struct kdbus_item *)found ? : ERR_PTR(-EBADMSG);
+-}
+-
+-/**
+- * kdbus_items_get_str() - get string from a list of items
+- * @items: The items to walk
+- * @items_size: The size of all items
+- * @item_type: The item type to look for
+- *
+- * This function walks a list of items and searches for items of type
+- * @item_type. If it finds exactly one such item, @str_ret will be set to
+- * the .str member of the item.
+- *
+- * Return: the string, if the item was found exactly once, ERR_PTR(-EEXIST)
+- * if the item was found more than once, and ERR_PTR(-EBADMSG) if there was
+- * no item of the given type.
+- */
+-const char *kdbus_items_get_str(const struct kdbus_item *items,
+- size_t items_size,
+- unsigned int item_type)
+-{
+- const struct kdbus_item *item;
+-
+- item = kdbus_items_get(items, items_size, item_type);
+- return IS_ERR(item) ? ERR_CAST(item) : item->str;
+-}
+-
+ /**
+ * kdbus_item_set() - Set item content
+ * @item: The item to modify
+diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h
+index bca63b4e6e80..3a7e6ccc253c 100644
+--- a/ipc/kdbus/item.h
++++ b/ipc/kdbus/item.h
+@@ -55,9 +55,6 @@ struct kdbus_item_header {
+ int kdbus_item_validate_name(const struct kdbus_item *item);
+ int kdbus_item_validate(const struct kdbus_item *item);
+ int kdbus_items_validate(const struct kdbus_item *items, size_t items_size);
+-const char *kdbus_items_get_str(const struct kdbus_item *items,
+- size_t items_size,
+- unsigned int item_type);
+ struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type,
+ const void *data, size_t len);
+
+--
+2.4.3
+
+
+From 992775c9c377ca14c6dcd2890283602a3fb36213 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Sat, 20 Jun 2015 11:37:58 +0200
+Subject: [PATCH 25/34] kdbus: import messages via kdbus_args
+
+The kdbus_args helpers take care of copying command payloads into
+kernel-space, verifying item validity and implementing negotiation. So
+far, we use it for all user-space interaction but messages. This patch
+adds support for kdbus-messages via kdbus_args so all user-space
+interaction will now use kdbus_args.
+
+This has the benefit that we now support negotiation for messages,
+stack-placement in case the messages are small enough, and unify the item
+handling across all callers.
+
+This patch does *not* remove the old message importer. Instead, follow-up
+patches will slowly perform the transition to the new one. It will be
+removed once the transition is done.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++---
+ ipc/kdbus/handle.c | 15 +++++++++----
+ ipc/kdbus/handle.h | 17 ++++++++++++--
+ 3 files changed, 84 insertions(+), 9 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 29b99c023bfe..20bb083aa2b4 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -1929,10 +1929,13 @@ exit:
+ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ {
+ struct kdbus_cmd_send *cmd;
++ struct kdbus_staging *staging = NULL;
+ struct kdbus_kmsg *kmsg = NULL;
++ struct kdbus_msg *msg = NULL;
+ struct file *cancel_fd = NULL;
+- int ret;
++ int ret, ret2;
+
++ /* command arguments */
+ struct kdbus_arg argv[] = {
+ { .type = KDBUS_ITEM_NEGOTIATE },
+ { .type = KDBUS_ITEM_CANCEL_FD },
+@@ -1944,12 +1947,48 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ .argc = ARRAY_SIZE(argv),
+ };
+
++ /* message arguments */
++ struct kdbus_arg msg_argv[] = {
++ { .type = KDBUS_ITEM_NEGOTIATE },
++ { .type = KDBUS_ITEM_PAYLOAD_VEC, .multiple = true },
++ { .type = KDBUS_ITEM_PAYLOAD_MEMFD, .multiple = true },
++ { .type = KDBUS_ITEM_FDS },
++ { .type = KDBUS_ITEM_BLOOM_FILTER },
++ { .type = KDBUS_ITEM_DST_NAME },
++ };
++ struct kdbus_args msg_args = {
++ .allowed_flags = KDBUS_FLAG_NEGOTIATE |
++ KDBUS_MSG_EXPECT_REPLY |
++ KDBUS_MSG_NO_AUTO_START |
++ KDBUS_MSG_SIGNAL,
++ .argv = msg_argv,
++ .argc = ARRAY_SIZE(msg_argv),
++ };
++
+ if (!kdbus_conn_is_ordinary(conn))
+ return -EOPNOTSUPP;
+
++ /* make sure to parse both, @cmd and @msg on negotiation */
++
+ ret = kdbus_args_parse(&args, argp, &cmd);
+- if (ret != 0)
+- return ret;
++ if (ret < 0)
++ goto exit;
++ else if (ret > 0 && !cmd->msg_address) /* negotiation without msg */
++ goto exit;
++
++ ret2 = kdbus_args_parse_msg(&msg_args, KDBUS_PTR(cmd->msg_address),
++ &msg);
++ if (ret2 < 0) { /* cannot parse message */
++ ret = ret2;
++ goto exit;
++ } else if (ret2 > 0 && !ret) { /* msg-negot implies cmd-negot */
++ ret = -EINVAL;
++ goto exit;
++ } else if (ret > 0) { /* negotiation */
++ goto exit;
++ }
++
++ /* here we parsed both, @cmd and @msg, and neither wants negotiation */
+
+ cmd->reply.return_flags = 0;
+ kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset,
+@@ -1968,6 +2007,20 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ }
+ }
+
++ /* patch-in the source of this message */
++ if (msg->src_id > 0 && msg->src_id != conn->id) {
++ ret = -EINVAL;
++ goto exit;
++ }
++ msg->src_id = conn->id;
++
++ staging = kdbus_staging_new_user(conn->ep->bus, cmd, msg);
++ if (IS_ERR(staging)) {
++ ret = PTR_ERR(staging);
++ staging = NULL;
++ goto exit;
++ }
++
+ kmsg = kdbus_kmsg_new_from_cmd(conn, cmd);
+ if (IS_ERR(kmsg)) {
+ ret = PTR_ERR(kmsg);
+@@ -2012,6 +2065,8 @@ exit:
+ if (cancel_fd)
+ fput(cancel_fd);
+ kdbus_kmsg_free(kmsg);
++ kdbus_staging_free(staging);
++ ret = kdbus_args_clear(&msg_args, ret);
+ return kdbus_args_clear(&args, ret);
+ }
+
+diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c
+index 07527990a051..e0e06b0e1114 100644
+--- a/ipc/kdbus/handle.c
++++ b/ipc/kdbus/handle.c
+@@ -126,6 +126,7 @@ static int kdbus_args_negotiate(struct kdbus_args *args)
+ /**
+ * __kdbus_args_parse() - parse payload of kdbus command
+ * @args: object to parse data into
++ * @is_cmd: whether this is a command or msg payload
+ * @argp: user-space location of command payload to parse
+ * @type_size: overall size of command payload to parse
+ * @items_offset: offset of items array in command payload
+@@ -140,10 +141,14 @@ static int kdbus_args_negotiate(struct kdbus_args *args)
+ * If this function succeeded, you must call kdbus_args_clear() to release
+ * allocated resources before destroying @args.
+ *
++ * This can also be used to import kdbus_msg objects. In that case, @is_cmd must
++ * be set to 'false' and the 'return_flags' field will not be touched (as it
++ * doesn't exist on kdbus_msg).
++ *
+ * Return: On failure a negative error code is returned. Otherwise, 1 is
+ * returned if negotiation was requested, 0 if not.
+ */
+-int __kdbus_args_parse(struct kdbus_args *args, void __user *argp,
++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp,
+ size_t type_size, size_t items_offset, void **out)
+ {
+ u64 user_size;
+@@ -173,10 +178,12 @@ int __kdbus_args_parse(struct kdbus_args *args, void __user *argp,
+ goto error;
+ }
+
+- args->cmd->return_flags = 0;
++ if (is_cmd)
++ args->cmd->return_flags = 0;
+ args->user = argp;
+ args->items = (void *)((u8 *)args->cmd + items_offset);
+ args->items_size = args->cmd->size - items_offset;
++ args->is_cmd = is_cmd;
+
+ if (args->cmd->flags & ~args->allowed_flags) {
+ ret = -EINVAL;
+@@ -225,8 +232,8 @@ int kdbus_args_clear(struct kdbus_args *args, int ret)
+ return ret;
+
+ if (!IS_ERR_OR_NULL(args->cmd)) {
+- if (put_user(args->cmd->return_flags,
+- &args->user->return_flags))
++ if (args->is_cmd && put_user(args->cmd->return_flags,
++ &args->user->return_flags))
+ ret = -EFAULT;
+ if (args->cmd != (void*)args->cmd_buf)
+ kfree(args->cmd);
+diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h
+index 13c59d975728..8a36c0595091 100644
+--- a/ipc/kdbus/handle.h
++++ b/ipc/kdbus/handle.h
+@@ -48,6 +48,7 @@ struct kdbus_arg {
+ * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds
+ * @items: points to item array in @cmd
+ * @items_size: size of @items in bytes
++ * @is_cmd: whether this is a command-payload or msg-payload
+ *
+ * This structure is used to parse ioctl command payloads on each invocation.
+ * The ioctl handler has to pre-fill the flags and allowed items before passing
+@@ -68,9 +69,10 @@ struct kdbus_args {
+
+ struct kdbus_item *items;
+ size_t items_size;
++ bool is_cmd : 1;
+ };
+
+-int __kdbus_args_parse(struct kdbus_args *args, void __user *argp,
++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp,
+ size_t type_size, size_t items_offset, void **out);
+ int kdbus_args_clear(struct kdbus_args *args, int ret);
+
+@@ -82,7 +84,18 @@ int kdbus_args_clear(struct kdbus_args *args, int ret);
+ offsetof(struct kdbus_cmd, flags)); \
+ BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) != \
+ offsetof(struct kdbus_cmd, return_flags)); \
+- __kdbus_args_parse((_args), (_argp), sizeof(**(_v)), \
++ __kdbus_args_parse((_args), 1, (_argp), sizeof(**(_v)), \
++ offsetof(typeof(**(_v)), items), \
++ (void **)(_v)); \
++ })
++
++#define kdbus_args_parse_msg(_args, _argp, _v) \
++ ({ \
++ BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \
++ offsetof(struct kdbus_cmd, size)); \
++ BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \
++ offsetof(struct kdbus_cmd, flags)); \
++ __kdbus_args_parse((_args), 0, (_argp), sizeof(**(_v)), \
+ offsetof(typeof(**(_v)), items), \
+ (void **)(_v)); \
+ })
+--
+2.4.3
+
+
+From c7bd78731b3a709a6d7d83f4851e30dc1ebf5cca Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Wed, 24 Jun 2015 15:27:03 +0200
+Subject: [PATCH 26/34] kdbus: switch to kdbus_staging
+
+This switches the existing infrastructure to use "kdbus_staging" in favor
+of "kdbus_kmsg" and "kdbus_msg_resources". As described during the
+introduction of kdbus_staging, it reduces the number of calls into shmem
+during each message, and also minimizes the resources we pin until
+RECV-time.
+
+This patch improves the pure message transaction speed by ~30% for empty
+payloads.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 30 ++--
+ ipc/kdbus/bus.h | 6 +-
+ ipc/kdbus/connection.c | 134 ++++++++----------
+ ipc/kdbus/connection.h | 4 +-
+ ipc/kdbus/match.c | 26 ++--
+ ipc/kdbus/match.h | 8 +-
+ ipc/kdbus/message.h | 6 +
+ ipc/kdbus/notify.c | 77 +++++------
+ ipc/kdbus/queue.c | 362 +++----------------------------------------------
+ ipc/kdbus/queue.h | 42 +++---
+ 10 files changed, 176 insertions(+), 519 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index 4f51723f8780..e7e17a7f7edd 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -232,9 +232,9 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id)
+ * kdbus_bus_broadcast() - send a message to all subscribed connections
+ * @bus: The bus the connections are connected to
+ * @conn_src: The source connection, may be %NULL for kernel notifications
+- * @kmsg: The message to send.
++ * @staging: Staging object containing the message to send
+ *
+- * Send @kmsg to all connections that are currently active on the bus.
++ * Send message to all connections that are currently active on the bus.
+ * Connections must still have matches installed in order to let the message
+ * pass.
+ *
+@@ -242,7 +242,7 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id)
+ */
+ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg)
++ struct kdbus_staging *staging)
+ {
+ struct kdbus_conn *conn_dst;
+ unsigned int i;
+@@ -259,11 +259,11 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * can re-construct order via sequence numbers), but we should at least
+ * try to avoid re-ordering for monitors.
+ */
+- kdbus_bus_eavesdrop(bus, conn_src, kmsg);
++ kdbus_bus_eavesdrop(bus, conn_src, staging);
+
+ down_read(&bus->conn_rwlock);
+ hash_for_each(bus->conn_hash, i, conn_dst, hentry) {
+- if (conn_dst->id == kmsg->msg.src_id)
++ if (conn_dst->id == staging->msg->src_id)
+ continue;
+ if (!kdbus_conn_is_ordinary(conn_dst))
+ continue;
+@@ -272,8 +272,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * Check if there is a match for the kmsg object in
+ * the destination connection match db
+ */
+- if (!kdbus_match_db_match_kmsg(conn_dst->match_db, conn_src,
+- kmsg))
++ if (!kdbus_match_db_match_msg(conn_dst->match_db, conn_src,
++ staging))
+ continue;
+
+ if (conn_src) {
+@@ -291,12 +291,12 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * notification
+ */
+ if (!kdbus_conn_policy_see_notification(conn_dst, NULL,
+- &kmsg->msg))
++ staging->msg))
+ continue;
+ }
+
+- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL,
+- NULL);
++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging,
++ NULL, NULL);
+ if (ret < 0)
+ kdbus_conn_lost_message(conn_dst);
+ }
+@@ -307,16 +307,16 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ * kdbus_bus_eavesdrop() - send a message to all subscribed monitors
+ * @bus: The bus the monitors are connected to
+ * @conn_src: The source connection, may be %NULL for kernel notifications
+- * @kmsg: The message to send.
++ * @staging: Staging object containing the message to send
+ *
+- * Send @kmsg to all monitors that are currently active on the bus. Monitors
++ * Send message to all monitors that are currently active on the bus. Monitors
+ * must still have matches installed in order to let the message pass.
+ *
+ * The caller must hold the name-registry lock of @bus.
+ */
+ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
+ struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg)
++ struct kdbus_staging *staging)
+ {
+ struct kdbus_conn *conn_dst;
+ int ret;
+@@ -330,8 +330,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
+
+ down_read(&bus->conn_rwlock);
+ list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) {
+- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL,
+- NULL);
++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging,
++ NULL, NULL);
+ if (ret < 0)
+ kdbus_conn_lost_message(conn_dst);
+ }
+diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h
+index e019ef34534c..238986eff92f 100644
+--- a/ipc/kdbus/bus.h
++++ b/ipc/kdbus/bus.h
+@@ -29,7 +29,7 @@
+
+ struct kdbus_conn;
+ struct kdbus_domain;
+-struct kdbus_kmsg;
++struct kdbus_staging;
+ struct kdbus_user;
+
+ /**
+@@ -87,10 +87,10 @@ struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus);
+ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id);
+ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+ struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg);
++ struct kdbus_staging *staging);
+ void kdbus_bus_eavesdrop(struct kdbus_bus *bus,
+ struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg);
++ struct kdbus_staging *staging);
+
+ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain,
+ void __user *argp);
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 20bb083aa2b4..2b334b04dd9d 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -781,7 +781,7 @@ void kdbus_conn_lost_message(struct kdbus_conn *c)
+ static struct kdbus_queue_entry *
+ kdbus_conn_entry_make(struct kdbus_conn *conn_src,
+ struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg)
++ struct kdbus_staging *staging)
+ {
+ /* The remote connection was disconnected */
+ if (!kdbus_conn_active(conn_dst))
+@@ -796,10 +796,10 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src,
+ */
+ if (!kdbus_conn_is_monitor(conn_dst) &&
+ !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) &&
+- kmsg->res && kmsg->res->fds_count > 0)
++ staging->gaps && staging->gaps->n_fds > 0)
+ return ERR_PTR(-ECOMM);
+
+- return kdbus_queue_entry_new(conn_src, conn_dst, kmsg);
++ return kdbus_queue_entry_new(conn_src, conn_dst, staging);
+ }
+
+ /*
+@@ -808,17 +808,11 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src,
+ * The connection's queue will never get to see it.
+ */
+ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
++ struct kdbus_staging *staging,
+ struct kdbus_reply *reply_wake)
+ {
+ struct kdbus_queue_entry *entry;
+- int remote_ret;
+- int ret;
+-
+- ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src,
+- conn_dst);
+- if (ret < 0)
+- return ret;
++ int remote_ret, ret = 0;
+
+ mutex_lock(&reply_wake->reply_dst->lock);
+
+@@ -828,7 +822,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ */
+ if (reply_wake->waiting) {
+ entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst,
+- kmsg);
++ staging);
+ if (IS_ERR(entry))
+ ret = PTR_ERR(entry);
+ else
+@@ -869,7 +863,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ * kdbus_conn_entry_insert() - enqueue a message into the receiver's pool
+ * @conn_src: The sending connection
+ * @conn_dst: The connection to queue into
+- * @kmsg: The kmsg to queue
++ * @staging: Message to send
+ * @reply: The reply tracker to attach to the queue entry
+ * @name: Destination name this msg is sent to, or NULL
+ *
+@@ -877,22 +871,16 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst,
+ */
+ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
++ struct kdbus_staging *staging,
+ struct kdbus_reply *reply,
+ const struct kdbus_name_entry *name)
+ {
+ struct kdbus_queue_entry *entry;
+ int ret;
+
+- if (conn_src) {
+- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst);
+- if (ret < 0)
+- return ret;
+- }
+-
+ kdbus_conn_lock2(conn_src, conn_dst);
+
+- entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg);
++ entry = kdbus_conn_entry_make(conn_src, conn_dst, staging);
+ if (IS_ERR(entry)) {
+ ret = PTR_ERR(entry);
+ goto exit_unlock;
+@@ -1044,22 +1032,18 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src,
+ }
+
+ static int kdbus_pin_dst(struct kdbus_bus *bus,
+- const struct kdbus_kmsg *kmsg,
++ struct kdbus_staging *staging,
+ struct kdbus_name_entry **out_name,
+ struct kdbus_conn **out_dst)
+ {
+- struct kdbus_msg_resources *res = kmsg->res;
+- const struct kdbus_msg *msg = &kmsg->msg;
++ const struct kdbus_msg *msg = staging->msg;
+ struct kdbus_name_entry *name = NULL;
+ struct kdbus_conn *dst = NULL;
+ int ret;
+
+- if (WARN_ON(!res))
+- return -EINVAL;
+-
+ lockdep_assert_held(&bus->name_registry->rwlock);
+
+- if (!res->dst_name) {
++ if (!staging->dst_name) {
+ dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id);
+ if (!dst)
+ return -ENXIO;
+@@ -1070,7 +1054,7 @@ static int kdbus_pin_dst(struct kdbus_bus *bus,
+ }
+ } else {
+ name = kdbus_name_lookup_unlocked(bus->name_registry,
+- res->dst_name);
++ staging->dst_name);
+ if (!name)
+ return -ESRCH;
+
+@@ -1107,17 +1091,19 @@ error:
+ return ret;
+ }
+
+-static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
++static int kdbus_conn_reply(struct kdbus_conn *src,
++ struct kdbus_staging *staging)
+ {
++ const struct kdbus_msg *msg = staging->msg;
+ struct kdbus_name_entry *name = NULL;
+ struct kdbus_reply *reply, *wake = NULL;
+ struct kdbus_conn *dst = NULL;
+ struct kdbus_bus *bus = src->ep->bus;
+ int ret;
+
+- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) ||
+- WARN_ON(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) ||
+- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL))
++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++ WARN_ON(msg->flags & KDBUS_MSG_EXPECT_REPLY) ||
++ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL))
+ return -EINVAL;
+
+ /* name-registry must be locked for lookup *and* collecting data */
+@@ -1125,12 +1111,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+
+ /* find and pin destination */
+
+- ret = kdbus_pin_dst(bus, kmsg, &name, &dst);
++ ret = kdbus_pin_dst(bus, staging, &name, &dst);
+ if (ret < 0)
+ goto exit;
+
+ mutex_lock(&dst->lock);
+- reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply);
++ reply = kdbus_reply_find(src, dst, msg->cookie_reply);
+ if (reply) {
+ if (reply->sync)
+ wake = kdbus_reply_ref(reply);
+@@ -1145,12 +1131,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+
+ /* send message */
+
+- kdbus_bus_eavesdrop(bus, src, kmsg);
++ kdbus_bus_eavesdrop(bus, src, staging);
+
+ if (wake)
+- ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake);
++ ret = kdbus_conn_entry_sync_attach(dst, staging, wake);
+ else
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name);
++ ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name);
+
+ exit:
+ up_read(&bus->name_registry->rwlock);
+@@ -1160,24 +1146,25 @@ exit:
+ }
+
+ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+- struct kdbus_kmsg *kmsg,
++ struct kdbus_staging *staging,
+ ktime_t exp)
+ {
++ const struct kdbus_msg *msg = staging->msg;
+ struct kdbus_name_entry *name = NULL;
+ struct kdbus_reply *wait = NULL;
+ struct kdbus_conn *dst = NULL;
+ struct kdbus_bus *bus = src->ep->bus;
+ int ret;
+
+- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) ||
+- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL) ||
+- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY)))
++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL) ||
++ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY)))
+ return ERR_PTR(-EINVAL);
+
+ /* resume previous wait-context, if available */
+
+ mutex_lock(&src->lock);
+- wait = kdbus_reply_find(NULL, src, kmsg->msg.cookie);
++ wait = kdbus_reply_find(NULL, src, msg->cookie);
+ if (wait) {
+ if (wait->interrupted) {
+ kdbus_reply_ref(wait);
+@@ -1199,7 +1186,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+
+ /* find and pin destination */
+
+- ret = kdbus_pin_dst(bus, kmsg, &name, &dst);
++ ret = kdbus_pin_dst(bus, staging, &name, &dst);
+ if (ret < 0)
+ goto exit;
+
+@@ -1208,7 +1195,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+ goto exit;
+ }
+
+- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, true);
++ wait = kdbus_reply_new(dst, src, msg, name, true);
+ if (IS_ERR(wait)) {
+ ret = PTR_ERR(wait);
+ wait = NULL;
+@@ -1217,9 +1204,9 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src,
+
+ /* send message */
+
+- kdbus_bus_eavesdrop(bus, src, kmsg);
++ kdbus_bus_eavesdrop(bus, src, staging);
+
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name);
++ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name);
+ if (ret < 0)
+ goto exit;
+
+@@ -1235,18 +1222,20 @@ exit:
+ return wait;
+ }
+
+-static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
++static int kdbus_conn_unicast(struct kdbus_conn *src,
++ struct kdbus_staging *staging)
+ {
++ const struct kdbus_msg *msg = staging->msg;
+ struct kdbus_name_entry *name = NULL;
+ struct kdbus_reply *wait = NULL;
+ struct kdbus_conn *dst = NULL;
+ struct kdbus_bus *bus = src->ep->bus;
+- bool is_signal = (kmsg->msg.flags & KDBUS_MSG_SIGNAL);
++ bool is_signal = (msg->flags & KDBUS_MSG_SIGNAL);
+ int ret = 0;
+
+- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) ||
+- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) &&
+- kmsg->msg.cookie_reply != 0))
++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) ||
++ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY) &&
++ msg->cookie_reply != 0))
+ return -EINVAL;
+
+ /* name-registry must be locked for lookup *and* collecting data */
+@@ -1254,23 +1243,23 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+
+ /* find and pin destination */
+
+- ret = kdbus_pin_dst(bus, kmsg, &name, &dst);
++ ret = kdbus_pin_dst(bus, staging, &name, &dst);
+ if (ret < 0)
+ goto exit;
+
+ if (is_signal) {
+ /* like broadcasts we eavesdrop even if the msg is dropped */
+- kdbus_bus_eavesdrop(bus, src, kmsg);
++ kdbus_bus_eavesdrop(bus, src, staging);
+
+ /* drop silently if peer is not interested or not privileged */
+- if (!kdbus_match_db_match_kmsg(dst->match_db, src, kmsg) ||
++ if (!kdbus_match_db_match_msg(dst->match_db, src, staging) ||
+ !kdbus_conn_policy_talk(dst, NULL, src))
+ goto exit;
+ } else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) {
+ ret = -EPERM;
+ goto exit;
+- } else if (kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) {
+- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, false);
++ } else if (msg->flags & KDBUS_MSG_EXPECT_REPLY) {
++ wait = kdbus_reply_new(dst, src, msg, name, false);
+ if (IS_ERR(wait)) {
+ ret = PTR_ERR(wait);
+ wait = NULL;
+@@ -1281,9 +1270,9 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg)
+ /* send message */
+
+ if (!is_signal)
+- kdbus_bus_eavesdrop(bus, src, kmsg);
++ kdbus_bus_eavesdrop(bus, src, staging);
+
+- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name);
++ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name);
+ if (ret < 0 && !is_signal)
+ goto exit;
+
+@@ -1353,7 +1342,7 @@ void kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
+ continue;
+
+ if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) &&
+- e->msg_res && e->msg_res->fds_count > 0) {
++ e->gaps && e->gaps->n_fds > 0) {
+ kdbus_conn_lost_message(conn_dst);
+ kdbus_queue_entry_free(e);
+ continue;
+@@ -1930,7 +1919,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ {
+ struct kdbus_cmd_send *cmd;
+ struct kdbus_staging *staging = NULL;
+- struct kdbus_kmsg *kmsg = NULL;
+ struct kdbus_msg *msg = NULL;
+ struct file *cancel_fd = NULL;
+ int ret, ret2;
+@@ -2021,23 +2009,16 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ goto exit;
+ }
+
+- kmsg = kdbus_kmsg_new_from_cmd(conn, cmd);
+- if (IS_ERR(kmsg)) {
+- ret = PTR_ERR(kmsg);
+- kmsg = NULL;
+- goto exit;
+- }
+-
+- if (kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) {
++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
+ down_read(&conn->ep->bus->name_registry->rwlock);
+- kdbus_bus_broadcast(conn->ep->bus, conn, kmsg);
++ kdbus_bus_broadcast(conn->ep->bus, conn, staging);
+ up_read(&conn->ep->bus->name_registry->rwlock);
+ } else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) {
+ struct kdbus_reply *r;
+ ktime_t exp;
+
+- exp = ns_to_ktime(kmsg->msg.timeout_ns);
+- r = kdbus_conn_call(conn, kmsg, exp);
++ exp = ns_to_ktime(msg->timeout_ns);
++ r = kdbus_conn_call(conn, staging, exp);
+ if (IS_ERR(r)) {
+ ret = PTR_ERR(r);
+ goto exit;
+@@ -2047,13 +2028,13 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ kdbus_reply_unref(r);
+ if (ret < 0)
+ goto exit;
+- } else if ((kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) ||
+- kmsg->msg.cookie_reply == 0) {
+- ret = kdbus_conn_unicast(conn, kmsg);
++ } else if ((msg->flags & KDBUS_MSG_EXPECT_REPLY) ||
++ msg->cookie_reply == 0) {
++ ret = kdbus_conn_unicast(conn, staging);
+ if (ret < 0)
+ goto exit;
+ } else {
+- ret = kdbus_conn_reply(conn, kmsg);
++ ret = kdbus_conn_reply(conn, staging);
+ if (ret < 0)
+ goto exit;
+ }
+@@ -2064,7 +2045,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp)
+ exit:
+ if (cancel_fd)
+ fput(cancel_fd);
+- kdbus_kmsg_free(kmsg);
+ kdbus_staging_free(staging);
+ ret = kdbus_args_clear(&msg_args, ret);
+ return kdbus_args_clear(&args, ret);
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index 90c1bcc91fe6..b1769b877504 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -31,7 +31,7 @@
+ KDBUS_HELLO_MONITOR)
+
+ struct kdbus_quota;
+-struct kdbus_kmsg;
++struct kdbus_staging;
+
+ /**
+ * struct kdbus_conn - connection to a bus
+@@ -134,7 +134,7 @@ void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u,
+ void kdbus_conn_lost_message(struct kdbus_conn *c);
+ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+ struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg,
++ struct kdbus_staging *staging,
+ struct kdbus_reply *reply,
+ const struct kdbus_name_entry *name);
+ void kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+index 3f86e4c81468..3ae224ff9f3f 100644
+--- a/ipc/kdbus/match.c
++++ b/ipc/kdbus/match.c
+@@ -206,13 +206,13 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter,
+
+ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
+ struct kdbus_conn *c,
+- const struct kdbus_kmsg *kmsg)
++ const struct kdbus_staging *s)
+ {
+ lockdep_assert_held(&c->ep->bus->name_registry->rwlock);
+
+ switch (r->type) {
+ case KDBUS_ITEM_BLOOM_MASK:
+- return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c);
++ return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c);
+ case KDBUS_ITEM_ID:
+ return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY;
+ case KDBUS_ITEM_NAME:
+@@ -223,9 +223,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
+ }
+
+ static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r,
+- const struct kdbus_kmsg *kmsg)
++ const struct kdbus_staging *s)
+ {
+- struct kdbus_item *n = kmsg->notify;
++ struct kdbus_item *n = s->notify;
+
+ if (WARN_ON(!n) || n->type != r->type)
+ return false;
+@@ -252,23 +252,23 @@ static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r,
+
+ static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
+ struct kdbus_conn *c,
+- const struct kdbus_kmsg *kmsg)
++ const struct kdbus_staging *s)
+ {
+ struct kdbus_match_rule *r;
+
+ list_for_each_entry(r, &entry->rules_list, rules_entry)
+- if ((c && !kdbus_match_rule_conn(r, c, kmsg)) ||
+- (!c && !kdbus_match_rule_kernel(r, kmsg)))
++ if ((c && !kdbus_match_rule_conn(r, c, s)) ||
++ (!c && !kdbus_match_rule_kernel(r, s)))
+ return false;
+
+ return true;
+ }
+
+ /**
+- * kdbus_match_db_match_kmsg() - match a kmsg object agains the database entries
++ * kdbus_match_db_match_msg() - match a msg object agains the database entries
+ * @mdb: The match database
+ * @conn_src: The connection object originating the message
+- * @kmsg: The kmsg to perform the match on
++ * @staging: Staging object containing the message to match against
+ *
+ * This function will walk through all the database entries previously uploaded
+ * with kdbus_match_db_add(). As soon as any of them has an all-satisfied rule
+@@ -279,16 +279,16 @@ static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
+ *
+ * Return: true if there was a matching database entry, false otherwise.
+ */
+-bool kdbus_match_db_match_kmsg(struct kdbus_match_db *mdb,
+- struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg)
++bool kdbus_match_db_match_msg(struct kdbus_match_db *mdb,
++ struct kdbus_conn *conn_src,
++ const struct kdbus_staging *staging)
+ {
+ struct kdbus_match_entry *entry;
+ bool matched = false;
+
+ down_read(&mdb->mdb_rwlock);
+ list_for_each_entry(entry, &mdb->entries_list, list_entry) {
+- matched = kdbus_match_rules(entry, conn_src, kmsg);
++ matched = kdbus_match_rules(entry, conn_src, staging);
+ if (matched)
+ break;
+ }
+diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h
+index ea4292938deb..ceb492f8e51c 100644
+--- a/ipc/kdbus/match.h
++++ b/ipc/kdbus/match.h
+@@ -16,8 +16,8 @@
+ #define __KDBUS_MATCH_H
+
+ struct kdbus_conn;
+-struct kdbus_kmsg;
+ struct kdbus_match_db;
++struct kdbus_staging;
+
+ struct kdbus_match_db *kdbus_match_db_new(void);
+ void kdbus_match_db_free(struct kdbus_match_db *db);
+@@ -25,9 +25,9 @@ int kdbus_match_db_add(struct kdbus_conn *conn,
+ struct kdbus_cmd_match *cmd);
+ int kdbus_match_db_remove(struct kdbus_conn *conn,
+ struct kdbus_cmd_match *cmd);
+-bool kdbus_match_db_match_kmsg(struct kdbus_match_db *db,
+- struct kdbus_conn *conn_src,
+- struct kdbus_kmsg *kmsg);
++bool kdbus_match_db_match_msg(struct kdbus_match_db *db,
++ struct kdbus_conn *conn_src,
++ const struct kdbus_staging *staging);
+
+ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp);
+ int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp);
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index 8fe49a961834..e0c4f2e324b3 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -14,6 +14,9 @@
+ #ifndef __KDBUS_MESSAGE_H
+ #define __KDBUS_MESSAGE_H
+
++#include <linux/fs.h>
++#include <linux/kref.h>
++#include <uapi/linux/kdbus.h>
+ #include "util.h"
+ #include "metadata.h"
+
+@@ -114,6 +117,9 @@ struct kdbus_kmsg {
+
+ struct kdbus_bus;
+ struct kdbus_conn;
++struct kdbus_meta_conn;
++struct kdbus_meta_proc;
++struct kdbus_pool_slice;
+
+ struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus,
+ u64 dst, u64 cookie_timeout,
+diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c
+index a07d242d0470..375758c4896a 100644
+--- a/ipc/kdbus/notify.c
++++ b/ipc/kdbus/notify.c
+@@ -28,24 +28,24 @@
+ #include "message.h"
+ #include "notify.h"
+
+-static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg,
++static inline void kdbus_notify_add_tail(struct kdbus_staging *staging,
+ struct kdbus_bus *bus)
+ {
+ spin_lock(&bus->notify_lock);
+- list_add_tail(&kmsg->notify_entry, &bus->notify_list);
++ list_add_tail(&staging->notify_entry, &bus->notify_list);
+ spin_unlock(&bus->notify_lock);
+ }
+
+ static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id,
+ u64 cookie, u64 msg_type)
+ {
+- struct kdbus_kmsg *kmsg;
++ struct kdbus_staging *s;
+
+- kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type);
+- if (IS_ERR(kmsg))
+- return PTR_ERR(kmsg);
++ s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type);
++ if (IS_ERR(s))
++ return PTR_ERR(s);
+
+- kdbus_notify_add_tail(kmsg, bus);
++ kdbus_notify_add_tail(s, bus);
+ return 0;
+ }
+
+@@ -100,23 +100,23 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
+ const char *name)
+ {
+ size_t name_len, extra_size;
+- struct kdbus_kmsg *kmsg;
++ struct kdbus_staging *s;
+
+ name_len = strlen(name) + 1;
+ extra_size = sizeof(struct kdbus_notify_name_change) + name_len;
+
+- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
+ extra_size, type);
+- if (IS_ERR(kmsg))
+- return PTR_ERR(kmsg);
++ if (IS_ERR(s))
++ return PTR_ERR(s);
+
+- kmsg->notify->name_change.old_id.id = old_id;
+- kmsg->notify->name_change.old_id.flags = old_flags;
+- kmsg->notify->name_change.new_id.id = new_id;
+- kmsg->notify->name_change.new_id.flags = new_flags;
+- memcpy(kmsg->notify->name_change.name, name, name_len);
++ s->notify->name_change.old_id.id = old_id;
++ s->notify->name_change.old_id.flags = old_flags;
++ s->notify->name_change.new_id.id = new_id;
++ s->notify->name_change.new_id.flags = new_flags;
++ memcpy(s->notify->name_change.name, name, name_len);
+
+- kdbus_notify_add_tail(kmsg, bus);
++ kdbus_notify_add_tail(s, bus);
+ return 0;
+ }
+
+@@ -132,19 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
+ */
+ int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags)
+ {
+- struct kdbus_kmsg *kmsg;
++ struct kdbus_staging *s;
+ size_t extra_size;
+
+ extra_size = sizeof(struct kdbus_notify_id_change);
+- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
++ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0,
+ extra_size, type);
+- if (IS_ERR(kmsg))
+- return PTR_ERR(kmsg);
++ if (IS_ERR(s))
++ return PTR_ERR(s);
+
+- kmsg->notify->id_change.id = id;
+- kmsg->notify->id_change.flags = flags;
++ s->notify->id_change.id = id;
++ s->notify->id_change.flags = flags;
+
+- kdbus_notify_add_tail(kmsg, bus);
++ kdbus_notify_add_tail(s, bus);
+ return 0;
+ }
+
+@@ -157,7 +157,7 @@ int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags)
+ void kdbus_notify_flush(struct kdbus_bus *bus)
+ {
+ LIST_HEAD(notify_list);
+- struct kdbus_kmsg *kmsg, *tmp;
++ struct kdbus_staging *s, *tmp;
+
+ mutex_lock(&bus->notify_flush_lock);
+ down_read(&bus->name_registry->rwlock);
+@@ -166,26 +166,23 @@ void kdbus_notify_flush(struct kdbus_bus *bus)
+ list_splice_init(&bus->notify_list, &notify_list);
+ spin_unlock(&bus->notify_lock);
+
+- list_for_each_entry_safe(kmsg, tmp, &notify_list, notify_entry) {
+- kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq,
+- KDBUS_ATTACH_TIMESTAMP);
+-
+- if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) {
++ list_for_each_entry_safe(s, tmp, &notify_list, notify_entry) {
++ if (s->msg->dst_id != KDBUS_DST_ID_BROADCAST) {
+ struct kdbus_conn *conn;
+
+- conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id);
++ conn = kdbus_bus_find_conn_by_id(bus, s->msg->dst_id);
+ if (conn) {
+- kdbus_bus_eavesdrop(bus, NULL, kmsg);
+- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL,
++ kdbus_bus_eavesdrop(bus, NULL, s);
++ kdbus_conn_entry_insert(NULL, conn, s, NULL,
+ NULL);
+ kdbus_conn_unref(conn);
+ }
+ } else {
+- kdbus_bus_broadcast(bus, NULL, kmsg);
++ kdbus_bus_broadcast(bus, NULL, s);
+ }
+
+- list_del(&kmsg->notify_entry);
+- kdbus_kmsg_free(kmsg);
++ list_del(&s->notify_entry);
++ kdbus_staging_free(s);
+ }
+
+ up_read(&bus->name_registry->rwlock);
+@@ -198,10 +195,10 @@ void kdbus_notify_flush(struct kdbus_bus *bus)
+ */
+ void kdbus_notify_free(struct kdbus_bus *bus)
+ {
+- struct kdbus_kmsg *kmsg, *tmp;
++ struct kdbus_staging *s, *tmp;
+
+- list_for_each_entry_safe(kmsg, tmp, &bus->notify_list, notify_entry) {
+- list_del(&kmsg->notify_entry);
+- kdbus_kmsg_free(kmsg);
++ list_for_each_entry_safe(s, tmp, &bus->notify_list, notify_entry) {
++ list_del(&s->notify_entry);
++ kdbus_staging_free(s);
+ }
+ }
+diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c
+index 4749b23a4f14..f9c44d7bae6d 100644
+--- a/ipc/kdbus/queue.c
++++ b/ipc/kdbus/queue.c
+@@ -171,243 +171,43 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry)
+
+ /**
+ * kdbus_queue_entry_new() - allocate a queue entry
+- * @conn_src: source connection
+- * @conn_dst: destination connection
+- * @kmsg: kmsg object the queue entry should track
++ * @src: source connection, or NULL
++ * @dst: destination connection
++ * @s: staging object carrying the message
+ *
+- * Allocates a queue entry based on a given kmsg and allocate space for
++ * Allocates a queue entry based on a given msg and allocate space for
+ * the message payload and the requested metadata in the connection's pool.
+ * The entry is not actually added to the queue's lists at this point.
+ *
+ * Return: the allocated entry on success, or an ERR_PTR on failures.
+ */
+-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src,
+- struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg)
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src,
++ struct kdbus_conn *dst,
++ struct kdbus_staging *s)
+ {
+- struct kdbus_user *user = conn_src ? conn_src->user : NULL;
+- struct kdbus_msg_resources *res = kmsg->res;
+- const struct kdbus_msg *msg = &kmsg->msg;
+ struct kdbus_queue_entry *entry;
+- size_t memfd_cnt = 0;
+- struct kvec kvec[2];
+- size_t meta_size;
+- size_t msg_size;
+- u64 payload_off;
+- u64 size = 0;
+- int ret = 0;
++ int ret;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&entry->entry);
+- entry->priority = msg->priority;
+- entry->msg_res = kdbus_msg_resources_ref(res);
+- entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta);
+- entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta);
+- entry->conn = kdbus_conn_ref(conn_dst);
+-
+- if (kmsg->msg.src_id == KDBUS_SRC_ID_KERNEL)
+- msg_size = msg->size;
+- else
+- msg_size = offsetof(struct kdbus_msg, items);
+-
+- /* sum up the size of the needed slice */
+- size = msg_size;
+-
+- if (res) {
+- size += res->vec_count *
+- KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
+-
+- if (res->memfd_count) {
+- entry->memfd_offset =
+- kcalloc(res->memfd_count, sizeof(size_t),
+- GFP_KERNEL);
+- if (!entry->memfd_offset) {
+- ret = -ENOMEM;
+- goto exit_free_entry;
+- }
+-
+- size += res->memfd_count *
+- KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
+- }
+-
+- if (res->fds_count)
+- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count);
+-
+- if (res->dst_name)
+- size += KDBUS_ITEM_SIZE(strlen(res->dst_name) + 1);
+- }
+-
+- /*
+- * Remember the offset of the metadata part, so we can override
+- * this part later during kdbus_queue_entry_install().
+- */
+- entry->meta_offset = size;
+-
+- if (entry->proc_meta || entry->conn_meta) {
+- entry->attach_flags =
+- atomic64_read(&conn_dst->attach_flags_recv);
+-
+- ret = kdbus_meta_export_prepare(entry->proc_meta,
+- NULL,
+- entry->conn_meta,
+- &entry->attach_flags,
+- &meta_size);
+- if (ret < 0)
+- goto exit_free_entry;
+-
+- size += meta_size;
+- }
++ entry->priority = s->msg->priority;
++ entry->conn = kdbus_conn_ref(dst);
++ entry->gaps = kdbus_gaps_ref(s->gaps);
+
+- payload_off = size;
+- size += kmsg->pool_size;
+- size = KDBUS_ALIGN8(size);
+-
+- ret = kdbus_conn_quota_inc(conn_dst, user, size,
+- res ? res->fds_count : 0);
+- if (ret < 0)
+- goto exit_free_entry;
+-
+- entry->slice = kdbus_pool_slice_alloc(conn_dst->pool, size, true);
++ entry->slice = kdbus_staging_emit(s, src, dst);
+ if (IS_ERR(entry->slice)) {
+ ret = PTR_ERR(entry->slice);
+ entry->slice = NULL;
+- kdbus_conn_quota_dec(conn_dst, user, size,
+- res ? res->fds_count : 0);
+- goto exit_free_entry;
+- }
+-
+- /* we accounted for exactly 'size' bytes, make sure it didn't grow */
+- WARN_ON(kdbus_pool_slice_size(entry->slice) != size);
+- entry->user = kdbus_user_ref(user);
+-
+- /* copy message header */
+- kvec[0].iov_base = (char *)msg;
+- kvec[0].iov_len = msg_size;
+-
+- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, msg_size);
+- if (ret < 0)
+- goto exit_free_entry;
+-
+- /* 'size' will now track the write position */
+- size = msg_size;
+-
+- /* create message payload items */
+- if (res) {
+- size_t dst_name_len = 0;
+- unsigned int i;
+- size_t sz = 0;
+-
+- if (res->dst_name) {
+- dst_name_len = strlen(res->dst_name) + 1;
+- sz += KDBUS_ITEM_SIZE(dst_name_len);
+- }
+-
+- for (i = 0; i < res->data_count; ++i) {
+- struct kdbus_vec v;
+- struct kdbus_memfd m;
+-
+- switch (res->data[i].type) {
+- case KDBUS_MSG_DATA_VEC:
+- sz += KDBUS_ITEM_SIZE(sizeof(v));
+- break;
+-
+- case KDBUS_MSG_DATA_MEMFD:
+- sz += KDBUS_ITEM_SIZE(sizeof(m));
+- break;
+- }
+- }
+-
+- if (sz) {
+- struct kdbus_item *items, *item;
+-
+- items = kmalloc(sz, GFP_KERNEL);
+- if (!items) {
+- ret = -ENOMEM;
+- goto exit_free_entry;
+- }
+-
+- item = items;
+-
+- if (res->dst_name)
+- item = kdbus_item_set(item, KDBUS_ITEM_DST_NAME,
+- res->dst_name,
+- dst_name_len);
+-
+- for (i = 0; i < res->data_count; ++i) {
+- struct kdbus_msg_data *d = res->data + i;
+- struct kdbus_memfd m = {};
+- struct kdbus_vec v = {};
+-
+- switch (d->type) {
+- case KDBUS_MSG_DATA_VEC:
+- v.size = d->size;
+- v.offset = d->vec.off;
+- if (v.offset != ~0ULL)
+- v.offset += payload_off;
+-
+- item = kdbus_item_set(item,
+- KDBUS_ITEM_PAYLOAD_OFF,
+- &v, sizeof(v));
+- break;
+-
+- case KDBUS_MSG_DATA_MEMFD:
+- /*
+- * Remember the location of memfds, so
+- * we can override the content from
+- * kdbus_queue_entry_install().
+- */
+- entry->memfd_offset[memfd_cnt++] =
+- msg_size +
+- (char *)item - (char *)items +
+- offsetof(struct kdbus_item,
+- memfd);
+-
+- item = kdbus_item_set(item,
+- KDBUS_ITEM_PAYLOAD_MEMFD,
+- &m, sizeof(m));
+- break;
+- }
+- }
+-
+- kvec[0].iov_base = items;
+- kvec[0].iov_len = sz;
+-
+- ret = kdbus_pool_slice_copy_kvec(entry->slice, size,
+- kvec, 1, sz);
+- kfree(items);
+-
+- if (ret < 0)
+- goto exit_free_entry;
+-
+- size += sz;
+- }
+-
+- /*
+- * Remember the location of the FD part, so we can override the
+- * content in kdbus_queue_entry_install().
+- */
+- if (res->fds_count) {
+- entry->fds_offset = size;
+- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count);
+- }
+- }
+-
+- /* finally, copy over the actual message payload */
+- if (kmsg->iov_count) {
+- ret = kdbus_pool_slice_copy_iovec(entry->slice, payload_off,
+- kmsg->iov,
+- kmsg->iov_count,
+- kmsg->pool_size);
+- if (ret < 0)
+- goto exit_free_entry;
++ goto error;
+ }
+
++ entry->user = src ? kdbus_user_ref(src->user) : NULL;
+ return entry;
+
+-exit_free_entry:
++error:
+ kdbus_queue_entry_free(entry);
+ return ERR_PTR(ret);
+ }
+@@ -432,17 +232,13 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry)
+ if (entry->slice) {
+ kdbus_conn_quota_dec(entry->conn, entry->user,
+ kdbus_pool_slice_size(entry->slice),
+- entry->msg_res ?
+- entry->msg_res->fds_count : 0);
++ entry->gaps ? entry->gaps->n_fds : 0);
+ kdbus_pool_slice_release(entry->slice);
+- kdbus_user_unref(entry->user);
+ }
+
+- kdbus_msg_resources_unref(entry->msg_res);
+- kdbus_meta_conn_unref(entry->conn_meta);
+- kdbus_meta_proc_unref(entry->proc_meta);
++ kdbus_user_unref(entry->user);
++ kdbus_gaps_unref(entry->gaps);
+ kdbus_conn_unref(entry->conn);
+- kfree(entry->memfd_offset);
+ kfree(entry);
+ }
+
+@@ -453,136 +249,22 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry)
+ * @return_flags: Pointer to store the return flags for userspace
+ * @install_fds: Whether or not to install associated file descriptors
+ *
+- * This function will create a slice to transport the message header, the
+- * metadata items and other items for information stored in @entry, and
+- * store it as entry->slice.
+- *
+- * If @install_fds is %true, file descriptors will as well be installed.
+- * This function must always be called from the task context of the receiver.
+- *
+ * Return: 0 on success.
+ */
+ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
+ u64 *return_flags, bool install_fds)
+ {
+- u64 msg_size = entry->meta_offset;
+- struct kdbus_conn *conn_dst = entry->conn;
+- struct kdbus_msg_resources *res;
+ bool incomplete_fds = false;
+- struct kvec kvec[2];
+- size_t memfds = 0;
+- int i, ret;
+-
+- lockdep_assert_held(&conn_dst->lock);
+-
+- if (entry->proc_meta || entry->conn_meta) {
+- size_t meta_size;
+-
+- ret = kdbus_meta_export(entry->proc_meta,
+- NULL,
+- entry->conn_meta,
+- conn_dst,
+- entry->attach_flags,
+- entry->slice,
+- entry->meta_offset,
+- &meta_size);
+- if (ret < 0)
+- return ret;
+-
+- msg_size += meta_size;
+- }
++ int ret;
+
+- /* Update message size at offset 0 */
+- kvec[0].iov_base = &msg_size;
+- kvec[0].iov_len = sizeof(msg_size);
++ lockdep_assert_held(&entry->conn->lock);
+
+- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1,
+- sizeof(msg_size));
++ ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds);
+ if (ret < 0)
+ return ret;
+
+- res = entry->msg_res;
+-
+- if (!res)
+- return 0;
+-
+- if (res->fds_count) {
+- struct kdbus_item_header hdr;
+- size_t off;
+- int *fds;
+-
+- fds = kmalloc_array(res->fds_count, sizeof(int), GFP_KERNEL);
+- if (!fds)
+- return -ENOMEM;
+-
+- for (i = 0; i < res->fds_count; i++) {
+- if (install_fds) {
+- fds[i] = get_unused_fd_flags(O_CLOEXEC);
+- if (fds[i] >= 0)
+- fd_install(fds[i],
+- get_file(res->fds[i]));
+- else
+- incomplete_fds = true;
+- } else {
+- fds[i] = -1;
+- }
+- }
+-
+- off = entry->fds_offset;
+-
+- hdr.type = KDBUS_ITEM_FDS;
+- hdr.size = KDBUS_ITEM_HEADER_SIZE +
+- sizeof(int) * res->fds_count;
+-
+- kvec[0].iov_base = &hdr;
+- kvec[0].iov_len = sizeof(hdr);
+-
+- kvec[1].iov_base = fds;
+- kvec[1].iov_len = sizeof(int) * res->fds_count;
+-
+- ret = kdbus_pool_slice_copy_kvec(entry->slice, off,
+- kvec, 2, hdr.size);
+- kfree(fds);
+-
+- if (ret < 0)
+- return ret;
+- }
+-
+- for (i = 0; i < res->data_count; ++i) {
+- struct kdbus_msg_data *d = res->data + i;
+- struct kdbus_memfd m;
+-
+- if (d->type != KDBUS_MSG_DATA_MEMFD)
+- continue;
+-
+- m.start = d->memfd.start;
+- m.size = d->size;
+- m.fd = -1;
+-
+- if (install_fds) {
+- m.fd = get_unused_fd_flags(O_CLOEXEC);
+- if (m.fd < 0) {
+- m.fd = -1;
+- incomplete_fds = true;
+- } else {
+- fd_install(m.fd,
+- get_file(d->memfd.file));
+- }
+- }
+-
+- kvec[0].iov_base = &m;
+- kvec[0].iov_len = sizeof(m);
+-
+- ret = kdbus_pool_slice_copy_kvec(entry->slice,
+- entry->memfd_offset[memfds++],
+- kvec, 1, sizeof(m));
+- if (ret < 0)
+- return ret;
+- }
+-
+ if (incomplete_fds)
+ *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS;
+-
+ return 0;
+ }
+
+@@ -646,7 +328,7 @@ int kdbus_queue_entry_move(struct kdbus_queue_entry *e,
+ return 0;
+
+ size = kdbus_pool_slice_size(e->slice);
+- fds = e->msg_res ? e->msg_res->fds_count : 0;
++ fds = e->gaps ? e->gaps->n_fds : 0;
+
+ ret = kdbus_conn_quota_inc(dst, e->user, size, fds);
+ if (ret < 0)
+diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h
+index ac471d0c809d..bf686d182ce1 100644
+--- a/ipc/kdbus/queue.h
++++ b/ipc/kdbus/queue.h
+@@ -15,6 +15,13 @@
+ #ifndef __KDBUS_QUEUE_H
+ #define __KDBUS_QUEUE_H
+
++#include <linux/list.h>
++#include <linux/rbtree.h>
++
++struct kdbus_conn;
++struct kdbus_pool_slice;
++struct kdbus_reply;
++struct kdbus_staging;
+ struct kdbus_user;
+
+ /**
+@@ -35,52 +42,37 @@ struct kdbus_queue {
+ * @entry: Entry in the connection's list
+ * @prio_node: Entry in the priority queue tree
+ * @prio_entry: Queue tree node entry in the list of one priority
+- * @slice: Slice in the receiver's pool for the message
+- * @attach_flags: Attach flags used during slice allocation
+- * @meta_offset: Offset of first metadata item in slice
+- * @fds_offset: Offset of FD item in slice
+- * @memfd_offset: Array of slice-offsets for all memfd items
+ * @priority: Message priority
+ * @dst_name_id: The sequence number of the name this message is
+ * addressed to, 0 for messages sent to an ID
+- * @msg_res: Message resources
+- * @proc_meta: Process metadata, captured at message arrival
+- * @conn_meta: Connection metadata, captured at message arrival
+- * @reply: The reply block if a reply to this message is expected
++ * @conn: Connection this entry is queued on
++ * @gaps: Gaps object to fill message gaps at RECV time
+ * @user: User used for accounting
++ * @slice: Slice in the receiver's pool for the message
++ * @reply: The reply block if a reply to this message is expected
+ */
+ struct kdbus_queue_entry {
+ struct list_head entry;
+ struct rb_node prio_node;
+ struct list_head prio_entry;
+
+- struct kdbus_pool_slice *slice;
+-
+- u64 attach_flags;
+- size_t meta_offset;
+- size_t fds_offset;
+- size_t *memfd_offset;
+-
+ s64 priority;
+ u64 dst_name_id;
+
+- struct kdbus_msg_resources *msg_res;
+- struct kdbus_meta_proc *proc_meta;
+- struct kdbus_meta_conn *conn_meta;
+- struct kdbus_reply *reply;
+ struct kdbus_conn *conn;
++ struct kdbus_gaps *gaps;
+ struct kdbus_user *user;
++ struct kdbus_pool_slice *slice;
++ struct kdbus_reply *reply;
+ };
+
+-struct kdbus_kmsg;
+-
+ void kdbus_queue_init(struct kdbus_queue *queue);
+ struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue,
+ s64 priority, bool use_priority);
+
+-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src,
+- struct kdbus_conn *conn_dst,
+- const struct kdbus_kmsg *kmsg);
++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src,
++ struct kdbus_conn *dst,
++ struct kdbus_staging *s);
+ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry);
+ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry,
+ u64 *return_flags, bool install_fds);
+--
+2.4.3
+
+
+From 149fd9e2deb3fc394cf37f6f848ccb1ea34358d2 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Wed, 24 Jun 2015 15:29:53 +0200
+Subject: [PATCH 27/34] kdbus: drop unused metadata code
+
+Now that we switched to the new kdbus_staging infrastructure, the old
+RECV-time metadata helpers are no longer needed. Drop them.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/metadata.c | 371 ---------------------------------------------------
+ ipc/kdbus/metadata.h | 11 --
+ 2 files changed, 382 deletions(-)
+
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index 70ce5d15fc98..43e5f4564925 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -714,138 +714,6 @@ exit_unlock:
+ return ret;
+ }
+
+-/*
+- * kdbus_meta_export_prepare() - Prepare metadata for export
+- * @mp: Process metadata, or NULL
+- * @mf: Fake metadata, or NULL
+- * @mc: Connection metadata, or NULL
+- * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export
+- * @sz: Pointer to return the size needed by the metadata
+- *
+- * Does a conservative calculation of how much space metadata information
+- * will take up during export. It is 'conservative' because for string
+- * translations in namespaces, it will use the kernel namespaces, which is
+- * the longest possible version.
+- *
+- * The actual size consumed by kdbus_meta_export() may hence vary from the
+- * one reported here, but it is guaranteed never to be greater.
+- *
+- * Return: 0 on success, negative error number otherwise.
+- */
+-int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+- struct kdbus_meta_fake *mf,
+- struct kdbus_meta_conn *mc,
+- u64 *mask, size_t *sz)
+-{
+- char *exe_pathname = NULL;
+- void *exe_page = NULL;
+- size_t size = 0;
+- u64 valid = 0;
+- int ret = 0;
+-
+- if (WARN_ON(mf && mp))
+- mp = NULL;
+-
+- if (mf)
+- valid |= mf->valid;
+-
+- if (mp) {
+- mutex_lock(&mp->lock);
+- valid |= mp->valid;
+- mutex_unlock(&mp->lock);
+- }
+-
+- if (mc) {
+- mutex_lock(&mc->lock);
+- valid |= mc->valid;
+- mutex_unlock(&mc->lock);
+- }
+-
+- *mask &= valid;
+-
+- if (!*mask)
+- goto exit;
+-
+- /* process metadata */
+-
+- if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS))
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds));
+-
+- if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS))
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids));
+-
+- if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS))
+- size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups *
+- sizeof(u64));
+-
+- if (mp && (*mask & KDBUS_ATTACH_TID_COMM))
+- size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1);
+-
+- if (mp && (*mask & KDBUS_ATTACH_PID_COMM))
+- size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1);
+-
+- if (mp && (*mask & KDBUS_ATTACH_EXE)) {
+- exe_page = (void *)__get_free_page(GFP_TEMPORARY);
+- if (!exe_page) {
+- ret = -ENOMEM;
+- goto exit;
+- }
+-
+- exe_pathname = d_path(&mp->exe_path, exe_page, PAGE_SIZE);
+- if (IS_ERR(exe_pathname)) {
+- ret = PTR_ERR(exe_pathname);
+- goto exit;
+- }
+-
+- size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1);
+- free_page((unsigned long)exe_page);
+- }
+-
+- if (mp && (*mask & KDBUS_ATTACH_CMDLINE))
+- size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1);
+-
+- if (mp && (*mask & KDBUS_ATTACH_CGROUP))
+- size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1);
+-
+- if (mp && (*mask & KDBUS_ATTACH_CAPS))
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps));
+-
+- if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL))
+- size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel
+- : mf->seclabel) + 1);
+-
+- if (mp && (*mask & KDBUS_ATTACH_AUDIT))
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
+-
+- /* connection metadata */
+-
+- if (mc && (*mask & KDBUS_ATTACH_NAMES))
+- size += KDBUS_ALIGN8(mc->owned_names_size);
+-
+- if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+- size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1);
+-
+- if (mc && (*mask & KDBUS_ATTACH_TIMESTAMP))
+- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp));
+-
+-exit:
+- *sz = size;
+-
+- return ret;
+-}
+-
+-static int kdbus_meta_push_kvec(struct kvec *kvec,
+- struct kdbus_item_header *hdr,
+- u64 type, void *payload,
+- size_t payload_size, u64 *size)
+-{
+- hdr->type = type;
+- hdr->size = KDBUS_ITEM_HEADER_SIZE + payload_size;
+- kdbus_kvec_set(kvec++, hdr, sizeof(*hdr), size);
+- kdbus_kvec_set(kvec++, payload, payload_size, size);
+- return 2 + !!kdbus_kvec_pad(kvec++, size);
+-}
+-
+ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out,
+ const struct kdbus_meta_proc *mp,
+ struct user_namespace *user_ns)
+@@ -922,245 +790,6 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid)
+ return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1);
+ }
+
+-/**
+- * kdbus_meta_export() - export information from metadata into a slice
+- * @mp: Process metadata, or NULL
+- * @mf: Fake metadata, or NULL
+- * @mc: Connection metadata, or NULL
+- * @conn: Target connection to translate metadata into
+- * @mask: Mask of KDBUS_ATTACH_* flags to export
+- * @slice: The slice to export to
+- * @offset: The offset inside @slice to write to
+- * @real_size: The real size the metadata consumed
+- *
+- * This function exports information from metadata into @slice at offset
+- * @offset inside that slice. Only information that is requested in @mask
+- * and that has been collected before is exported.
+- *
+- * In order to make sure not to write out of bounds, @mask must be the same
+- * value that was previously returned from kdbus_meta_export_prepare(). The
+- * function will, however, not necessarily write as many bytes as returned by
+- * kdbus_meta_export_prepare(); depending on the namespaces in question, it
+- * might use up less than that.
+- *
+- * All information will be translated using the namespaces of @conn.
+- *
+- * Return: 0 on success, negative error number otherwise.
+- */
+-int kdbus_meta_export(struct kdbus_meta_proc *mp,
+- struct kdbus_meta_fake *mf,
+- struct kdbus_meta_conn *mc,
+- struct kdbus_conn *conn,
+- u64 mask,
+- struct kdbus_pool_slice *slice,
+- off_t offset,
+- size_t *real_size)
+-{
+- struct user_namespace *user_ns = conn->user_ns;
+- struct kdbus_item_header item_hdr[13], *hdr;
+- char *exe_pathname = NULL;
+- struct kdbus_creds creds;
+- struct kdbus_pids pids;
+- void *exe_page = NULL;
+- struct kvec kvec[40];
+- u64 *auxgrps = NULL;
+- size_t cnt = 0;
+- u64 size = 0;
+- int ret = 0;
+-
+- if (WARN_ON(mf && mp))
+- mp = NULL;
+-
+- hdr = &item_hdr[0];
+-
+- if (mask == 0) {
+- *real_size = 0;
+- return 0;
+- }
+-
+- /* process metadata */
+-
+- if (mf && (mask & KDBUS_ATTACH_CREDS)) {
+- creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid);
+- creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid);
+- creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid);
+- creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid);
+- creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid);
+- creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid);
+- creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid);
+- creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid);
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
+- &creds, sizeof(creds), &size);
+- } else if (mp && (mask & KDBUS_ATTACH_CREDS)) {
+- const struct cred *c = mp->cred;
+-
+- creds.uid = kdbus_from_kuid_keep(user_ns, c->uid);
+- creds.euid = kdbus_from_kuid_keep(user_ns, c->euid);
+- creds.suid = kdbus_from_kuid_keep(user_ns, c->suid);
+- creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid);
+- creds.gid = kdbus_from_kgid_keep(user_ns, c->gid);
+- creds.egid = kdbus_from_kgid_keep(user_ns, c->egid);
+- creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid);
+- creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid);
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS,
+- &creds, sizeof(creds), &size);
+- }
+-
+- if (mf && (mask & KDBUS_ATTACH_PIDS)) {
+- pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns);
+- pids.tid = pid_nr_ns(mf->pid, conn->pid_ns);
+- pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns);
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS,
+- &pids, sizeof(pids), &size);
+- } else if (mp && (mask & KDBUS_ATTACH_PIDS)) {
+- pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns);
+- pids.tid = pid_nr_ns(mp->pid, conn->pid_ns);
+- pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns);
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS,
+- &pids, sizeof(pids), &size);
+- }
+-
+- if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) {
+- const struct group_info *info = mp->cred->group_info;
+- size_t i, n, payload_size;
+-
+- n = info->ngroups;
+- payload_size = n * sizeof(u64);
+- auxgrps = kmalloc(payload_size, GFP_KERNEL);
+- if (!auxgrps) {
+- ret = -ENOMEM;
+- goto exit;
+- }
+-
+- for (i = 0; i < n; ++i)
+- auxgrps[i] = from_kgid_munged(user_ns,
+- GROUP_AT(info, i));
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_AUXGROUPS,
+- auxgrps, payload_size, &size);
+- }
+-
+- if (mp && (mask & KDBUS_ATTACH_TID_COMM))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_TID_COMM, mp->tid_comm,
+- strlen(mp->tid_comm) + 1, &size);
+-
+- if (mp && (mask & KDBUS_ATTACH_PID_COMM))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_PID_COMM, mp->pid_comm,
+- strlen(mp->pid_comm) + 1, &size);
+-
+- if (mp && (mask & KDBUS_ATTACH_EXE)) {
+- struct path p;
+-
+- /*
+- * TODO: We need access to __d_path() so we can write the path
+- * relative to conn->root_path. Once upstream, we need
+- * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that
+- * takes the root path directly. Until then, we drop this item
+- * if the root-paths differ.
+- */
+-
+- get_fs_root(current->fs, &p);
+- if (path_equal(&p, &mp->root_path) &&
+- path_equal(&p, &conn->root_path)) {
+- exe_page = (void *)__get_free_page(GFP_TEMPORARY);
+- if (!exe_page) {
+- path_put(&p);
+- ret = -ENOMEM;
+- goto exit;
+- }
+-
+- exe_pathname = d_path(&mp->exe_path, exe_page,
+- PAGE_SIZE);
+- if (IS_ERR(exe_pathname)) {
+- path_put(&p);
+- ret = PTR_ERR(exe_pathname);
+- goto exit;
+- }
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_EXE,
+- exe_pathname,
+- strlen(exe_pathname) + 1,
+- &size);
+- }
+- path_put(&p);
+- }
+-
+- if (mp && (mask & KDBUS_ATTACH_CMDLINE))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_CMDLINE, mp->cmdline,
+- strlen(mp->cmdline) + 1, &size);
+-
+- if (mp && (mask & KDBUS_ATTACH_CGROUP))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_CGROUP, mp->cgroup,
+- strlen(mp->cgroup) + 1, &size);
+-
+- if (mp && (mask & KDBUS_ATTACH_CAPS)) {
+- struct kdbus_meta_caps caps = {};
+-
+- kdbus_meta_export_caps(&caps, mp, user_ns);
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_CAPS, &caps,
+- sizeof(caps), &size);
+- }
+-
+- if (mf && (mask & KDBUS_ATTACH_SECLABEL))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_SECLABEL, mf->seclabel,
+- strlen(mf->seclabel) + 1, &size);
+- else if (mp && (mask & KDBUS_ATTACH_SECLABEL))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_SECLABEL, mp->seclabel,
+- strlen(mp->seclabel) + 1, &size);
+-
+- if (mp && (mask & KDBUS_ATTACH_AUDIT)) {
+- struct kdbus_audit a = {
+- .loginuid = from_kuid(user_ns, mp->audit_loginuid),
+- .sessionid = mp->audit_sessionid,
+- };
+-
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_AUDIT,
+- &a, sizeof(a), &size);
+- }
+-
+- /* connection metadata */
+-
+- if (mc && (mask & KDBUS_ATTACH_NAMES))
+- kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items,
+- KDBUS_ALIGN8(mc->owned_names_size), &size);
+-
+- if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_CONN_DESCRIPTION,
+- mc->conn_description,
+- strlen(mc->conn_description) + 1,
+- &size);
+-
+- if (mc && (mask & KDBUS_ATTACH_TIMESTAMP))
+- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++,
+- KDBUS_ITEM_TIMESTAMP, &mc->ts,
+- sizeof(mc->ts), &size);
+-
+- ret = kdbus_pool_slice_copy_kvec(slice, offset, kvec, cnt, size);
+- *real_size = size;
+-
+-exit:
+- kfree(auxgrps);
+-
+- if (exe_page)
+- free_page((unsigned long)exe_page);
+-
+- return ret;
+-}
+-
+ struct kdbus_meta_staging {
+ const struct kdbus_meta_proc *mp;
+ const struct kdbus_meta_fake *mf;
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index a30b0ad26af2..8fb2a9f7f82e 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -72,17 +72,6 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc,
+ struct kdbus_conn *conn,
+ u64 msg_seqnum, u64 what);
+
+-int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp,
+- struct kdbus_meta_fake *mf,
+- struct kdbus_meta_conn *mc,
+- u64 *mask, size_t *sz);
+-int kdbus_meta_export(struct kdbus_meta_proc *mp,
+- struct kdbus_meta_fake *mf,
+- struct kdbus_meta_conn *mc,
+- struct kdbus_conn *conn,
+- u64 mask,
+- struct kdbus_pool_slice *slice,
+- off_t offset, size_t *real_size);
+ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
+ struct kdbus_meta_fake *mf,
+ struct kdbus_meta_conn *mc,
+--
+2.4.3
+
+
+From 5c9d1e5ee20da087dee20f20d5fa312249a163e4 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Wed, 24 Jun 2015 15:31:10 +0200
+Subject: [PATCH 28/34] kdbus: drop unused message handling
+
+Now that we switched to kdbus_staging, the old message importer and
+handling is no longer needed. Drop it.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/message.c | 600 ----------------------------------------------------
+ ipc/kdbus/message.h | 106 ----------
+ 2 files changed, 706 deletions(-)
+
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index f1ec69f3697f..72fb5908c927 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -37,608 +37,8 @@
+ #include "names.h"
+ #include "policy.h"
+
+-#define KDBUS_KMSG_HEADER_SIZE offsetof(struct kdbus_kmsg, msg)
+-
+-static struct kdbus_msg_resources *kdbus_msg_resources_new(void)
+-{
+- struct kdbus_msg_resources *r;
+-
+- r = kzalloc(sizeof(*r), GFP_KERNEL);
+- if (!r)
+- return ERR_PTR(-ENOMEM);
+-
+- kref_init(&r->kref);
+-
+- return r;
+-}
+-
+-static void __kdbus_msg_resources_free(struct kref *kref)
+-{
+- struct kdbus_msg_resources *r =
+- container_of(kref, struct kdbus_msg_resources, kref);
+- size_t i;
+-
+- for (i = 0; i < r->data_count; ++i) {
+- switch (r->data[i].type) {
+- case KDBUS_MSG_DATA_VEC:
+- /* nothing to do */
+- break;
+- case KDBUS_MSG_DATA_MEMFD:
+- if (r->data[i].memfd.file)
+- fput(r->data[i].memfd.file);
+- break;
+- }
+- }
+-
+- for (i = 0; i < r->fds_count; i++)
+- if (r->fds[i])
+- fput(r->fds[i]);
+-
+- kfree(r->dst_name);
+- kfree(r->data);
+- kfree(r->fds);
+- kfree(r);
+-}
+-
+-/**
+- * kdbus_msg_resources_ref() - Acquire reference to msg resources
+- * @r: resources to acquire ref to
+- *
+- * Return: The acquired resource
+- */
+-struct kdbus_msg_resources *
+-kdbus_msg_resources_ref(struct kdbus_msg_resources *r)
+-{
+- if (r)
+- kref_get(&r->kref);
+- return r;
+-}
+-
+-/**
+- * kdbus_msg_resources_unref() - Drop reference to msg resources
+- * @r: resources to drop reference of
+- *
+- * Return: NULL
+- */
+-struct kdbus_msg_resources *
+-kdbus_msg_resources_unref(struct kdbus_msg_resources *r)
+-{
+- if (r)
+- kref_put(&r->kref, __kdbus_msg_resources_free);
+- return NULL;
+-}
+-
+-/**
+- * kdbus_kmsg_free() - free allocated message
+- * @kmsg: Message
+- */
+-void kdbus_kmsg_free(struct kdbus_kmsg *kmsg)
+-{
+- if (!kmsg)
+- return;
+-
+- kdbus_msg_resources_unref(kmsg->res);
+- kdbus_meta_conn_unref(kmsg->conn_meta);
+- kdbus_meta_proc_unref(kmsg->proc_meta);
+- kfree(kmsg->iov);
+- kfree(kmsg);
+-}
+-
+-struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus,
+- u64 dst, u64 cookie_timeout,
+- size_t it_size, size_t it_type)
+-{
+- struct kdbus_kmsg *kmsg;
+- size_t size;
+- int ret;
+-
+- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size);
+- kmsg = kzalloc(size, GFP_KERNEL);
+- if (!kmsg)
+- return ERR_PTR(-ENOMEM);
+-
+- kmsg->seq = atomic64_inc_return(&bus->domain->last_id);
+-
+- kmsg->proc_meta = kdbus_meta_proc_new();
+- if (IS_ERR(kmsg->proc_meta)) {
+- ret = PTR_ERR(kmsg->proc_meta);
+- kmsg->proc_meta = NULL;
+- goto exit;
+- }
+-
+- kmsg->conn_meta = kdbus_meta_conn_new();
+- if (IS_ERR(kmsg->conn_meta)) {
+- ret = PTR_ERR(kmsg->conn_meta);
+- kmsg->conn_meta = NULL;
+- goto exit;
+- }
+-
+- kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE;
+- kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ?
+- KDBUS_MSG_SIGNAL : 0;
+- kmsg->msg.dst_id = dst;
+- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL;
+- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL;
+- kmsg->msg.cookie_reply = cookie_timeout;
+- kmsg->notify = kmsg->msg.items;
+- kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size;
+- kmsg->notify->type = it_type;
+-
+- return kmsg;
+-
+-exit:
+- kdbus_kmsg_free(kmsg);
+- return ERR_PTR(ret);
+-}
+-
+-static int kdbus_handle_check_file(struct file *file)
+-{
+- struct inode *inode = file_inode(file);
+- struct socket *sock;
+-
+- /*
+- * Don't allow file descriptors in the transport that themselves allow
+- * file descriptor queueing. This will eventually be allowed once both
+- * unix domain sockets and kdbus share a generic garbage collector.
+- */
+-
+- if (file->f_op == &kdbus_handle_ops)
+- return -EOPNOTSUPP;
+-
+- if (!S_ISSOCK(inode->i_mode))
+- return 0;
+-
+- if (file->f_mode & FMODE_PATH)
+- return 0;
+-
+- sock = SOCKET_I(inode);
+- if (sock->sk && sock->ops && sock->ops->family == PF_UNIX)
+- return -EOPNOTSUPP;
+-
+- return 0;
+-}
+-
+ static const char * const zeros = "\0\0\0\0\0\0\0";
+
+-/*
+- * kdbus_msg_scan_items() - validate incoming data and prepare parsing
+- * @kmsg: Message
+- * @bus: Bus the message is sent over
+- *
+- * Return: 0 on success, negative errno on failure.
+- *
+- * Files references in MEMFD or FDS items are pinned.
+- *
+- * On errors, the caller should drop any taken reference with
+- * kdbus_kmsg_free()
+- */
+-static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg,
+- struct kdbus_bus *bus)
+-{
+- struct kdbus_msg_resources *res = kmsg->res;
+- const struct kdbus_msg *msg = &kmsg->msg;
+- const struct kdbus_item *item;
+- size_t n_res, n_vecs, n_memfds;
+- bool has_bloom = false;
+- bool has_name = false;
+- bool has_fds = false;
+- bool is_broadcast;
+- bool is_signal;
+- u64 vec_size;
+-
+- is_broadcast = (msg->dst_id == KDBUS_DST_ID_BROADCAST);
+- is_signal = !!(msg->flags & KDBUS_MSG_SIGNAL);
+-
+- /* count data payloads */
+- n_vecs = 0;
+- n_memfds = 0;
+- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) {
+- switch (item->type) {
+- case KDBUS_ITEM_PAYLOAD_VEC:
+- ++n_vecs;
+- break;
+- case KDBUS_ITEM_PAYLOAD_MEMFD:
+- ++n_memfds;
+- if (item->memfd.size % 8)
+- ++n_vecs;
+- break;
+- default:
+- break;
+- }
+- }
+-
+- n_res = n_vecs + n_memfds;
+- if (n_res > 0) {
+- res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL);
+- if (!res->data)
+- return -ENOMEM;
+- }
+-
+- if (n_vecs > 0) {
+- kmsg->iov = kcalloc(n_vecs, sizeof(*kmsg->iov), GFP_KERNEL);
+- if (!kmsg->iov)
+- return -ENOMEM;
+- }
+-
+- /* import data payloads */
+- vec_size = 0;
+- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) {
+- size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item);
+- struct iovec *iov = kmsg->iov + kmsg->iov_count;
+-
+- switch (item->type) {
+- case KDBUS_ITEM_PAYLOAD_VEC: {
+- struct kdbus_msg_data *d = res->data + res->data_count;
+- void __force __user *ptr = KDBUS_PTR(item->vec.address);
+- size_t size = item->vec.size;
+-
+- if (vec_size + size < vec_size)
+- return -EMSGSIZE;
+- if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
+- return -EMSGSIZE;
+-
+- d->type = KDBUS_MSG_DATA_VEC;
+- d->size = size;
+-
+- if (ptr) {
+- if (unlikely(!access_ok(VERIFY_READ, ptr,
+- size)))
+- return -EFAULT;
+-
+- d->vec.off = kmsg->pool_size;
+- iov->iov_base = ptr;
+- iov->iov_len = size;
+- } else {
+- d->vec.off = ~0ULL;
+- iov->iov_base = (char __user *)zeros;
+- iov->iov_len = size % 8;
+- }
+-
+- if (kmsg->pool_size + iov->iov_len < kmsg->pool_size)
+- return -EMSGSIZE;
+-
+- kmsg->pool_size += iov->iov_len;
+- ++kmsg->iov_count;
+- ++res->vec_count;
+- ++res->data_count;
+- vec_size += size;
+-
+- break;
+- }
+-
+- case KDBUS_ITEM_PAYLOAD_MEMFD: {
+- struct kdbus_msg_data *d = res->data + res->data_count;
+- u64 start = item->memfd.start;
+- u64 size = item->memfd.size;
+- size_t pad = size % 8;
+- int seals, mask;
+- struct file *f;
+-
+- if (kmsg->pool_size + size % 8 < kmsg->pool_size)
+- return -EMSGSIZE;
+- if (start + size < start)
+- return -EMSGSIZE;
+-
+- if (item->memfd.fd < 0)
+- return -EBADF;
+-
+- if (res->memfd_count >= KDBUS_MSG_MAX_MEMFD_ITEMS)
+- return -E2BIG;
+-
+- f = fget(item->memfd.fd);
+- if (!f)
+- return -EBADF;
+-
+- if (pad) {
+- iov->iov_base = (char __user *)zeros;
+- iov->iov_len = pad;
+-
+- kmsg->pool_size += pad;
+- ++kmsg->iov_count;
+- }
+-
+- ++res->data_count;
+- ++res->memfd_count;
+-
+- d->type = KDBUS_MSG_DATA_MEMFD;
+- d->size = size;
+- d->memfd.start = start;
+- d->memfd.file = f;
+-
+- /*
+- * We only accept a sealed memfd file whose content
+- * cannot be altered by the sender or anybody else
+- * while it is shared or in-flight. Other files need
+- * to be passed with KDBUS_MSG_FDS.
+- */
+- seals = shmem_get_seals(f);
+- if (seals < 0)
+- return -EMEDIUMTYPE;
+-
+- mask = F_SEAL_SHRINK | F_SEAL_GROW |
+- F_SEAL_WRITE | F_SEAL_SEAL;
+- if ((seals & mask) != mask)
+- return -ETXTBSY;
+-
+- if (start + size > (u64)i_size_read(file_inode(f)))
+- return -EBADF;
+-
+- break;
+- }
+-
+- case KDBUS_ITEM_FDS: {
+- unsigned int i;
+- unsigned int fds_count = payload_size / sizeof(int);
+-
+- /* do not allow multiple fd arrays */
+- if (has_fds)
+- return -EEXIST;
+- has_fds = true;
+-
+- /* Do not allow to broadcast file descriptors */
+- if (is_broadcast)
+- return -ENOTUNIQ;
+-
+- if (fds_count > KDBUS_CONN_MAX_FDS_PER_USER)
+- return -EMFILE;
+-
+- res->fds = kcalloc(fds_count, sizeof(struct file *),
+- GFP_KERNEL);
+- if (!res->fds)
+- return -ENOMEM;
+-
+- for (i = 0; i < fds_count; i++) {
+- int fd = item->fds[i];
+- int ret;
+-
+- /*
+- * Verify the fd and increment the usage count.
+- * Use fget_raw() to allow passing O_PATH fds.
+- */
+- if (fd < 0)
+- return -EBADF;
+-
+- res->fds[i] = fget_raw(fd);
+- if (!res->fds[i])
+- return -EBADF;
+-
+- res->fds_count++;
+-
+- ret = kdbus_handle_check_file(res->fds[i]);
+- if (ret < 0)
+- return ret;
+- }
+-
+- break;
+- }
+-
+- case KDBUS_ITEM_BLOOM_FILTER: {
+- u64 bloom_size;
+-
+- /* do not allow multiple bloom filters */
+- if (has_bloom)
+- return -EEXIST;
+- has_bloom = true;
+-
+- bloom_size = payload_size -
+- offsetof(struct kdbus_bloom_filter, data);
+-
+- /*
+- * Allow only bloom filter sizes of a multiple of 64bit.
+- */
+- if (!KDBUS_IS_ALIGNED8(bloom_size))
+- return -EFAULT;
+-
+- /* do not allow mismatching bloom filter sizes */
+- if (bloom_size != bus->bloom.size)
+- return -EDOM;
+-
+- kmsg->bloom_filter = &item->bloom_filter;
+- break;
+- }
+-
+- case KDBUS_ITEM_DST_NAME:
+- /* do not allow multiple names */
+- if (has_name)
+- return -EEXIST;
+- has_name = true;
+-
+- if (!kdbus_name_is_valid(item->str, false))
+- return -EINVAL;
+-
+- res->dst_name = kstrdup(item->str, GFP_KERNEL);
+- if (!res->dst_name)
+- return -ENOMEM;
+- break;
+-
+- default:
+- return -EINVAL;
+- }
+- }
+-
+- /* name is needed if no ID is given */
+- if (msg->dst_id == KDBUS_DST_ID_NAME && !has_name)
+- return -EDESTADDRREQ;
+-
+- if (is_broadcast) {
+- /* Broadcasts can't take names */
+- if (has_name)
+- return -EBADMSG;
+-
+- /* All broadcasts have to be signals */
+- if (!is_signal)
+- return -EBADMSG;
+-
+- /* Timeouts are not allowed for broadcasts */
+- if (msg->timeout_ns > 0)
+- return -ENOTUNIQ;
+- }
+-
+- /*
+- * Signal messages require a bloom filter, and bloom filters are
+- * only valid with signals.
+- */
+- if (is_signal ^ has_bloom)
+- return -EBADMSG;
+-
+- return 0;
+-}
+-
+-/**
+- * kdbus_kmsg_new_from_cmd() - create kernel message from send payload
+- * @conn: Connection
+- * @cmd_send: Payload of KDBUS_CMD_SEND
+- *
+- * Return: a new kdbus_kmsg on success, ERR_PTR on failure.
+- */
+-struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn,
+- struct kdbus_cmd_send *cmd_send)
+-{
+- struct kdbus_kmsg *m;
+- u64 size;
+- int ret;
+-
+- ret = kdbus_copy_from_user(&size, KDBUS_PTR(cmd_send->msg_address),
+- sizeof(size));
+- if (ret < 0)
+- return ERR_PTR(ret);
+-
+- if (size < sizeof(struct kdbus_msg) || size > KDBUS_MSG_MAX_SIZE)
+- return ERR_PTR(-EINVAL);
+-
+- m = kmalloc(size + KDBUS_KMSG_HEADER_SIZE, GFP_KERNEL);
+- if (!m)
+- return ERR_PTR(-ENOMEM);
+-
+- memset(m, 0, KDBUS_KMSG_HEADER_SIZE);
+- m->seq = atomic64_inc_return(&conn->ep->bus->domain->last_id);
+-
+- m->proc_meta = kdbus_meta_proc_new();
+- if (IS_ERR(m->proc_meta)) {
+- ret = PTR_ERR(m->proc_meta);
+- m->proc_meta = NULL;
+- goto exit_free;
+- }
+-
+- m->conn_meta = kdbus_meta_conn_new();
+- if (IS_ERR(m->conn_meta)) {
+- ret = PTR_ERR(m->conn_meta);
+- m->conn_meta = NULL;
+- goto exit_free;
+- }
+-
+- if (copy_from_user(&m->msg, KDBUS_PTR(cmd_send->msg_address), size)) {
+- ret = -EFAULT;
+- goto exit_free;
+- }
+-
+- if (m->msg.size != size) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+-
+- if (m->msg.flags & ~(KDBUS_MSG_EXPECT_REPLY |
+- KDBUS_MSG_NO_AUTO_START |
+- KDBUS_MSG_SIGNAL)) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+-
+- ret = kdbus_items_validate(m->msg.items,
+- KDBUS_ITEMS_SIZE(&m->msg, items));
+- if (ret < 0)
+- goto exit_free;
+-
+- m->res = kdbus_msg_resources_new();
+- if (IS_ERR(m->res)) {
+- ret = PTR_ERR(m->res);
+- m->res = NULL;
+- goto exit_free;
+- }
+-
+- /* do not accept kernel-generated messages */
+- if (m->msg.payload_type == KDBUS_PAYLOAD_KERNEL) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+-
+- if (m->msg.flags & KDBUS_MSG_EXPECT_REPLY) {
+- /* requests for replies need timeout and cookie */
+- if (m->msg.timeout_ns == 0 || m->msg.cookie == 0) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+-
+- /* replies may not be expected for broadcasts */
+- if (m->msg.dst_id == KDBUS_DST_ID_BROADCAST) {
+- ret = -ENOTUNIQ;
+- goto exit_free;
+- }
+-
+- /* replies may not be expected for signals */
+- if (m->msg.flags & KDBUS_MSG_SIGNAL) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+- } else {
+- /*
+- * KDBUS_SEND_SYNC_REPLY is only valid together with
+- * KDBUS_MSG_EXPECT_REPLY
+- */
+- if (cmd_send->flags & KDBUS_SEND_SYNC_REPLY) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+-
+- /* replies cannot be signals */
+- if (m->msg.cookie_reply && (m->msg.flags & KDBUS_MSG_SIGNAL)) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+- }
+-
+- ret = kdbus_msg_scan_items(m, conn->ep->bus);
+- if (ret < 0)
+- goto exit_free;
+-
+- /* patch-in the source of this message */
+- if (m->msg.src_id > 0 && m->msg.src_id != conn->id) {
+- ret = -EINVAL;
+- goto exit_free;
+- }
+- m->msg.src_id = conn->id;
+-
+- return m;
+-
+-exit_free:
+- kdbus_kmsg_free(m);
+- return ERR_PTR(ret);
+-}
+-
+-/**
+- * kdbus_kmsg_collect_metadata() - collect metadata
+- * @kmsg: message to collect metadata on
+- * @src: source connection of message
+- * @dst: destination connection of message
+- *
+- * Return: 0 on success, negative error code on failure.
+- */
+-int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
+- struct kdbus_conn *src, struct kdbus_conn *dst)
+-{
+- u64 attach;
+- int ret;
+-
+- attach = kdbus_meta_calc_attach_flags(src, dst);
+- if (!src->meta_fake) {
+- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach);
+- if (ret < 0)
+- return ret;
+- }
+-
+- return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach);
+-}
+-
+ static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds)
+ {
+ size_t size_offsets, size_memfds, size_fds, size;
+diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h
+index e0c4f2e324b3..298f9c99dfcf 100644
+--- a/ipc/kdbus/message.h
++++ b/ipc/kdbus/message.h
+@@ -17,103 +17,6 @@
+ #include <linux/fs.h>
+ #include <linux/kref.h>
+ #include <uapi/linux/kdbus.h>
+-#include "util.h"
+-#include "metadata.h"
+-
+-/**
+- * enum kdbus_msg_data_type - Type of kdbus_msg_data payloads
+- * @KDBUS_MSG_DATA_VEC: Data vector provided by user-space
+- * @KDBUS_MSG_DATA_MEMFD: Memfd payload
+- */
+-enum kdbus_msg_data_type {
+- KDBUS_MSG_DATA_VEC,
+- KDBUS_MSG_DATA_MEMFD,
+-};
+-
+-/**
+- * struct kdbus_msg_data - Data payload as stored by messages
+- * @type: Type of payload (KDBUS_MSG_DATA_*)
+- * @size: Size of the described payload
+- * @off: The offset, relative to the vec slice
+- * @start: Offset inside the memfd
+- * @file: Backing file referenced by the memfd
+- */
+-struct kdbus_msg_data {
+- unsigned int type;
+- u64 size;
+-
+- union {
+- struct {
+- u64 off;
+- } vec;
+- struct {
+- u64 start;
+- struct file *file;
+- } memfd;
+- };
+-};
+-
+-/**
+- * struct kdbus_kmsg_resources - resources of a message
+- * @kref: Reference counter
+- * @dst_name: Short-cut to msg for faster lookup
+- * @fds: Array of file descriptors to pass
+- * @fds_count: Number of file descriptors to pass
+- * @data: Array of data payloads
+- * @vec_count: Number of VEC entries
+- * @memfd_count: Number of MEMFD entries in @data
+- * @data_count: Sum of @vec_count + @memfd_count
+- */
+-struct kdbus_msg_resources {
+- struct kref kref;
+- const char *dst_name;
+-
+- struct file **fds;
+- unsigned int fds_count;
+-
+- struct kdbus_msg_data *data;
+- size_t vec_count;
+- size_t memfd_count;
+- size_t data_count;
+-};
+-
+-struct kdbus_msg_resources *
+-kdbus_msg_resources_ref(struct kdbus_msg_resources *r);
+-struct kdbus_msg_resources *
+-kdbus_msg_resources_unref(struct kdbus_msg_resources *r);
+-
+-/**
+- * struct kdbus_kmsg - internal message handling data
+- * @seq: Domain-global message sequence number
+- * @notify: Short-cut to notify-item for kernel notifications
+- * @bloom_filter: Bloom filter to match message properties
+- * @notify_entry: List of kernel-generated notifications
+- * @iov: Array of iovec, describing the payload to copy
+- * @iov_count: Number of array members in @iov
+- * @pool_size: Overall size of inlined data referenced by @iov
+- * @proc_meta: Appended SCM-like metadata of the sending process
+- * @conn_meta: Appended SCM-like metadata of the sending connection
+- * @res: Message resources
+- * @msg: Message from or to userspace
+- */
+-struct kdbus_kmsg {
+- u64 seq;
+- struct kdbus_item *notify;
+-
+- const struct kdbus_bloom_filter *bloom_filter;
+- struct list_head notify_entry;
+-
+- struct iovec *iov;
+- size_t iov_count;
+- u64 pool_size;
+-
+- struct kdbus_meta_proc *proc_meta;
+- struct kdbus_meta_conn *conn_meta;
+- struct kdbus_msg_resources *res;
+-
+- /* variable size, must be the last member */
+- struct kdbus_msg msg;
+-};
+
+ struct kdbus_bus;
+ struct kdbus_conn;
+@@ -121,15 +24,6 @@ struct kdbus_meta_conn;
+ struct kdbus_meta_proc;
+ struct kdbus_pool_slice;
+
+-struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus,
+- u64 dst, u64 cookie_timeout,
+- size_t it_size, size_t it_type);
+-struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn,
+- struct kdbus_cmd_send *cmd_send);
+-void kdbus_kmsg_free(struct kdbus_kmsg *kmsg);
+-int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg,
+- struct kdbus_conn *src, struct kdbus_conn *dst);
+-
+ /**
+ * struct kdbus_gaps - gaps in message to be filled later
+ * @kref: Reference counter
+--
+2.4.3
+
+
+From 5b2ae5600065167040dd6d61466cce345568c68e Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 6 Jul 2015 11:29:05 +0200
+Subject: [PATCH 29/34] kdbus: allow senders to receive own broadcasts
+
+The dbus1 spec does not place a restriction on who can receive broadcasts.
+As long as the sender has a MATCH-rule on itself, it can as well receive
+its own broadcasts.
+
+As it turns out, user-space currently relies on this feature. So make sure
+to allow this just like dbus1. If we find some client that does not work
+with this, we will have to turn it into a HELLO-flag. Until then, just try
+to adjust the default behavior.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/bus.c | 2 --
+ tools/testing/selftests/kdbus/test-message.c | 9 +++++---
+ tools/testing/selftests/kdbus/test-policy-priv.c | 26 +++++++++++++++++++-----
+ 3 files changed, 27 insertions(+), 10 deletions(-)
+
+diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c
+index e7e17a7f7edd..a67f825bdeaf 100644
+--- a/ipc/kdbus/bus.c
++++ b/ipc/kdbus/bus.c
+@@ -263,8 +263,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus,
+
+ down_read(&bus->conn_rwlock);
+ hash_for_each(bus->conn_hash, i, conn_dst, hentry) {
+- if (conn_dst->id == staging->msg->src_id)
+- continue;
+ if (!kdbus_conn_is_ordinary(conn_dst))
+ continue;
+
+diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c
+index f1615dafb7f1..ddc1e0af877b 100644
+--- a/tools/testing/selftests/kdbus/test-message.c
++++ b/tools/testing/selftests/kdbus/test-message.c
+@@ -54,9 +54,12 @@ int kdbus_test_message_basic(struct kdbus_test_env *env)
+ KDBUS_DST_ID_BROADCAST);
+ ASSERT_RETURN(ret == 0);
+
+- /* Make sure that we do not get our own broadcasts */
+- ret = kdbus_msg_recv(sender, NULL, NULL);
+- ASSERT_RETURN(ret == -EAGAIN);
++ /* Make sure that we do get our own broadcasts */
++ ret = kdbus_msg_recv(sender, &msg, &offset);
++ ASSERT_RETURN(ret == 0);
++ ASSERT_RETURN(msg->cookie == cookie);
++
++ kdbus_msg_free(msg);
+
+ /* ... and receive on the 2nd */
+ ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset);
+diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c
+index a318cccad0d5..0208638a7245 100644
+--- a/tools/testing/selftests/kdbus/test-policy-priv.c
++++ b/tools/testing/selftests/kdbus/test-policy-priv.c
+@@ -110,6 +110,12 @@ static int test_policy_priv_by_broadcast(const char *bus,
+ KDBUS_DST_ID_BROADCAST);
+ ASSERT_RETURN(ret == 0);
+
++ /* drop own broadcast */
++ ret = kdbus_msg_recv(child_2, &msg, NULL);
++ ASSERT_RETURN(ret == 0);
++ ASSERT_RETURN(msg->src_id == child_2->id);
++ kdbus_msg_free(msg);
++
+ /* Use a little bit high time */
+ ret = kdbus_msg_recv_poll(child_2, 1000,
+ &msg, NULL);
+@@ -145,6 +151,12 @@ static int test_policy_priv_by_broadcast(const char *bus,
+ KDBUS_DST_ID_BROADCAST);
+ ASSERT_EXIT(ret == 0);
+
++ /* drop own broadcast */
++ ret = kdbus_msg_recv(child_2, &msg, NULL);
++ ASSERT_RETURN(ret == 0);
++ ASSERT_RETURN(msg->src_id == child_2->id);
++ kdbus_msg_free(msg);
++
+ /* Use a little bit high time */
+ ret = kdbus_msg_recv_poll(child_2, 1000,
+ &msg, NULL);
+@@ -313,11 +325,6 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env)
+ * receiver is not able to TALK to that name.
+ */
+
+- ret = test_policy_priv_by_broadcast(env->buspath, owner_a,
+- DO_NOT_DROP,
+- -ETIMEDOUT, -ETIMEDOUT);
+- ASSERT_RETURN(ret == 0);
+-
+ /* Activate matching for a privileged connection */
+ ret = kdbus_add_match_empty(owner_a);
+ ASSERT_RETURN(ret == 0);
+@@ -408,6 +415,15 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env)
+ 0, 0, KDBUS_DST_ID_BROADCAST);
+ ASSERT_RETURN(ret == 0);
+
++ ret = kdbus_msg_recv_poll(owner_a, 100, &msg, NULL);
++ ASSERT_RETURN(ret == 0);
++ ASSERT_RETURN(msg->cookie == expected_cookie);
++
++ /* Check src ID */
++ ASSERT_RETURN(msg->src_id == owner_a->id);
++
++ kdbus_msg_free(msg);
++
+ ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL);
+ ASSERT_RETURN(ret == 0);
+ ASSERT_RETURN(msg->cookie == expected_cookie);
+--
+2.4.3
+
+
+From ebca68e897b944559d77d7165bf3d1b173257e72 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Sat, 4 Jul 2015 19:41:28 +0200
+Subject: [PATCH 30/34] kdbus: pass metadata which a receiver could read via
+ /proc
+
+Current kdbus behavior is to only pass metadata to a receiver if the
+sender actively agreed on sending the metadata (via send-attach-flags).
+We now extend this logic in 2 ways:
+
+ - Implicit metadata is always sent, if requested by the receiver. This
+ includes basic process credentials, pids and connection metadata. The
+ latter is kdbus-specific information and always public (as it can be
+ retrieved via other means), and basic process credentials and pids are
+ required for compatibility to UDS.
+
+ - Any extended process credentials were only passed if told by the
+ sender. We now extend this logic to pass them also if the receiver
+ could have read that information via /proc. We verify that the sending
+ process has a pid in the pid-namespace of the receiver (i.e., it shows
+ up in /proc mounted in the receiver namespace) and verify the hide_pid
+ restrictions.
+
+With this change, we make kdbus in-line with /proc access checks. We
+basically say that we assume anyone with access to kdbusfs also has access
+to /proc of its *own* pid-namespace (which should be given in any system
+setup). We then automatically pass all information *as if* the receiver
+would read them immediately on message-retrieval via /proc. But kdbus now
+fixes the race-gap between message transmittal and /proc access.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 2 +
+ ipc/kdbus/connection.h | 2 +
+ ipc/kdbus/message.c | 2 +-
+ ipc/kdbus/metadata.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++---
+ ipc/kdbus/metadata.h | 5 +-
+ 5 files changed, 187 insertions(+), 13 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 2b334b04dd9d..461b8d66b2b9 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -132,6 +132,7 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+ conn->cred = get_current_cred();
+ conn->user_ns = get_user_ns(current_user_ns());
+ conn->pid_ns = get_pid_ns(task_active_pid_ns(current));
++ conn->pid = get_pid(task_pid(current));
+ get_fs_root(current->fs, &conn->root_path);
+ init_waitqueue_head(&conn->wait);
+ kdbus_queue_init(&conn->queue);
+@@ -282,6 +283,7 @@ static void __kdbus_conn_free(struct kref *kref)
+ kdbus_pool_free(conn->pool);
+ kdbus_ep_unref(conn->ep);
+ path_put(&conn->root_path);
++ put_pid(conn->pid);
+ put_pid_ns(conn->pid_ns);
+ put_user_ns(conn->user_ns);
+ put_cred(conn->cred);
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index b1769b877504..9a1b13d69085 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -61,6 +61,7 @@ struct kdbus_staging;
+ * @cred: The credentials of the connection at creation time
+ * @user_ns: User namespace at creation time
+ * @pid_ns: Pid namespace at creation time
++ * @pid: Pid at creation time
+ * @root_path: Root path at creation time
+ * @name_count: Number of owned well-known names
+ * @request_count: Number of pending requests issued by this
+@@ -102,6 +103,7 @@ struct kdbus_conn {
+ const struct cred *cred;
+ struct user_namespace *user_ns;
+ struct pid_namespace *pid_ns;
++ struct pid *pid;
+ struct path root_path;
+ atomic_t name_count;
+ atomic_t request_count;
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 72fb5908c927..64763ead693c 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -849,7 +849,7 @@ static int kdbus_staging_collect_metadata(struct kdbus_staging *staging,
+ int ret;
+
+ if (src)
+- attach = kdbus_meta_calc_attach_flags(src, dst);
++ attach = kdbus_meta_msg_mask(src, dst);
+ else
+ attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */
+
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index 43e5f4564925..5150932cb257 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -1156,18 +1156,187 @@ exit:
+ return ret;
+ }
+
++enum {
++ KDBUS_META_PROC_NONE,
++ KDBUS_META_PROC_NORMAL,
++};
++
++/**
++ * kdbus_proc_permission() - check /proc permissions on target pid
++ * @pid_ns: namespace we operate in
++ * @cred: credentials of requestor
++ * @target: target process
++ *
++ * This checks whether a process with credentials @cred can access information
++ * of @target in the namespace @pid_ns. This tries to follow /proc permissions,
++ * but is slightly more restrictive.
++ *
++ * Return: The /proc access level (KDBUS_META_PROC_*) is returned.
++ */
++static unsigned int kdbus_proc_permission(const struct pid_namespace *pid_ns,
++ const struct cred *cred,
++ struct pid *target)
++{
++ if (pid_ns->hide_pid < 1)
++ return KDBUS_META_PROC_NORMAL;
++
++ /* XXX: we need groups_search() exported for aux-groups */
++ if (gid_eq(cred->egid, pid_ns->pid_gid))
++ return KDBUS_META_PROC_NORMAL;
++
++ /*
++ * XXX: If ptrace_may_access(PTRACE_MODE_READ) is granted, you can
++ * overwrite hide_pid. However, ptrace_may_access() only supports
++ * checking 'current', hence, we cannot use this here. But we
++ * simply decide to not support this override, so no need to worry.
++ */
++
++ return KDBUS_META_PROC_NONE;
++}
++
++/**
++ * kdbus_meta_proc_mask() - calculate which metadata would be visible to
++ * a connection via /proc
++ * @prv_pid: pid of metadata provider
++ * @req_pid: pid of metadata requestor
++ * @req_cred: credentials of metadata reqeuestor
++ * @wanted: metadata that is requested
++ *
++ * This checks which metadata items of @prv_pid can be read via /proc by the
++ * requestor @req_pid.
++ *
++ * Return: Set of metadata flags the requestor can see (limited by @wanted).
++ */
++static u64 kdbus_meta_proc_mask(struct pid *prv_pid,
++ struct pid *req_pid,
++ const struct cred *req_cred,
++ u64 wanted)
++{
++ struct pid_namespace *prv_ns, *req_ns;
++ unsigned int proc;
++
++ prv_ns = ns_of_pid(prv_pid);
++ req_ns = ns_of_pid(req_pid);
++
++ /*
++ * If the sender is not visible in the receiver namespace, then the
++ * receiver cannot access the sender via its own procfs. Hence, we do
++ * not attach any additional metadata.
++ */
++ if (!pid_nr_ns(prv_pid, req_ns))
++ return 0;
++
++ /*
++ * If the pid-namespace of the receiver has hide_pid set, it cannot see
++ * any process but its own. We shortcut this /proc permission check if
++ * provider and requestor are the same. If not, we perform rather
++ * expensive /proc permission checks.
++ */
++ if (prv_pid == req_pid)
++ proc = KDBUS_META_PROC_NORMAL;
++ else
++ proc = kdbus_proc_permission(req_ns, req_cred, prv_pid);
++
++ /* you need /proc access to read standard process attributes */
++ if (proc < KDBUS_META_PROC_NORMAL)
++ wanted &= ~(KDBUS_ATTACH_TID_COMM |
++ KDBUS_ATTACH_PID_COMM |
++ KDBUS_ATTACH_SECLABEL |
++ KDBUS_ATTACH_CMDLINE |
++ KDBUS_ATTACH_CGROUP |
++ KDBUS_ATTACH_AUDIT |
++ KDBUS_ATTACH_CAPS |
++ KDBUS_ATTACH_EXE);
++
++ /* clear all non-/proc flags */
++ return wanted & (KDBUS_ATTACH_TID_COMM |
++ KDBUS_ATTACH_PID_COMM |
++ KDBUS_ATTACH_SECLABEL |
++ KDBUS_ATTACH_CMDLINE |
++ KDBUS_ATTACH_CGROUP |
++ KDBUS_ATTACH_AUDIT |
++ KDBUS_ATTACH_CAPS |
++ KDBUS_ATTACH_EXE);
++}
++
+ /**
+- * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender
+- * and a receiver
+- * @sender: Sending connection
+- * @receiver: Receiving connection
++ * kdbus_meta_get_mask() - calculate attach flags mask for metadata request
++ * @prv_pid: pid of metadata provider
++ * @prv_mask: mask of metadata the provide grants unchecked
++ * @req_pid: pid of metadata requestor
++ * @req_cred: credentials of metadata requestor
++ * @req_mask: mask of metadata that is requested
+ *
+- * Return: the attach flags both the sender and the receiver have opted-in
+- * for.
++ * This calculates the metadata items that the requestor @req_pid can access
++ * from the metadata provider @prv_pid. This permission check consists of
++ * several different parts:
++ * - Providers can grant metadata items unchecked. Regardless of their type,
++ * they're always granted to the requestor. This mask is passed as @prv_mask.
++ * - Basic items (credentials and connection metadata) are granted implicitly
++ * to everyone. They're publicly available to any bus-user that can see the
++ * provider.
++ * - Process credentials that are not granted implicitly follow the same
++ * permission checks as /proc. This means, we always assume a requestor
++ * process has access to their *own* /proc mount, if they have access to
++ * kdbusfs.
++ *
++ * Return: Mask of metadata that is granted.
++ */
++static u64 kdbus_meta_get_mask(struct pid *prv_pid, u64 prv_mask,
++ struct pid *req_pid,
++ const struct cred *req_cred, u64 req_mask)
++{
++ u64 missing, impl_mask, proc_mask = 0;
++
++ /*
++ * Connection metadata and basic unix process credentials are
++ * transmitted implicitly, and cannot be suppressed. Both are required
++ * to perform user-space policies on the receiver-side. Furthermore,
++ * connection metadata is public state, anyway, and unix credentials
++ * are needed for UDS-compatibility. We extend them slightly by
++ * auxiliary groups and additional uids/gids/pids.
++ */
++ impl_mask = /* connection metadata */
++ KDBUS_ATTACH_CONN_DESCRIPTION |
++ KDBUS_ATTACH_TIMESTAMP |
++ KDBUS_ATTACH_NAMES |
++ /* credentials and pids */
++ KDBUS_ATTACH_AUXGROUPS |
++ KDBUS_ATTACH_CREDS |
++ KDBUS_ATTACH_PIDS;
++
++ /*
++ * Calculate the set of metadata that is not granted implicitly nor by
++ * the sender, but still requested by the receiver. If any are left,
++ * perform rather expensive /proc access checks for them.
++ */
++ missing = req_mask & ~((prv_mask | impl_mask) & req_mask);
++ if (missing)
++ proc_mask = kdbus_meta_proc_mask(prv_pid, req_pid, req_cred,
++ missing);
++
++ return (prv_mask | impl_mask | proc_mask) & req_mask;
++}
++
++/**
++ */
++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask)
++{
++ return kdbus_meta_get_mask(conn->pid,
++ atomic64_read(&conn->attach_flags_send),
++ task_pid(current),
++ current_cred(),
++ mask);
++}
++
++/**
+ */
+-u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
+- const struct kdbus_conn *receiver)
++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd,
++ const struct kdbus_conn *rcv)
+ {
+- return atomic64_read(&sender->attach_flags_send) &
+- atomic64_read(&receiver->attach_flags_recv);
++ return kdbus_meta_get_mask(task_pid(current),
++ atomic64_read(&snd->attach_flags_send),
++ rcv->pid,
++ rcv->cred,
++ atomic64_read(&rcv->attach_flags_recv));
+ }
+diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h
+index 8fb2a9f7f82e..dba7cc7fdbcb 100644
+--- a/ipc/kdbus/metadata.h
++++ b/ipc/kdbus/metadata.h
+@@ -79,7 +79,8 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
+ u64 mask,
+ struct kdbus_item **out_items,
+ size_t *out_size);
+-u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender,
+- const struct kdbus_conn *receiver);
++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask);
++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd,
++ const struct kdbus_conn *rcv);
+
+ #endif
+--
+2.4.3
+
+
+From 087d17ac489a3c8f7c35bb5faf4c1bc858fc0978 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 6 Jul 2015 16:52:44 +0200
+Subject: [PATCH 31/34] kdbus: drop redundant ns pointers
+
+We already pin 'cred' and 'pid', so they provide the same information as
+we store in 'user_ns' and 'pid_ns'. Drop the redundant information to
+reduce memory consumption of kdbus_conn.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ ipc/kdbus/connection.c | 4 ----
+ ipc/kdbus/connection.h | 4 ----
+ ipc/kdbus/metadata.c | 4 ++--
+ 3 files changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c
+index 461b8d66b2b9..d94b417e0f32 100644
+--- a/ipc/kdbus/connection.c
++++ b/ipc/kdbus/connection.c
+@@ -130,8 +130,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged,
+ atomic_set(&conn->lost_count, 0);
+ INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work);
+ conn->cred = get_current_cred();
+- conn->user_ns = get_user_ns(current_user_ns());
+- conn->pid_ns = get_pid_ns(task_active_pid_ns(current));
+ conn->pid = get_pid(task_pid(current));
+ get_fs_root(current->fs, &conn->root_path);
+ init_waitqueue_head(&conn->wait);
+@@ -284,8 +282,6 @@ static void __kdbus_conn_free(struct kref *kref)
+ kdbus_ep_unref(conn->ep);
+ path_put(&conn->root_path);
+ put_pid(conn->pid);
+- put_pid_ns(conn->pid_ns);
+- put_user_ns(conn->user_ns);
+ put_cred(conn->cred);
+ kfree(conn->description);
+ kfree(conn->quota);
+diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h
+index 9a1b13d69085..5ee864eb0e41 100644
+--- a/ipc/kdbus/connection.h
++++ b/ipc/kdbus/connection.h
+@@ -59,8 +59,6 @@ struct kdbus_staging;
+ * @pool: The user's buffer to receive messages
+ * @user: Owner of the connection
+ * @cred: The credentials of the connection at creation time
+- * @user_ns: User namespace at creation time
+- * @pid_ns: Pid namespace at creation time
+ * @pid: Pid at creation time
+ * @root_path: Root path at creation time
+ * @name_count: Number of owned well-known names
+@@ -101,8 +99,6 @@ struct kdbus_conn {
+ struct kdbus_pool *pool;
+ struct kdbus_user *user;
+ const struct cred *cred;
+- struct user_namespace *user_ns;
+- struct pid_namespace *pid_ns;
+ struct pid *pid;
+ struct path root_path;
+ atomic_t name_count;
+diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c
+index 5150932cb257..d4973a90a81e 100644
+--- a/ipc/kdbus/metadata.c
++++ b/ipc/kdbus/metadata.c
+@@ -896,8 +896,8 @@ static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter,
+ static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem,
+ size_t size)
+ {
+- struct user_namespace *user_ns = staging->conn->user_ns;
+- struct pid_namespace *pid_ns = staging->conn->pid_ns;
++ struct user_namespace *user_ns = staging->conn->cred->user_ns;
++ struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid);
+ struct kdbus_item *item = NULL, *items = mem;
+ u8 *end, *owned_names_end = NULL;
+
+--
+2.4.3
+
+
+From c61382ef278eb8569c87e4be3077f3f9f1f2fc49 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 6 Jul 2015 16:54:36 +0200
+Subject: [PATCH 32/34] kdbus: allow match rules on msg->dst_id
+
+This patch extends kdbus MATCH rules to allow matching on the destination
+of a message. We add a KDBUS_ITEM_DST_ID type which takes a u64 and
+matches on msg->dst_id.
+
+This is required for dbus1 compatibility, as dbus1 does not apply MATCH
+rules to unicast signals. Therefore, this field allows to match on
+unicasts directed to the owning connection.
+
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+---
+ include/uapi/linux/kdbus.h | 1 +
+ ipc/kdbus/item.c | 1 +
+ ipc/kdbus/match.c | 18 +++++++++++++++---
+ 3 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h
+index 00a6e142c977..ecffc6b13c3e 100644
+--- a/include/uapi/linux/kdbus.h
++++ b/include/uapi/linux/kdbus.h
+@@ -374,6 +374,7 @@ enum kdbus_item_type {
+ KDBUS_ITEM_ATTACH_FLAGS_RECV,
+ KDBUS_ITEM_ID,
+ KDBUS_ITEM_NAME,
++ KDBUS_ITEM_DST_ID,
+
+ /* keep these item types in sync with KDBUS_ATTACH_* flags */
+ _KDBUS_ITEM_ATTACH_BASE = 0x1000,
+diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c
+index e763083cc16c..ce78dba03426 100644
+--- a/ipc/kdbus/item.c
++++ b/ipc/kdbus/item.c
+@@ -147,6 +147,7 @@ int kdbus_item_validate(const struct kdbus_item *item)
+ case KDBUS_ITEM_ATTACH_FLAGS_SEND:
+ case KDBUS_ITEM_ATTACH_FLAGS_RECV:
+ case KDBUS_ITEM_ID:
++ case KDBUS_ITEM_DST_ID:
+ if (payload_size != sizeof(u64))
+ return -EINVAL;
+ break;
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+index 3ae224ff9f3f..d1b300769014 100644
+--- a/ipc/kdbus/match.c
++++ b/ipc/kdbus/match.c
+@@ -78,6 +78,7 @@ struct kdbus_bloom_mask {
+ * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE},
+ * KDBUS_ITEM_ID_REMOVE
+ * @src_id: ID to match against, used with KDBUS_ITEM_ID
++ * @dst_id: Message destination ID, used with KDBUS_ITEM_DST_ID
+ * @rules_entry: Entry in the entry's rules list
+ */
+ struct kdbus_match_rule {
+@@ -90,6 +91,7 @@ struct kdbus_match_rule {
+ u64 new_id;
+ };
+ u64 src_id;
++ u64 dst_id;
+ };
+ struct list_head rules_entry;
+ };
+@@ -112,6 +114,7 @@ static void kdbus_match_rule_free(struct kdbus_match_rule *rule)
+ break;
+
+ case KDBUS_ITEM_ID:
++ case KDBUS_ITEM_DST_ID:
+ case KDBUS_ITEM_ID_ADD:
+ case KDBUS_ITEM_ID_REMOVE:
+ break;
+@@ -215,6 +218,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r,
+ return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c);
+ case KDBUS_ITEM_ID:
+ return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY;
++ case KDBUS_ITEM_DST_ID:
++ return r->dst_id == s->msg->dst_id ||
++ r->dst_id == KDBUS_MATCH_ID_ANY;
+ case KDBUS_ITEM_NAME:
+ return kdbus_conn_has_name(c, r->name);
+ default:
+@@ -328,6 +334,7 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb,
+ * KDBUS_ITEM_BLOOM_MASK: A bloom mask
+ * KDBUS_ITEM_NAME: A connection's source name
+ * KDBUS_ITEM_ID: A connection ID
++ * KDBUS_ITEM_DST_ID: A connection ID
+ * KDBUS_ITEM_NAME_ADD:
+ * KDBUS_ITEM_NAME_REMOVE:
+ * KDBUS_ITEM_NAME_CHANGE: Well-known name changes, carry
+@@ -339,9 +346,9 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb,
+ * For kdbus_notify_{id,name}_change structs, only the ID and name fields
+ * are looked at when adding an entry. The flags are unused.
+ *
+- * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME and KDBUS_ITEM_ID
+- * are used to match messages from userspace, while the others apply to
+- * kernel-generated notifications.
++ * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME, KDBUS_ITEM_ID,
++ * and KDBUS_ITEM_DST_ID are used to match messages from userspace, while the
++ * others apply to kernel-generated notifications.
+ *
+ * Return: >=0 on success, negative error code on failure.
+ */
+@@ -358,6 +365,7 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp)
+ { .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true },
+ { .type = KDBUS_ITEM_NAME, .multiple = true },
+ { .type = KDBUS_ITEM_ID, .multiple = true },
++ { .type = KDBUS_ITEM_DST_ID, .multiple = true },
+ { .type = KDBUS_ITEM_NAME_ADD, .multiple = true },
+ { .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true },
+ { .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true },
+@@ -440,6 +448,10 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp)
+ rule->src_id = item->id;
+ break;
+
++ case KDBUS_ITEM_DST_ID:
++ rule->dst_id = item->id;
++ break;
++
+ case KDBUS_ITEM_NAME_ADD:
+ case KDBUS_ITEM_NAME_REMOVE:
+ case KDBUS_ITEM_NAME_CHANGE:
+--
+2.4.3
+
+
+From cf23304185c5787d875971cc730e29637d3f4d7e Mon Sep 17 00:00:00 2001
+From: Masanari Iida <standby24x7@gmail.com>
+Date: Fri, 10 Jul 2015 21:55:33 +0900
+Subject: [PATCH 33/34] kdbus: Fix typo in ipc/kdbus
+
+This patch fix spelling typos found in ipc/kdbus
+
+Signed-off-by: Masanari Iida <standby24x7@gmail.com>
+Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ ipc/kdbus/endpoint.c | 2 +-
+ ipc/kdbus/endpoint.h | 4 ++--
+ ipc/kdbus/fs.c | 2 +-
+ ipc/kdbus/match.c | 2 +-
+ ipc/kdbus/node.c | 4 ++--
+ ipc/kdbus/policy.c | 2 +-
+ ipc/kdbus/pool.c | 2 +-
+ 7 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c
+index 9a95a5ea84d7..977964dbb44a 100644
+--- a/ipc/kdbus/endpoint.c
++++ b/ipc/kdbus/endpoint.c
+@@ -78,7 +78,7 @@ static void kdbus_ep_release(struct kdbus_node *node, bool was_active)
+ * @gid: The gid of the node
+ * @is_custom: Whether this is a custom endpoint
+ *
+- * This function will create a new enpoint with the given
++ * This function will create a new endpoint with the given
+ * name and properties for a given bus.
+ *
+ * Return: a new kdbus_ep on success, ERR_PTR on failure.
+diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h
+index d31954bfba2c..bc1b94a70f93 100644
+--- a/ipc/kdbus/endpoint.h
++++ b/ipc/kdbus/endpoint.h
+@@ -25,7 +25,7 @@ struct kdbus_bus;
+ struct kdbus_user;
+
+ /**
+- * struct kdbus_ep - enpoint to access a bus
++ * struct kdbus_ep - endpoint to access a bus
+ * @node: The kdbus node
+ * @lock: Endpoint data lock
+ * @bus: Bus behind this endpoint
+@@ -33,7 +33,7 @@ struct kdbus_user;
+ * @policy_db: Uploaded policy
+ * @conn_list: Connections of this endpoint
+ *
+- * An enpoint offers access to a bus; the default endpoint node name is "bus".
++ * An endpoint offers access to a bus; the default endpoint node name is "bus".
+ * Additional custom endpoints to the same bus can be created and they can
+ * carry their own policies/filters.
+ */
+diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c
+index 205a3adaa2ab..09c480924b9e 100644
+--- a/ipc/kdbus/fs.c
++++ b/ipc/kdbus/fs.c
+@@ -74,7 +74,7 @@ static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx)
+ * closest node to that position and cannot use our node pointer. This
+ * means iterating the rb-tree to find the closest match and start over
+ * from there.
+- * Note that hash values are not neccessarily unique. Therefore, llseek
++ * Note that hash values are not necessarily unique. Therefore, llseek
+ * is not guaranteed to seek to the same node that you got when you
+ * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe,
+ * though. We could use the inode-number as position, but this would
+diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c
+index d1b300769014..4ee6a1f2e1bc 100644
+--- a/ipc/kdbus/match.c
++++ b/ipc/kdbus/match.c
+@@ -66,7 +66,7 @@ struct kdbus_bloom_mask {
+
+ /**
+ * struct kdbus_match_rule - a rule appended to a match entry
+- * @type: An item type to match agains
++ * @type: An item type to match against
+ * @bloom_mask: Bloom mask to match a message's filter against, used
+ * with KDBUS_ITEM_BLOOM_MASK
+ * @name: Name to match against, used with KDBUS_ITEM_NAME,
+diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c
+index 0d65c65d2bde..89f58bc85433 100644
+--- a/ipc/kdbus/node.c
++++ b/ipc/kdbus/node.c
+@@ -120,7 +120,7 @@
+ * new active references can be acquired.
+ * Once all active references are dropped, the node is considered 'drained'. Now
+ * kdbus_node_deactivate() is called on each child of the node before we
+- * continue deactvating our node. That is, once all children are entirely
++ * continue deactivating our node. That is, once all children are entirely
+ * deactivated, we call ->release_cb() of our node. ->release_cb() can release
+ * any resources on that node which are bound to the "active" state of a node.
+ * When done, we unlink the node from its parent rb-tree, mark it as
+@@ -637,7 +637,7 @@ void kdbus_node_deactivate(struct kdbus_node *node)
+ kdbus_fs_flush(pos);
+
+ /*
+- * If the node was activated and somone subtracted BIAS
++ * If the node was activated and someone subtracted BIAS
+ * from it to deactivate it, we, and only us, are
+ * responsible to release the extra ref-count that was
+ * taken once in kdbus_node_activate().
+diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c
+index dd7fffaafa84..f2618e15e78d 100644
+--- a/ipc/kdbus/policy.c
++++ b/ipc/kdbus/policy.c
+@@ -344,7 +344,7 @@ err:
+ * In order to allow atomic replacement of rules, the function first removes
+ * all entries that have been created for the given owner previously.
+ *
+- * Callers to this function must make sur that the owner is a custom
++ * Callers to this function must make sure that the owner is a custom
+ * endpoint, or if the endpoint is a default endpoint, then it must be
+ * either a policy holder or an activator.
+ *
+diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c
+index 45dcdea505f4..63ccd55713c7 100644
+--- a/ipc/kdbus/pool.c
++++ b/ipc/kdbus/pool.c
+@@ -44,7 +44,7 @@
+ * The receiver's buffer, managed as a pool of allocated and free
+ * slices containing the queued messages.
+ *
+- * Messages sent with KDBUS_CMD_SEND are copied direcly by the
++ * Messages sent with KDBUS_CMD_SEND are copied directly by the
+ * sending process into the receiver's pool.
+ *
+ * Messages received with KDBUS_CMD_RECV just return the offset
+--
+2.4.3
+
+
+From eee8b5b3ceaeca1b1b998552cd6c9f9dea8938e5 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Tue, 14 Jul 2015 20:12:28 +0200
+Subject: [PATCH 34/34] kdbus: properly reset metadata iovecs on multicasts
+
+If a message is sent to multiple destinations, each destination might
+request a different set of metadata. Hence, we cannot rely on each one
+requesting at least a single bit.
+
+Fix the message exporter to properly reset the metadata iovec on each
+emit-iteration. Otherwise, we might end up scanning random heap memory if
+a following destination does not request metadata.
+
+Reported-by: Jan Alexander Steffens <jan.steffens@gmail.com>
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ ipc/kdbus/message.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c
+index 64763ead693c..3520f45875df 100644
+--- a/ipc/kdbus/message.c
++++ b/ipc/kdbus/message.c
+@@ -946,6 +946,16 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging,
+ ++v;
+
+ msg_size = KDBUS_ALIGN8(msg_size) + meta_size;
++ } else {
++ /* metadata items */
++ v->iov_len = 0;
++ v->iov_base = (void __user *)zeros;
++ ++v;
++
++ /* padding after metadata */
++ v->iov_len = 0;
++ v->iov_base = (void __user *)zeros;
++ ++v;
+ }
+
+ /* ... payload iovecs are already filled in ... */
+--
+2.4.3
+