From da4e5658e3a188cbd2fe493c337e5dd4904a7cee Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 8 May 2013 00:13:08 +0200 Subject: rename files: ns -> namespace, ep -> endpoint --- Makefile | 4 +- bus.c | 4 +- connection.c | 4 +- endpoint.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ endpoint.h | 54 ++++++++++ ep.c | 299 ------------------------------------------------------- ep.h | 54 ---------- main.c | 2 +- match.c | 2 +- message.c | 2 +- names.c | 2 +- namespace.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ namespace.h | 54 ++++++++++ notify.c | 2 +- ns.c | 316 ----------------------------------------------------------- ns.h | 54 ---------- 16 files changed, 734 insertions(+), 734 deletions(-) create mode 100644 endpoint.c create mode 100644 endpoint.h delete mode 100644 ep.c delete mode 100644 ep.h create mode 100644 namespace.c create mode 100644 namespace.h delete mode 100644 ns.c delete mode 100644 ns.h diff --git a/Makefile b/Makefile index 28ea15118f9..716d971bc0f 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,13 @@ kdbus-y := \ bus.o \ connection.o \ buffer.o \ - ep.o \ + endpoint.o \ main.o \ match.o \ message.o \ names.o \ notify.o \ - ns.o \ + namespace.o \ policy.o # obj-$(CONFIG_KDBUS) += kdbus.o diff --git a/bus.c b/bus.c index f4c25624d42..7a68759ef10 100644 --- a/bus.c +++ b/bus.c @@ -26,8 +26,8 @@ #include "bus.h" #include "connection.h" #include "names.h" -#include "ep.h" -#include "ns.h" +#include "endpoint.h" +#include "namespace.h" /** * kdbus_bus_unref() - increase the reference counter of a kdbus_bus diff --git a/connection.c b/connection.c index c5f528e3f05..c65f1ab0da2 100644 --- a/connection.c +++ b/connection.c @@ -34,8 +34,8 @@ #include "buffer.h" #include "message.h" #include "notify.h" -#include "ns.h" -#include "ep.h" +#include "namespace.h" +#include "endpoint.h" #include "bus.h" #include "match.h" #include "names.h" diff --git a/endpoint.c b/endpoint.c new file mode 100644 index 00000000000..29aedd36fd6 --- /dev/null +++ b/endpoint.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "endpoint.h" +#include "bus.h" +#include "policy.h" +#include "namespace.h" + +/* endpoints are by default owned by the bus owner */ +static char *kdbus_devnode_ep(struct device *dev, umode_t *mode +#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID + , kuid_t *uid, kgid_t *gid) +#else + ) +#endif +{ + struct kdbus_ep *ep = dev_get_drvdata(dev); + + if (mode) + *mode = ep->mode; +#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID + if (uid) + *uid = ep->uid; + if (gid) + *gid = ep->gid; +#endif + return NULL; +} + +static struct device_type kdbus_devtype_ep = { + .name = "ep", + .release = kdbus_dev_release, + .devnode = kdbus_devnode_ep, +}; + +struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep) +{ + kref_get(&ep->kref); + return ep; +} + +void kdbus_ep_disconnect(struct kdbus_ep *ep) +{ + if (ep->disconnected) + return; + ep->disconnected = true; + + if (ep->dev) { + device_unregister(ep->dev); + ep->dev = NULL; + } + if (ep->minor > 0) { + idr_remove(&ep->bus->ns->idr, ep->minor); + ep->minor = 0; + } + pr_debug("closing endpoint %s/%s/%s\n", + ep->bus->ns->devpath, ep->bus->name, ep->name); +} + +static void __kdbus_ep_free(struct kref *kref) +{ + struct kdbus_ep *ep = container_of(kref, struct kdbus_ep, kref); + + mutex_lock(&ep->bus->lock); + kdbus_ep_disconnect(ep); + pr_debug("clean up endpoint %s/%s/%s\n", + ep->bus->ns->devpath, ep->bus->name, ep->name); + mutex_unlock(&ep->bus->lock); + + kdbus_bus_unref(ep->bus); + if (ep->policy_db) + kdbus_policy_db_unref(ep->policy_db); + + kfree(ep->name); + kfree(ep); +} + +void kdbus_ep_unref(struct kdbus_ep *ep) +{ + kref_put(&ep->kref, __kdbus_ep_free); +} + +static struct kdbus_ep *kdbus_ep_find(struct kdbus_bus *bus, const char *name) +{ + struct kdbus_ep *ep = NULL; + struct kdbus_ep *e; + + mutex_lock(&bus->lock); + list_for_each_entry(e, &bus->ep_list, bus_entry) { + if (strcmp(ep->name, name) != 0) + continue; + + ep = kdbus_ep_ref(e); + } + mutex_unlock(&bus->lock); + + return ep; +} + +int kdbus_ep_new(struct kdbus_bus *bus, const char *name, umode_t mode, + kuid_t uid, kgid_t gid, bool policy_open) +{ + struct kdbus_ep *e; + int ret; + int i; + + e = kdbus_ep_find(bus, name); + if (e) { + kdbus_ep_unref(e); + return -EEXIST; + } + + e = kzalloc(sizeof(struct kdbus_ep), GFP_KERNEL); + if (!e) + return -ENOMEM; + + mutex_lock(&bus->ns->lock); + kref_init(&e->kref); + e->mode = mode > 0 ? mode : 0600; + e->uid = uid; + e->gid = gid; + + e->name = kstrdup(name, GFP_KERNEL); + if (!e->name) { + ret = -ENOMEM; + goto exit_unlock; + } + + /* register minor in our endpoint map */ + i = idr_alloc(&bus->ns->idr, e, 1, 0, GFP_KERNEL); + if (i <= 0) { + ret = i; + goto exit_unlock; + } + e->minor = i; + + /* get id for this endpoint from bus */ + mutex_lock(&bus->lock); + e->id = bus->ep_id_next++; + mutex_unlock(&bus->lock); + + /* register bus endpoint device */ + e->dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!e->dev) { + ret = -ENOMEM; + goto exit_unlock; + } + + dev_set_name(e->dev, "%s/%s/%s", bus->ns->devpath, bus->name, name); + e->dev->bus = &kdbus_subsys; + e->dev->type = &kdbus_devtype_ep; + e->dev->devt = MKDEV(bus->ns->major, e->minor); + dev_set_drvdata(e->dev, e); + ret = device_register(e->dev); + if (ret < 0) { + put_device(e->dev); + e->dev = NULL; + } + + /* Link this endpoint to the bus it is on */ + e->bus = kdbus_bus_ref(bus); + list_add_tail(&e->bus_entry, &bus->ep_list); + + /* install policy */ + e->policy_open = policy_open; + if (!policy_open) { + e->policy_db = kdbus_policy_db_new(); + if (!e->policy_db) { + ret = -ENOMEM; + goto exit_unlock; + } + } + + init_waitqueue_head(&e->wait); + INIT_LIST_HEAD(&e->connection_list); + + mutex_unlock(&bus->ns->lock); + + pr_debug("created endpoint %llu for bus '%s/%s/%s'\n", + (unsigned long long)e->id, bus->ns->devpath, bus->name, name); + return 0; + +exit_unlock: + mutex_unlock(&bus->ns->lock); + kdbus_ep_unref(e); + return ret; +} + +int kdbus_ep_remove(struct kdbus_ep *ep) +{ + struct kdbus_bus *bus = ep->bus; + + mutex_lock(&bus->ns->lock); + device_unregister(ep->dev); + list_del(&ep->bus_entry); + kdbus_ep_unref(ep); + mutex_unlock(&bus->ns->lock); + kdbus_bus_unref(bus); + return 0; +} + +int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake) +{ + u64 size; + struct kdbus_cmd_ep_kmake *km; + const struct kdbus_item *item; + int ret; + + if (kdbus_size_get_user(size, buf, struct kdbus_cmd_ep_make)) + return -EFAULT; + + if (size < sizeof(struct kdbus_cmd_ep_make) || size > KDBUS_MAKE_MAX_SIZE) + return -EMSGSIZE; + + km = kmalloc(sizeof(struct kdbus_cmd_ep_kmake) + size, GFP_KERNEL); + if (!km) + return -ENOMEM; + + memset(km, 0, offsetof(struct kdbus_cmd_ep_kmake, make)); + if (copy_from_user(&km->make, buf, size)) { + ret = -EFAULT; + goto exit; + } + + KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { + /* empty data records are invalid */ + if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + ret = -EINVAL; + goto exit; + } + + switch (item->type) { + case KDBUS_MAKE_NAME: + if (km->name) { + ret = -EEXIST; + goto exit; + } + + if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { + ret = -EINVAL; + goto exit; + } + + if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { + ret = -ENAMETOOLONG; + goto exit; + } + + if (!kdbus_validate_nul(item->str, + item->size - KDBUS_ITEM_HEADER_SIZE)) { + ret = -EINVAL; + goto exit; + } + + km->name = item->str; + continue; + + default: + ret = -ENOTSUPP; + goto exit; + } + } + + /* expect correct padding and size values */ + if ((char *)item - ((char *)&km->make + km->make.size) >= 8) + return EINVAL; + + if (!km->name) { + ret = -EBADMSG; + goto exit; + } + + *kmake = km; + return 0; + +exit: + return ret; +} diff --git a/endpoint.h b/endpoint.h new file mode 100644 index 00000000000..6e7e9a12fb6 --- /dev/null +++ b/endpoint.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * + * 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. + */ + +#ifndef __KDBUS_EP_H +#define __KDBUS_EP_H + +#include "internal.h" + +/* + * kdbus endpoint + * - offers access to a bus, the default device node name is "bus" + * - additional endpoints can carry a specific policy/filters + */ +struct kdbus_ep { + struct kref kref; /* reference count */ + bool disconnected; /* invalidated data */ + struct kdbus_bus *bus; /* bus behind this endpoint */ + const char *name; /* name, prefixed with uid */ + u64 id; /* id of this endpoint on the bus */ + unsigned int minor; /* minor of this endpoint in the namespace major */ + struct device *dev; /* device node of this endpoint */ + umode_t mode; /* file mode of this endpoint device node */ + kuid_t uid; /* uid owning this endpoint */ + kgid_t gid; /* gid owning this endpoint */ + struct list_head bus_entry; /* list of endpoints for this bus */ + struct list_head message_list; /* messages in flight for this endpoint */ + struct list_head connection_list; + wait_queue_head_t wait; /* wake up this endpoint */ + struct kdbus_policy_db *policy_db; + bool policy_open:1; +}; + +struct kdbus_cmd_ep_kmake { + const char *name; + struct kdbus_cmd_ep_make make; +}; + +struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); +void kdbus_ep_unref(struct kdbus_ep *ep); + +int kdbus_ep_new(struct kdbus_bus *bus, const char *name, + umode_t mode, kuid_t uid, kgid_t gid, bool policy); +int kdbus_ep_remove(struct kdbus_ep *ep); +void kdbus_ep_disconnect(struct kdbus_ep *ep); +int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake); +#endif diff --git a/ep.c b/ep.c deleted file mode 100644 index d5b9805b299..00000000000 --- a/ep.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2013 Kay Sievers - * Copyright (C) 2013 Greg Kroah-Hartman - * Copyright (C) 2013 Linux Foundation - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ep.h" -#include "bus.h" -#include "policy.h" -#include "ns.h" - -/* endpoints are by default owned by the bus owner */ -static char *kdbus_devnode_ep(struct device *dev, umode_t *mode -#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID - , kuid_t *uid, kgid_t *gid) -#else - ) -#endif -{ - struct kdbus_ep *ep = dev_get_drvdata(dev); - - if (mode) - *mode = ep->mode; -#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID - if (uid) - *uid = ep->uid; - if (gid) - *gid = ep->gid; -#endif - return NULL; -} - -static struct device_type kdbus_devtype_ep = { - .name = "ep", - .release = kdbus_dev_release, - .devnode = kdbus_devnode_ep, -}; - -struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep) -{ - kref_get(&ep->kref); - return ep; -} - -void kdbus_ep_disconnect(struct kdbus_ep *ep) -{ - if (ep->disconnected) - return; - ep->disconnected = true; - - if (ep->dev) { - device_unregister(ep->dev); - ep->dev = NULL; - } - if (ep->minor > 0) { - idr_remove(&ep->bus->ns->idr, ep->minor); - ep->minor = 0; - } - pr_debug("closing endpoint %s/%s/%s\n", - ep->bus->ns->devpath, ep->bus->name, ep->name); -} - -static void __kdbus_ep_free(struct kref *kref) -{ - struct kdbus_ep *ep = container_of(kref, struct kdbus_ep, kref); - - mutex_lock(&ep->bus->lock); - kdbus_ep_disconnect(ep); - pr_debug("clean up endpoint %s/%s/%s\n", - ep->bus->ns->devpath, ep->bus->name, ep->name); - mutex_unlock(&ep->bus->lock); - - kdbus_bus_unref(ep->bus); - if (ep->policy_db) - kdbus_policy_db_unref(ep->policy_db); - - kfree(ep->name); - kfree(ep); -} - -void kdbus_ep_unref(struct kdbus_ep *ep) -{ - kref_put(&ep->kref, __kdbus_ep_free); -} - -static struct kdbus_ep *kdbus_ep_find(struct kdbus_bus *bus, const char *name) -{ - struct kdbus_ep *ep = NULL; - struct kdbus_ep *e; - - mutex_lock(&bus->lock); - list_for_each_entry(e, &bus->ep_list, bus_entry) { - if (strcmp(ep->name, name) != 0) - continue; - - ep = kdbus_ep_ref(e); - } - mutex_unlock(&bus->lock); - - return ep; -} - -int kdbus_ep_new(struct kdbus_bus *bus, const char *name, umode_t mode, - kuid_t uid, kgid_t gid, bool policy_open) -{ - struct kdbus_ep *e; - int ret; - int i; - - e = kdbus_ep_find(bus, name); - if (e) { - kdbus_ep_unref(e); - return -EEXIST; - } - - e = kzalloc(sizeof(struct kdbus_ep), GFP_KERNEL); - if (!e) - return -ENOMEM; - - mutex_lock(&bus->ns->lock); - kref_init(&e->kref); - e->mode = mode > 0 ? mode : 0600; - e->uid = uid; - e->gid = gid; - - e->name = kstrdup(name, GFP_KERNEL); - if (!e->name) { - ret = -ENOMEM; - goto exit_unlock; - } - - /* register minor in our endpoint map */ - i = idr_alloc(&bus->ns->idr, e, 1, 0, GFP_KERNEL); - if (i <= 0) { - ret = i; - goto exit_unlock; - } - e->minor = i; - - /* get id for this endpoint from bus */ - mutex_lock(&bus->lock); - e->id = bus->ep_id_next++; - mutex_unlock(&bus->lock); - - /* register bus endpoint device */ - e->dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!e->dev) { - ret = -ENOMEM; - goto exit_unlock; - } - - dev_set_name(e->dev, "%s/%s/%s", bus->ns->devpath, bus->name, name); - e->dev->bus = &kdbus_subsys; - e->dev->type = &kdbus_devtype_ep; - e->dev->devt = MKDEV(bus->ns->major, e->minor); - dev_set_drvdata(e->dev, e); - ret = device_register(e->dev); - if (ret < 0) { - put_device(e->dev); - e->dev = NULL; - } - - /* Link this endpoint to the bus it is on */ - e->bus = kdbus_bus_ref(bus); - list_add_tail(&e->bus_entry, &bus->ep_list); - - /* install policy */ - e->policy_open = policy_open; - if (!policy_open) { - e->policy_db = kdbus_policy_db_new(); - if (!e->policy_db) { - ret = -ENOMEM; - goto exit_unlock; - } - } - - init_waitqueue_head(&e->wait); - INIT_LIST_HEAD(&e->connection_list); - - mutex_unlock(&bus->ns->lock); - - pr_debug("created endpoint %llu for bus '%s/%s/%s'\n", - (unsigned long long)e->id, bus->ns->devpath, bus->name, name); - return 0; - -exit_unlock: - mutex_unlock(&bus->ns->lock); - kdbus_ep_unref(e); - return ret; -} - -int kdbus_ep_remove(struct kdbus_ep *ep) -{ - struct kdbus_bus *bus = ep->bus; - - mutex_lock(&bus->ns->lock); - device_unregister(ep->dev); - list_del(&ep->bus_entry); - kdbus_ep_unref(ep); - mutex_unlock(&bus->ns->lock); - kdbus_bus_unref(bus); - return 0; -} - -int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake) -{ - u64 size; - struct kdbus_cmd_ep_kmake *km; - const struct kdbus_item *item; - int ret; - - if (kdbus_size_get_user(size, buf, struct kdbus_cmd_ep_make)) - return -EFAULT; - - if (size < sizeof(struct kdbus_cmd_ep_make) || size > KDBUS_MAKE_MAX_SIZE) - return -EMSGSIZE; - - km = kmalloc(sizeof(struct kdbus_cmd_ep_kmake) + size, GFP_KERNEL); - if (!km) - return -ENOMEM; - - memset(km, 0, offsetof(struct kdbus_cmd_ep_kmake, make)); - if (copy_from_user(&km->make, buf, size)) { - ret = -EFAULT; - goto exit; - } - - KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { - /* empty data records are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { - ret = -EINVAL; - goto exit; - } - - switch (item->type) { - case KDBUS_MAKE_NAME: - if (km->name) { - ret = -EEXIST; - goto exit; - } - - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { - ret = -EINVAL; - goto exit; - } - - if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { - ret = -ENAMETOOLONG; - goto exit; - } - - if (!kdbus_validate_nul(item->str, - item->size - KDBUS_ITEM_HEADER_SIZE)) { - ret = -EINVAL; - goto exit; - } - - km->name = item->str; - continue; - - default: - ret = -ENOTSUPP; - goto exit; - } - } - - /* expect correct padding and size values */ - if ((char *)item - ((char *)&km->make + km->make.size) >= 8) - return EINVAL; - - if (!km->name) { - ret = -EBADMSG; - goto exit; - } - - *kmake = km; - return 0; - -exit: - return ret; -} diff --git a/ep.h b/ep.h deleted file mode 100644 index 6e7e9a12fb6..00000000000 --- a/ep.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2013 Kay Sievers - * Copyright (C) 2013 Greg Kroah-Hartman - * Copyright (C) 2013 Linux Foundation - * - * 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. - */ - -#ifndef __KDBUS_EP_H -#define __KDBUS_EP_H - -#include "internal.h" - -/* - * kdbus endpoint - * - offers access to a bus, the default device node name is "bus" - * - additional endpoints can carry a specific policy/filters - */ -struct kdbus_ep { - struct kref kref; /* reference count */ - bool disconnected; /* invalidated data */ - struct kdbus_bus *bus; /* bus behind this endpoint */ - const char *name; /* name, prefixed with uid */ - u64 id; /* id of this endpoint on the bus */ - unsigned int minor; /* minor of this endpoint in the namespace major */ - struct device *dev; /* device node of this endpoint */ - umode_t mode; /* file mode of this endpoint device node */ - kuid_t uid; /* uid owning this endpoint */ - kgid_t gid; /* gid owning this endpoint */ - struct list_head bus_entry; /* list of endpoints for this bus */ - struct list_head message_list; /* messages in flight for this endpoint */ - struct list_head connection_list; - wait_queue_head_t wait; /* wake up this endpoint */ - struct kdbus_policy_db *policy_db; - bool policy_open:1; -}; - -struct kdbus_cmd_ep_kmake { - const char *name; - struct kdbus_cmd_ep_make make; -}; - -struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); -void kdbus_ep_unref(struct kdbus_ep *ep); - -int kdbus_ep_new(struct kdbus_bus *bus, const char *name, - umode_t mode, kuid_t uid, kgid_t gid, bool policy); -int kdbus_ep_remove(struct kdbus_ep *ep); -void kdbus_ep_disconnect(struct kdbus_ep *ep); -int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake); -#endif diff --git a/main.c b/main.c index f502643733d..8d0489f51be 100644 --- a/main.c +++ b/main.c @@ -23,7 +23,7 @@ #include #include "internal.h" -#include "ns.h" +#include "namespace.h" /* kdbus sysfs subsystem */ struct bus_type kdbus_subsys = { diff --git a/match.c b/match.c index 6cbbfbcdd16..04fb82f87f2 100644 --- a/match.c +++ b/match.c @@ -24,7 +24,7 @@ #include "match.h" #include "connection.h" -#include "ep.h" +#include "endpoint.h" #include "message.h" #include "bus.h" diff --git a/message.c b/message.c index 616146bedbe..ac1b0f58520 100644 --- a/message.c +++ b/message.c @@ -29,7 +29,7 @@ #include "message.h" #include "connection.h" #include "bus.h" -#include "ep.h" +#include "endpoint.h" #include "policy.h" #include "names.h" #include "match.h" diff --git a/names.c b/names.c index d66118bd326..70261f6d317 100644 --- a/names.c +++ b/names.c @@ -29,7 +29,7 @@ #include "notify.h" #include "policy.h" #include "bus.h" -#include "ep.h" +#include "endpoint.h" struct kdbus_name_queue_item { struct kdbus_conn *conn; diff --git a/namespace.c b/namespace.c new file mode 100644 index 00000000000..ff1f3e608fd --- /dev/null +++ b/namespace.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "namespace.h" + +/* global list of all namespaces */ +static LIST_HEAD(namespace_list); + +/* namespace list lock */ +DEFINE_MUTEX(kdbus_subsys_lock); + +/* next namespace id sequence number */ +static u64 kdbus_ns_id_next; + +/* control nodes are world accessible */ +static char *kdbus_devnode_control(struct device *dev, umode_t *mode +#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID + , kuid_t *uid, kgid_t *gid) +#else + ) +#endif +{ + struct kdbus_ns *ns = dev_get_drvdata(dev); + + if (mode) + *mode = ns->mode; + + return NULL; +} + +static struct device_type kdbus_devtype_control = { + .name = "control", + .release = kdbus_dev_release, + .devnode = kdbus_devnode_control, +}; + +/* kdbus namespace */ +struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns) +{ + kref_get(&ns->kref); + return ns; +} + +void kdbus_ns_disconnect(struct kdbus_ns *ns) +{ + mutex_lock(&kdbus_subsys_lock); + list_del(&ns->ns_entry); + + if (ns->dev) { + device_unregister(ns->dev); + ns->dev = NULL; + } + if (ns->major > 0) { + idr_remove(&kdbus_ns_major_idr, ns->major); + unregister_chrdev(ns->major, "kdbus"); + ns->major = 0; + } + mutex_unlock(&kdbus_subsys_lock); + pr_debug("closing namespace %s\n", ns->devpath); +} + +static void __kdbus_ns_free(struct kref *kref) +{ + struct kdbus_ns *ns = container_of(kref, struct kdbus_ns, kref); + + kdbus_ns_disconnect(ns); + pr_debug("clean up namespace %s\n", ns->devpath); + kfree(ns->name); + kfree(ns->devpath); + kfree(ns); +} + +void kdbus_ns_unref(struct kdbus_ns *ns) +{ + kref_put(&ns->kref, __kdbus_ns_free); +} + +static struct kdbus_ns *kdbus_ns_find(struct kdbus_ns const *parent, const char *name) +{ + struct kdbus_ns *ns = NULL; + struct kdbus_ns *n; + + mutex_lock(&kdbus_subsys_lock); + list_for_each_entry(n, &namespace_list, ns_entry) { + if (n->parent != parent) + continue; + if (strcmp(n->name, name)) + continue; + + ns = kdbus_ns_ref(n); + break; + } + + mutex_unlock(&kdbus_subsys_lock); + return ns; +} + +struct kdbus_ns *kdbus_ns_find_by_major(unsigned int major) +{ + struct kdbus_ns *ns; + + mutex_lock(&kdbus_subsys_lock); + ns = idr_find(&kdbus_ns_major_idr, major); + mutex_unlock(&kdbus_subsys_lock); + + return ns; +} + +int kdbus_ns_new(struct kdbus_ns *parent, const char *name, umode_t mode, struct kdbus_ns **ns) +{ + struct kdbus_ns *n; + const char *ns_name = NULL; + int i; + int ret; + + if ((parent && !name) || (!parent && name)) + return -EINVAL; + + n = kdbus_ns_find(parent, name); + if (n) { + kdbus_ns_unref(n); + return -EEXIST; + } + + n = kzalloc(sizeof(struct kdbus_ns), GFP_KERNEL); + if (!n) + return -ENOMEM; + + if (name) { + ns_name = kstrdup(name, GFP_KERNEL); + if (!ns_name) { + kfree(n); + return -ENOMEM; + } + } + + INIT_LIST_HEAD(&n->bus_list); + kref_init(&n->kref); + n->mode = mode; + idr_init(&n->idr); + mutex_init(&n->lock); + + /* compose name and path of base directory in /dev */ + if (!parent) { + /* initial namespace */ + n->devpath = kstrdup("kdbus", GFP_KERNEL); + if (!n->devpath) { + ret = -ENOMEM; + goto ret; + } + + /* register static major to support module auto-loading */ + ret = register_chrdev(KDBUS_CHAR_MAJOR, "kdbus", &kdbus_device_ops); + if (ret) + goto ret; + n->major = KDBUS_CHAR_MAJOR; + } else { + n->parent = parent; + n->devpath = kasprintf(GFP_KERNEL, "kdbus/ns/%s/%s", parent->devpath, name); + if (!n->devpath) { + ret = -ENOMEM; + goto ret; + } + + /* get dynamic major */ + n->major = register_chrdev(0, "kdbus", &kdbus_device_ops); + if (n->major < 0) { + ret = n->major; + goto ret; + } + n->name = ns_name; + } + + mutex_lock(&kdbus_subsys_lock); + + /* kdbus_device_ops' dev_t finds the namespace in the major map, + * and the bus in the minor map of that namespace */ + i = idr_alloc(&kdbus_ns_major_idr, n, n->major, 0, GFP_KERNEL); + if (i <= 0) { + ret = -EEXIST; + goto exit_unlock; + } + + /* get id for this namespace */ + n->id = kdbus_ns_id_next++; + + /* register control device for this namespace */ + n->dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!n->dev) + goto exit_unlock; + dev_set_name(n->dev, "%s/%s", n->devpath, "control"); + n->dev->bus = &kdbus_subsys; + n->dev->type = &kdbus_devtype_control; + n->dev->devt = MKDEV(n->major, 0); + dev_set_drvdata(n->dev, n); + ret = device_register(n->dev); + if (ret < 0) { + put_device(n->dev); + n->dev = NULL; + goto exit_unlock; + } + + list_add_tail(&n->ns_entry, &namespace_list); + + mutex_unlock(&kdbus_subsys_lock); + + *ns = n; + pr_debug("created namespace %llu '%s/'\n", + (unsigned long long)n->id, n->devpath); + return 0; + +exit_unlock: + mutex_unlock(&kdbus_subsys_lock); +ret: + kdbus_ns_unref(n); + return ret; +} + +int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake) +{ + u64 size; + struct kdbus_cmd_ns_kmake *km; + const struct kdbus_item *item; + int ret; + + if (kdbus_size_get_user(size, buf, struct kdbus_cmd_ns_make)) + return -EFAULT; + + if (size < sizeof(struct kdbus_cmd_ns_make) || size > KDBUS_MAKE_MAX_SIZE) + return -EMSGSIZE; + + km = kmalloc(sizeof(struct kdbus_cmd_ns_kmake) + size, GFP_KERNEL); + if (!km) + return -ENOMEM; + + memset(km, 0, offsetof(struct kdbus_cmd_ns_kmake, make)); + if (copy_from_user(&km->make, buf, size)) { + ret = -EFAULT; + goto exit; + } + + KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { + /* empty data records are invalid */ + if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + ret = -EINVAL; + goto exit; + } + + switch (item->type) { + case KDBUS_MAKE_NAME: + if (km->name) { + ret = -EEXIST; + goto exit; + } + + if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { + ret = -EINVAL; + goto exit; + } + + if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { + ret = -ENAMETOOLONG; + goto exit; + } + + if (!kdbus_validate_nul(item->str, + item->size - KDBUS_ITEM_HEADER_SIZE)) { + ret = -EINVAL; + goto exit; + } + + km->name = item->str; + continue; + + default: + ret = -ENOTSUPP; + goto exit; + } + } + + /* expect correct padding and size values */ + if ((char *)item - ((char *)&km->make + km->make.size) >= 8) + return EINVAL; + + if (!km->name) { + ret = -EBADMSG; + goto exit; + } + + *kmake = km; + return 0; + +exit: + return ret; +} diff --git a/namespace.h b/namespace.h new file mode 100644 index 00000000000..7a6bb96887f --- /dev/null +++ b/namespace.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * + * 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. + */ + +#ifndef __KDBUS_NS_H +#define __KDBUS_NS_H + +#include "internal.h" + +/* + * kdbus namespace + * - provides a "control" node + * - owns a major number + * - owns all created buses + * - the initial namespace is unnamed and stays around for forver + * - new namespaces are created by opening the control node and + * issuing KDBUS_NS_CREATE + * - closing the connection destroys the created namespace + */ +struct kdbus_ns { + struct kref kref; /* reference counter */ + const char *name; /* name of the namespace */ + struct kdbus_ns *parent; /* parent namespace */ + u64 id; /* global id of this namespace */ + const char *devpath; /* /dev base directory path */ + unsigned int major; /* device major number for all nodes */ + umode_t mode; /* device node access mode */ + struct idr idr; /* map of endpoint minors to buses */ + struct device *dev; /* control device node, minor == 0 */ + struct mutex lock; /* ns data lock */ + u64 bus_id_next; /* next bus id sequence number */ + struct list_head ns_entry; + struct list_head bus_list; /* list of all buses */ +}; + +struct kdbus_cmd_ns_kmake { + const char *name; + struct kdbus_cmd_ns_make make; +}; + +struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns); +void kdbus_ns_unref(struct kdbus_ns *ns); +void kdbus_ns_disconnect(struct kdbus_ns *ns); +int kdbus_ns_new(struct kdbus_ns *parent, const char *name, umode_t mode, struct kdbus_ns **ns); +int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake); +struct kdbus_ns *kdbus_ns_find_by_major(unsigned int major); +#endif diff --git a/notify.c b/notify.c index 5147e5bf54d..56cc67cfc31 100644 --- a/notify.c +++ b/notify.c @@ -24,7 +24,7 @@ #include "notify.h" #include "bus.h" -#include "ep.h" +#include "endpoint.h" #include "message.h" static int kdbus_notify_reply(struct kdbus_ep *ep, u64 src_id, diff --git a/ns.c b/ns.c deleted file mode 100644 index 51bbfa92889..00000000000 --- a/ns.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (C) 2013 Kay Sievers - * Copyright (C) 2013 Greg Kroah-Hartman - * Copyright (C) 2013 Linux Foundation - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ns.h" - -/* global list of all namespaces */ -static LIST_HEAD(namespace_list); - -/* namespace list lock */ -DEFINE_MUTEX(kdbus_subsys_lock); - -/* next namespace id sequence number */ -static u64 kdbus_ns_id_next; - -/* control nodes are world accessible */ -static char *kdbus_devnode_control(struct device *dev, umode_t *mode -#ifdef DRIVER_CORE_DEVICE_TYPE_DEVNODE_UID - , kuid_t *uid, kgid_t *gid) -#else - ) -#endif -{ - struct kdbus_ns *ns = dev_get_drvdata(dev); - - if (mode) - *mode = ns->mode; - - return NULL; -} - -static struct device_type kdbus_devtype_control = { - .name = "control", - .release = kdbus_dev_release, - .devnode = kdbus_devnode_control, -}; - -/* kdbus namespace */ -struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns) -{ - kref_get(&ns->kref); - return ns; -} - -void kdbus_ns_disconnect(struct kdbus_ns *ns) -{ - mutex_lock(&kdbus_subsys_lock); - list_del(&ns->ns_entry); - - if (ns->dev) { - device_unregister(ns->dev); - ns->dev = NULL; - } - if (ns->major > 0) { - idr_remove(&kdbus_ns_major_idr, ns->major); - unregister_chrdev(ns->major, "kdbus"); - ns->major = 0; - } - mutex_unlock(&kdbus_subsys_lock); - pr_debug("closing namespace %s\n", ns->devpath); -} - -static void __kdbus_ns_free(struct kref *kref) -{ - struct kdbus_ns *ns = container_of(kref, struct kdbus_ns, kref); - - kdbus_ns_disconnect(ns); - pr_debug("clean up namespace %s\n", ns->devpath); - kfree(ns->name); - kfree(ns->devpath); - kfree(ns); -} - -void kdbus_ns_unref(struct kdbus_ns *ns) -{ - kref_put(&ns->kref, __kdbus_ns_free); -} - -static struct kdbus_ns *kdbus_ns_find(struct kdbus_ns const *parent, const char *name) -{ - struct kdbus_ns *ns = NULL; - struct kdbus_ns *n; - - mutex_lock(&kdbus_subsys_lock); - list_for_each_entry(n, &namespace_list, ns_entry) { - if (n->parent != parent) - continue; - if (strcmp(n->name, name)) - continue; - - ns = kdbus_ns_ref(n); - break; - } - - mutex_unlock(&kdbus_subsys_lock); - return ns; -} - -struct kdbus_ns *kdbus_ns_find_by_major(unsigned int major) -{ - struct kdbus_ns *ns; - - mutex_lock(&kdbus_subsys_lock); - ns = idr_find(&kdbus_ns_major_idr, major); - mutex_unlock(&kdbus_subsys_lock); - - return ns; -} - -int kdbus_ns_new(struct kdbus_ns *parent, const char *name, umode_t mode, struct kdbus_ns **ns) -{ - struct kdbus_ns *n; - const char *ns_name = NULL; - int i; - int ret; - - if ((parent && !name) || (!parent && name)) - return -EINVAL; - - n = kdbus_ns_find(parent, name); - if (n) { - kdbus_ns_unref(n); - return -EEXIST; - } - - n = kzalloc(sizeof(struct kdbus_ns), GFP_KERNEL); - if (!n) - return -ENOMEM; - - if (name) { - ns_name = kstrdup(name, GFP_KERNEL); - if (!ns_name) { - kfree(n); - return -ENOMEM; - } - } - - INIT_LIST_HEAD(&n->bus_list); - kref_init(&n->kref); - n->mode = mode; - idr_init(&n->idr); - mutex_init(&n->lock); - - /* compose name and path of base directory in /dev */ - if (!parent) { - /* initial namespace */ - n->devpath = kstrdup("kdbus", GFP_KERNEL); - if (!n->devpath) { - ret = -ENOMEM; - goto ret; - } - - /* register static major to support module auto-loading */ - ret = register_chrdev(KDBUS_CHAR_MAJOR, "kdbus", &kdbus_device_ops); - if (ret) - goto ret; - n->major = KDBUS_CHAR_MAJOR; - } else { - n->parent = parent; - n->devpath = kasprintf(GFP_KERNEL, "kdbus/ns/%s/%s", parent->devpath, name); - if (!n->devpath) { - ret = -ENOMEM; - goto ret; - } - - /* get dynamic major */ - n->major = register_chrdev(0, "kdbus", &kdbus_device_ops); - if (n->major < 0) { - ret = n->major; - goto ret; - } - n->name = ns_name; - } - - mutex_lock(&kdbus_subsys_lock); - - /* kdbus_device_ops' dev_t finds the namespace in the major map, - * and the bus in the minor map of that namespace */ - i = idr_alloc(&kdbus_ns_major_idr, n, n->major, 0, GFP_KERNEL); - if (i <= 0) { - ret = -EEXIST; - goto exit_unlock; - } - - /* get id for this namespace */ - n->id = kdbus_ns_id_next++; - - /* register control device for this namespace */ - n->dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!n->dev) - goto exit_unlock; - dev_set_name(n->dev, "%s/%s", n->devpath, "control"); - n->dev->bus = &kdbus_subsys; - n->dev->type = &kdbus_devtype_control; - n->dev->devt = MKDEV(n->major, 0); - dev_set_drvdata(n->dev, n); - ret = device_register(n->dev); - if (ret < 0) { - put_device(n->dev); - n->dev = NULL; - goto exit_unlock; - } - - list_add_tail(&n->ns_entry, &namespace_list); - - mutex_unlock(&kdbus_subsys_lock); - - *ns = n; - pr_debug("created namespace %llu '%s/'\n", - (unsigned long long)n->id, n->devpath); - return 0; - -exit_unlock: - mutex_unlock(&kdbus_subsys_lock); -ret: - kdbus_ns_unref(n); - return ret; -} - -int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake) -{ - u64 size; - struct kdbus_cmd_ns_kmake *km; - const struct kdbus_item *item; - int ret; - - if (kdbus_size_get_user(size, buf, struct kdbus_cmd_ns_make)) - return -EFAULT; - - if (size < sizeof(struct kdbus_cmd_ns_make) || size > KDBUS_MAKE_MAX_SIZE) - return -EMSGSIZE; - - km = kmalloc(sizeof(struct kdbus_cmd_ns_kmake) + size, GFP_KERNEL); - if (!km) - return -ENOMEM; - - memset(km, 0, offsetof(struct kdbus_cmd_ns_kmake, make)); - if (copy_from_user(&km->make, buf, size)) { - ret = -EFAULT; - goto exit; - } - - KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { - /* empty data records are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { - ret = -EINVAL; - goto exit; - } - - switch (item->type) { - case KDBUS_MAKE_NAME: - if (km->name) { - ret = -EEXIST; - goto exit; - } - - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { - ret = -EINVAL; - goto exit; - } - - if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { - ret = -ENAMETOOLONG; - goto exit; - } - - if (!kdbus_validate_nul(item->str, - item->size - KDBUS_ITEM_HEADER_SIZE)) { - ret = -EINVAL; - goto exit; - } - - km->name = item->str; - continue; - - default: - ret = -ENOTSUPP; - goto exit; - } - } - - /* expect correct padding and size values */ - if ((char *)item - ((char *)&km->make + km->make.size) >= 8) - return EINVAL; - - if (!km->name) { - ret = -EBADMSG; - goto exit; - } - - *kmake = km; - return 0; - -exit: - return ret; -} diff --git a/ns.h b/ns.h deleted file mode 100644 index 7a6bb96887f..00000000000 --- a/ns.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2013 Kay Sievers - * Copyright (C) 2013 Greg Kroah-Hartman - * Copyright (C) 2013 Linux Foundation - * - * 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. - */ - -#ifndef __KDBUS_NS_H -#define __KDBUS_NS_H - -#include "internal.h" - -/* - * kdbus namespace - * - provides a "control" node - * - owns a major number - * - owns all created buses - * - the initial namespace is unnamed and stays around for forver - * - new namespaces are created by opening the control node and - * issuing KDBUS_NS_CREATE - * - closing the connection destroys the created namespace - */ -struct kdbus_ns { - struct kref kref; /* reference counter */ - const char *name; /* name of the namespace */ - struct kdbus_ns *parent; /* parent namespace */ - u64 id; /* global id of this namespace */ - const char *devpath; /* /dev base directory path */ - unsigned int major; /* device major number for all nodes */ - umode_t mode; /* device node access mode */ - struct idr idr; /* map of endpoint minors to buses */ - struct device *dev; /* control device node, minor == 0 */ - struct mutex lock; /* ns data lock */ - u64 bus_id_next; /* next bus id sequence number */ - struct list_head ns_entry; - struct list_head bus_list; /* list of all buses */ -}; - -struct kdbus_cmd_ns_kmake { - const char *name; - struct kdbus_cmd_ns_make make; -}; - -struct kdbus_ns *kdbus_ns_ref(struct kdbus_ns *ns); -void kdbus_ns_unref(struct kdbus_ns *ns); -void kdbus_ns_disconnect(struct kdbus_ns *ns); -int kdbus_ns_new(struct kdbus_ns *parent, const char *name, umode_t mode, struct kdbus_ns **ns); -int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake); -struct kdbus_ns *kdbus_ns_find_by_major(unsigned int major); -#endif -- cgit v1.2.3