[PATCH 10/14] kdbus: add name registry implementation
From: Daniel Mack This patch adds the name registry implementation. Each bus instantiates a name registry to resolve well-known names into unique connection IDs for message delivery. The registry will be queried when a message is sent with kdbus_msg.dst_id set to KDBUS_DST_ID_NAME, or when a registry dump is requested. It's important to have this registry implemented in the kernel to implement lookups and take-overs in a race-free way. Signed-off-by: Daniel Mack Signed-off-by: David Herrmann Signed-off-by: Djalal Harouni Signed-off-by: Greg Kroah-Hartman --- ipc/kdbus/names.c | 772 ++ ipc/kdbus/names.h | 74 ++ 2 files changed, 846 insertions(+) create mode 100644 ipc/kdbus/names.c create mode 100644 ipc/kdbus/names.h diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c new file mode 100644 index ..657008e1bb37 --- /dev/null +++ b/ipc/kdbus/names.c @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2013-2015 Kay Sievers + * Copyright (C) 2013-2015 Greg Kroah-Hartman + * Copyright (C) 2013-2015 Daniel Mack + * Copyright (C) 2013-2015 David Herrmann + * Copyright (C) 2013-2015 Linux Foundation + * Copyright (C) 2014-2015 Djalal Harouni + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "connection.h" +#include "endpoint.h" +#include "handle.h" +#include "item.h" +#include "names.h" +#include "notify.h" +#include "policy.h" + +struct kdbus_name_pending { + u64 flags; + struct kdbus_conn *conn; + struct kdbus_name_entry *name; + struct list_head conn_entry; + struct list_head name_entry; +}; + +static int kdbus_name_pending_new(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + struct kdbus_name_pending *p; + + kdbus_conn_assert_active(conn); + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->flags = flags; + p->conn = conn; + p->name = e; + list_add_tail(>conn_entry, >names_queue_list); + list_add_tail(>name_entry, >queue); + + return 0; +} + +static void kdbus_name_pending_free(struct kdbus_name_pending *p) +{ + if (!p) + return; + + list_del(>name_entry); + list_del(>conn_entry); + kfree(p); +} + +static struct kdbus_name_entry * +kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, const char *name) +{ + struct kdbus_name_entry *e; + size_t namelen; + + namelen = strlen(name); + + e = kmalloc(sizeof(*e) + namelen + 1, GFP_KERNEL); + if (!e) + return ERR_PTR(-ENOMEM); + + e->name_id = ++r->name_seq_last; + e->flags = 0; + e->conn = NULL; + e->activator = NULL; + INIT_LIST_HEAD(>queue); + INIT_LIST_HEAD(>conn_entry); + hash_add(r->entries_hash, >hentry, hash); + memcpy(e->name, name, namelen + 1); + + return e; +} + +static void kdbus_name_entry_free(struct kdbus_name_entry *e) +{ + if (!e) + return; + + WARN_ON(!list_empty(>conn_entry)); + WARN_ON(!list_empty(>queue)); + WARN_ON(e->activator); + WARN_ON(e->conn); + + hash_del(>hentry); + kfree(e); +} + +static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + WARN_ON(e->conn); + + e->conn = kdbus_conn_ref(conn); + e->flags = flags; + atomic_inc(>name_count); + list_add_tail(>conn_entry, >conn->names_list); +} + +static void kdbus_name_entry_remove_owner(struct kdbus_name_entry *e) +{ + WARN_ON(!e->conn); + + list_del_init(>conn_entry); + atomic_dec(>conn->name_count); + e->flags = 0; + e->conn = kdbus_conn_unref(e->conn); +} + +static void kdbus_name_entry_replace_owner(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + if (WARN_ON(!e->conn) || WARN_ON(conn == e->conn)) + return; + + kdbus_notify_name_change(conn->ep->bus, KDBUS_ITEM_NAME_CHANGE, +e->conn->id, conn->id, +e->flags, flags, e->name); + kdbus_name_entry_remove_owner(e); + kdbus_name_entry_set_owner(e, conn, flags); +} + +/** + * kdbus_name_is_valid() - check if a name is valid + * @p: The name to check + * @allow_wildcard:Whether or not to allow a wildcard name + * + * A name is valid if all of the following criterias are met: + * + * - The name
[PATCH 10/14] kdbus: add name registry implementation
From: Daniel Mack dan...@zonque.org This patch adds the name registry implementation. Each bus instantiates a name registry to resolve well-known names into unique connection IDs for message delivery. The registry will be queried when a message is sent with kdbus_msg.dst_id set to KDBUS_DST_ID_NAME, or when a registry dump is requested. It's important to have this registry implemented in the kernel to implement lookups and take-overs in a race-free way. Signed-off-by: Daniel Mack dan...@zonque.org Signed-off-by: David Herrmann dh.herrm...@gmail.com Signed-off-by: Djalal Harouni tix...@opendz.org Signed-off-by: Greg Kroah-Hartman gre...@linuxfoundation.org --- ipc/kdbus/names.c | 772 ++ ipc/kdbus/names.h | 74 ++ 2 files changed, 846 insertions(+) create mode 100644 ipc/kdbus/names.c create mode 100644 ipc/kdbus/names.h diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c new file mode 100644 index ..657008e1bb37 --- /dev/null +++ b/ipc/kdbus/names.c @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2013-2015 Kay Sievers + * Copyright (C) 2013-2015 Greg Kroah-Hartman gre...@linuxfoundation.org + * Copyright (C) 2013-2015 Daniel Mack dan...@zonque.org + * Copyright (C) 2013-2015 David Herrmann dh.herrm...@gmail.com + * Copyright (C) 2013-2015 Linux Foundation + * Copyright (C) 2014-2015 Djalal Harouni tix...@opendz.org + * + * kdbus is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#include linux/ctype.h +#include linux/fs.h +#include linux/hash.h +#include linux/idr.h +#include linux/init.h +#include linux/module.h +#include linux/mutex.h +#include linux/rwsem.h +#include linux/sched.h +#include linux/slab.h +#include linux/uaccess.h +#include linux/uio.h + +#include bus.h +#include connection.h +#include endpoint.h +#include handle.h +#include item.h +#include names.h +#include notify.h +#include policy.h + +struct kdbus_name_pending { + u64 flags; + struct kdbus_conn *conn; + struct kdbus_name_entry *name; + struct list_head conn_entry; + struct list_head name_entry; +}; + +static int kdbus_name_pending_new(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + struct kdbus_name_pending *p; + + kdbus_conn_assert_active(conn); + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p-flags = flags; + p-conn = conn; + p-name = e; + list_add_tail(p-conn_entry, conn-names_queue_list); + list_add_tail(p-name_entry, e-queue); + + return 0; +} + +static void kdbus_name_pending_free(struct kdbus_name_pending *p) +{ + if (!p) + return; + + list_del(p-name_entry); + list_del(p-conn_entry); + kfree(p); +} + +static struct kdbus_name_entry * +kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, const char *name) +{ + struct kdbus_name_entry *e; + size_t namelen; + + namelen = strlen(name); + + e = kmalloc(sizeof(*e) + namelen + 1, GFP_KERNEL); + if (!e) + return ERR_PTR(-ENOMEM); + + e-name_id = ++r-name_seq_last; + e-flags = 0; + e-conn = NULL; + e-activator = NULL; + INIT_LIST_HEAD(e-queue); + INIT_LIST_HEAD(e-conn_entry); + hash_add(r-entries_hash, e-hentry, hash); + memcpy(e-name, name, namelen + 1); + + return e; +} + +static void kdbus_name_entry_free(struct kdbus_name_entry *e) +{ + if (!e) + return; + + WARN_ON(!list_empty(e-conn_entry)); + WARN_ON(!list_empty(e-queue)); + WARN_ON(e-activator); + WARN_ON(e-conn); + + hash_del(e-hentry); + kfree(e); +} + +static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + WARN_ON(e-conn); + + e-conn = kdbus_conn_ref(conn); + e-flags = flags; + atomic_inc(conn-name_count); + list_add_tail(e-conn_entry, e-conn-names_list); +} + +static void kdbus_name_entry_remove_owner(struct kdbus_name_entry *e) +{ + WARN_ON(!e-conn); + + list_del_init(e-conn_entry); + atomic_dec(e-conn-name_count); + e-flags = 0; + e-conn = kdbus_conn_unref(e-conn); +} + +static void kdbus_name_entry_replace_owner(struct kdbus_name_entry *e, + struct kdbus_conn *conn, u64 flags) +{ + if (WARN_ON(!e-conn) || WARN_ON(conn == e-conn)) + return; + + kdbus_notify_name_change(conn-ep-bus, KDBUS_ITEM_NAME_CHANGE, +e-conn-id, conn-id, +e-flags, flags, e-name); + kdbus_name_entry_remove_owner(e); +