[PATCH 10/14] kdbus: add name registry implementation

2015-03-09 Thread Greg Kroah-Hartman
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

2015-03-09 Thread Greg Kroah-Hartman
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);
+