diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2014-10-21 14:11:36 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2014-10-21 14:11:36 +0200 |
commit | 1fc0e192a9c4b43842be277112e1210405e23f55 (patch) | |
tree | f57924d54e25b602b69df4eddfe2518188262815 | |
parent | 83f791cbcf08c70713078c80020554c21c031e91 (diff) | |
download | kdbus-bus-1fc0e192a9c4b43842be277112e1210405e23f55.tar.gz kdbus-bus-1fc0e192a9c4b43842be277112e1210405e23f55.tar.bz2 kdbus-bus-1fc0e192a9c4b43842be277112e1210405e23f55.zip |
handle: use dynamic major/minor allocation (ABI break)
Instead of requiring 1 major per domain, we now allocate major/minor
combinations dynamically. So far, only a single major is allocated during
module init, but the code can easily be extended to even make those
dynamic. However, device-cgroups require us to have a fixed major. User
space must be aware that major/minor numbers no longer have any specific
meaning. Each major/minor combination might be assigned to any domain
and/or endpoint! Apart from this semantics change, the ABI stays the same.
Furthermore, this patch reworks the kdbus_domain_new() and kdbus_ep_new()
functions to avoid races against UEVENT_ADD. Both objects must be active
before we call device_add() and thus produce UEVENT_ADD.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
-rw-r--r-- | domain.c | 150 | ||||
-rw-r--r-- | domain.h | 5 | ||||
-rw-r--r-- | endpoint.c | 105 | ||||
-rw-r--r-- | endpoint.h | 2 | ||||
-rw-r--r-- | handle.c | 231 | ||||
-rw-r--r-- | handle.h | 30 | ||||
-rw-r--r-- | main.c | 15 | ||||
-rw-r--r-- | message.c | 2 |
8 files changed, 325 insertions, 215 deletions
@@ -28,14 +28,8 @@ #include "limits.h" #include "util.h" -/* map of majors to domains */ -static DEFINE_IDR(kdbus_domain_major_idr); - /* previous domain id sequence number */ -static u64 kdbus_domain_seq_last; - -/* kdbus subsystem lock */ -static DEFINE_MUTEX(kdbus_subsys_lock); +static atomic64_t kdbus_domain_seq_last; /* kdbus sysfs subsystem */ struct bus_type kdbus_subsys = { @@ -99,19 +93,10 @@ void kdbus_domain_disconnect(struct kdbus_domain *domain) mutex_unlock(&domain->parent->lock); } - if (domain->major > 0) { - mutex_lock(&kdbus_subsys_lock); - + if (device_is_registered(&domain->dev)) device_del(&domain->dev); - idr_remove(&kdbus_domain_major_idr, domain->major); - unregister_chrdev(domain->major, KBUILD_MODNAME); - domain->major = 0; - if (idr_is_empty(&kdbus_domain_major_idr)) - idr_destroy(&kdbus_domain_major_idr); - - mutex_unlock(&kdbus_subsys_lock); - } + kdbus_minor_set(domain->dev.devt, KDBUS_MINOR_CONTROL, NULL); /* disconnect all sub-domains */ for (;;) { @@ -166,9 +151,9 @@ static void __kdbus_domain_free(struct device *dev) BUG_ON(!list_empty(&domain->bus_list)); BUG_ON(!hash_empty(domain->user_hash)); + kdbus_minor_free(domain->dev.devt); kdbus_domain_unref(domain->parent); idr_destroy(&domain->user_idr); - idr_destroy(&domain->idr); kfree(domain->name); kfree(domain->devpath); kfree(domain); @@ -203,29 +188,6 @@ static struct kdbus_domain *kdbus_domain_find(struct kdbus_domain *parent, } /** - * kdbus_domain_find_by_major() - lookup a domain by its major device number - * @major: Major number - * - * Looks up a domain by major number. The returned domain - * is ref'ed, and needs to be unref'ed by the user. Returns NULL if - * the domain can't be found. - * - * Return: the domain, or NULL if not found - */ -struct kdbus_domain *kdbus_domain_find_by_major(unsigned int major) -{ - struct kdbus_domain *domain; - - mutex_lock(&kdbus_subsys_lock); - domain = idr_find(&kdbus_domain_major_idr, major); - if (domain) - kdbus_domain_ref(domain); - mutex_unlock(&kdbus_subsys_lock); - - return domain; -} - -/** * kdbus_domain_new() - create a new domain * @parent: Parent domain, NULL for initial one * @name: Name of the domain, NULL for the initial one @@ -253,7 +215,6 @@ int kdbus_domain_new(struct kdbus_domain *parent, const char *name, INIT_LIST_HEAD(&d->bus_list); INIT_LIST_HEAD(&d->domain_list); d->mode = mode; - idr_init(&d->idr); mutex_init(&d->lock); atomic64_set(&d->msg_seq_last, 0); idr_init(&d->user_idr); @@ -264,99 +225,84 @@ int kdbus_domain_new(struct kdbus_domain *parent, const char *name, d->dev.release = __kdbus_domain_free; /* compose name and path of base directory in /dev */ - if (!parent) { + if (parent) { + d->devpath = kasprintf(GFP_KERNEL, "%s/domain/%s", + parent->devpath, name); + if (!d->devpath) { + ret = -ENOMEM; + goto exit_put; + } + + d->name = kstrdup(name, GFP_KERNEL); + if (!d->name) { + ret = -ENOMEM; + goto exit_put; + } + } else { /* initial domain */ d->devpath = kstrdup(KBUILD_MODNAME, GFP_KERNEL); if (!d->devpath) { ret = -ENOMEM; goto exit_put; } + } - mutex_lock(&kdbus_subsys_lock); + ret = dev_set_name(&d->dev, "%s/control", d->devpath); + if (ret < 0) + goto exit_put; - } else { - /* lock order: parent domain -> domain -> subsys_lock */ + ret = kdbus_minor_alloc(KDBUS_MINOR_CONTROL, NULL, &d->dev.devt); + if (ret < 0) + goto exit_put; + + if (parent) { + /* lock order: parent domain -> domain */ mutex_lock(&parent->lock); + if (parent->disconnected) { mutex_unlock(&parent->lock); ret = -ESHUTDOWN; goto exit_put; } - mutex_lock(&kdbus_subsys_lock); - if (kdbus_domain_find(parent, name)) { + mutex_unlock(&parent->lock); ret = -EEXIST; - goto exit_unlock; - } - - d->devpath = kasprintf(GFP_KERNEL, "%s/domain/%s", - parent->devpath, name); - if (!d->devpath) { - ret = -ENOMEM; - goto exit_unlock; + goto exit_put; } - d->name = kstrdup(name, GFP_KERNEL); - if (!d->name) { - ret = -ENOMEM; - goto exit_unlock; - } + d->parent = kdbus_domain_ref(parent); + list_add_tail(&d->domain_entry, &parent->domain_list); } - /* get dynamic major */ - ret = register_chrdev(0, d->devpath, &kdbus_device_ops); - if (ret < 0) - goto exit_unlock; - - d->major = ret; - d->dev.devt = MKDEV(d->major, 0); - - ret = dev_set_name(&d->dev, "%s/control", d->devpath); - if (ret < 0) - goto exit_chrdev; + d->id = atomic64_inc_return(&kdbus_domain_seq_last); /* - * kdbus_device_ops' dev_t finds the domain in the major map, - * and the bus in the minor map of that domain + * We have to mark the domain as enabled _before_ running device_add(). + * Otherwise, there's a race between UEVENT_ADD (generated by + * device_add()) and us enabling the minor. + * However, this means user-space can open the minor before we called + * device_add(). This is fine, as we never require the device to be + * registered, anyway. */ - ret = idr_alloc(&kdbus_domain_major_idr, d, d->major, 0, GFP_KERNEL); - if (ret < 0) { - if (ret == -ENOSPC) - ret = -EEXIST; - goto exit_chrdev; - } - /* get id for this domain */ - d->id = ++kdbus_domain_seq_last; + d->disconnected = false; + kdbus_minor_set_control(d->dev.devt, d); ret = device_add(&d->dev); - if (ret < 0) - goto exit_idr; - /* link into parent domain */ - if (parent) { - d->parent = kdbus_domain_ref(parent); - list_add_tail(&d->domain_entry, &parent->domain_list); - } - - d->disconnected = false; - - mutex_unlock(&kdbus_subsys_lock); if (parent) mutex_unlock(&parent->lock); + if (ret < 0) { + kdbus_domain_disconnect(d); + kdbus_domain_unref(d); + return ret; + } + *domain = d; return 0; -exit_idr: - idr_remove(&kdbus_domain_major_idr, d->major); -exit_chrdev: - unregister_chrdev(d->major, d->devpath); -exit_unlock: - mutex_unlock(&kdbus_subsys_lock); - if (parent) - mutex_unlock(&parent->lock); exit_put: put_device(&d->dev); return ret; @@ -26,9 +26,7 @@ * @devpath: /dev base directory path * @parent: Parent domain * @id: Global id of this domain - * @major: Device major number for all nodes * @mode: Device node access mode - * @idr: Map of endpoint minors to buses * @lock: Domain data lock * @bus_seq_last: Last used bus id sequence number * @msg_seq_last: Last used message id sequence number @@ -55,9 +53,7 @@ struct kdbus_domain { const char *devpath; struct kdbus_domain *parent; u64 id; - unsigned int major; umode_t mode; - struct idr idr; struct mutex lock; u64 bus_seq_last; atomic64_t msg_seq_last; @@ -95,7 +91,6 @@ struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain); void kdbus_domain_disconnect(struct kdbus_domain *domain); int kdbus_domain_new(struct kdbus_domain *parent, const char *name, umode_t mode, struct kdbus_domain **domain); -struct kdbus_domain *kdbus_domain_find_by_major(unsigned int major); int kdbus_domain_get_user_unlocked(struct kdbus_domain *domain, kuid_t uid, diff --git a/endpoint.c b/endpoint.c index 3e879d888f7..36411ad4f89 100644 --- a/endpoint.c +++ b/endpoint.c @@ -25,6 +25,7 @@ #include "connection.h" #include "domain.h" #include "endpoint.h" +#include "handle.h" #include "item.h" #include "message.h" #include "policy.h" @@ -76,6 +77,16 @@ void kdbus_ep_disconnect(struct kdbus_ep *ep) ep->disconnected = true; mutex_unlock(&ep->lock); + /* disconnect from bus */ + mutex_lock(&ep->bus->lock); + list_del(&ep->bus_entry); + mutex_unlock(&ep->bus->lock); + + if (device_is_registered(&ep->dev)) + device_del(&ep->dev); + + kdbus_minor_set(ep->dev.devt, KDBUS_MINOR_EP, NULL); + /* disconnect all connections to this endpoint */ for (;;) { struct kdbus_conn *conn; @@ -96,19 +107,6 @@ void kdbus_ep_disconnect(struct kdbus_ep *ep) kdbus_conn_disconnect(conn, false); kdbus_conn_unref(conn); } - - /* disconnect from bus */ - mutex_lock(&ep->bus->lock); - list_del(&ep->bus_entry); - mutex_unlock(&ep->bus->lock); - - if (ep->minor > 0) { - device_del(&ep->dev); - mutex_lock(&ep->bus->domain->lock); - idr_remove(&ep->bus->domain->idr, ep->minor); - mutex_unlock(&ep->bus->domain->lock); - ep->minor = 0; - } } static void __kdbus_ep_free(struct device *dev) @@ -119,6 +117,7 @@ static void __kdbus_ep_free(struct device *dev) BUG_ON(!list_empty(&ep->conn_list)); kdbus_policy_db_clear(&ep->policy_db); + kdbus_minor_free(ep->dev.devt); kdbus_bus_unref(ep->bus); kdbus_domain_user_unref(ep->user); kfree(ep->name); @@ -134,19 +133,13 @@ struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) static struct kdbus_ep *kdbus_ep_find(struct kdbus_bus *bus, const char *name) { - struct kdbus_ep *e, *ep = NULL; - - mutex_lock(&bus->lock); - list_for_each_entry(e, &bus->ep_list, bus_entry) { - if (strcmp(e->name, name) != 0) - continue; + struct kdbus_ep *e; - ep = kdbus_ep_ref(e); - break; - } - mutex_unlock(&bus->lock); + list_for_each_entry(e, &bus->ep_list, bus_entry) + if (!strcmp(e->name, name)) + return e; - return ep; + return NULL; } /** @@ -171,12 +164,6 @@ int kdbus_ep_new(struct kdbus_bus *bus, const char *name, struct kdbus_ep *e; int ret; - e = kdbus_ep_find(bus, name); - if (e) { - kdbus_ep_unref(e); - return -EEXIST; - } - e = kzalloc(sizeof(*e), GFP_KERNEL); if (!e) return -ENOMEM; @@ -201,52 +188,56 @@ int kdbus_ep_new(struct kdbus_bus *bus, const char *name, goto exit_put; } - mutex_lock(&bus->domain->lock); - /* register minor in our endpoint map */ - ret = idr_alloc(&bus->domain->idr, e, 1, 0, GFP_KERNEL); - if (ret < 0) { - if (ret == -ENOSPC) - ret = -EEXIST; - mutex_unlock(&bus->domain->lock); - goto exit_put; - } - - e->minor = ret; - e->dev.devt = MKDEV(bus->domain->major, e->minor); - mutex_unlock(&bus->domain->lock); - ret = dev_set_name(&e->dev, "%s/%s/%s", bus->domain->devpath, bus->name, name); if (ret < 0) - goto exit_idr; + goto exit_put; - ret = device_add(&e->dev); + ret = kdbus_minor_alloc(KDBUS_MINOR_EP, NULL, &e->dev.devt); if (ret < 0) - goto exit_idr; + goto exit_put; - /* link into bus */ mutex_lock(&bus->lock); + if (bus->disconnected) { mutex_unlock(&bus->lock); ret = -ESHUTDOWN; - goto exit_dev; + goto exit_put; } - e->id = ++bus->ep_seq_last; + + if (kdbus_ep_find(bus, name)) { + mutex_unlock(&bus->lock); + ret = -EEXIST; + goto exit_put; + } + e->bus = kdbus_bus_ref(bus); - e->disconnected = false; list_add_tail(&e->bus_entry, &bus->ep_list); + + e->id = ++bus->ep_seq_last; + + /* + * Same as with domains, we have to mark it enabled _before_ running + * device_add() to avoid messing with state after UEVENT_ADD was sent. + */ + + e->disconnected = false; + kdbus_minor_set_ep(e->dev.devt, e); + + ret = device_add(&e->dev); + mutex_unlock(&bus->lock); + if (ret < 0) { + kdbus_ep_disconnect(e); + kdbus_ep_unref(e); + return ret; + } + if (ep) *ep = e; return 0; -exit_dev: - device_del(&e->dev); -exit_idr: - mutex_lock(&bus->domain->lock); - idr_remove(&bus->domain->idr, e->minor); - mutex_unlock(&bus->domain->lock); exit_put: put_device(&e->dev); return ret; diff --git a/endpoint.h b/endpoint.h index 7ad25d31f58..19cb2d30d09 100644 --- a/endpoint.h +++ b/endpoint.h @@ -26,7 +26,6 @@ * @bus: Bus behind this endpoint * @name: Name of the endpoint * @id: ID of this endpoint on the bus - * @minor: Minor of this endpoint in the domain major * @mode: File mode of this endpoint device node * @uid: UID owning this endpoint * @gid: GID owning this endpoint @@ -47,7 +46,6 @@ struct kdbus_ep { struct kdbus_bus *bus; const char *name; u64 id; - unsigned int minor; umode_t mode; kuid_t uid; kgid_t gid; @@ -91,70 +91,211 @@ struct kdbus_handle { }; }; +/* kdbus major */ +static unsigned int kdbus_major; + +/* map of minors to objects */ +static DEFINE_IDR(kdbus_minor_idr); + +/* kdbus minor lock */ +static DEFINE_SPINLOCK(kdbus_minor_lock); + +int kdbus_minor_init(void) +{ + int ret; + + ret = __register_chrdev(0, 0, 0xfffff, KBUILD_MODNAME, + &kdbus_handle_ops); + if (ret < 0) + return ret; + + kdbus_major = ret; + return 0; +} + +void kdbus_minor_exit(void) +{ + __unregister_chrdev(kdbus_major, 0, 0xfffff, KBUILD_MODNAME); + idr_destroy(&kdbus_minor_idr); +} + +static void *kdbus_minor_pack(enum kdbus_minor_type type, void *ptr) +{ + unsigned long p = (unsigned long)ptr; + + BUILD_BUG_ON(KDBUS_MINOR_CNT > 4); + + if (WARN_ON(p & 0x3UL || type >= KDBUS_MINOR_CNT)) + return NULL; + + return (void*)(p | (unsigned long)type); +} + +static enum kdbus_minor_type kdbus_minor_unpack(void **ptr) +{ + unsigned long p = (unsigned long)*ptr; + + *ptr = (void*)(p & ~0x3UL); + return p & 0x3UL; +} + +static void kdbus_minor_ref(enum kdbus_minor_type type, void *ptr) +{ + if (ptr) { + switch (type) { + case KDBUS_MINOR_CONTROL: + kdbus_domain_ref(ptr); + break; + case KDBUS_MINOR_EP: + kdbus_ep_ref(ptr); + break; + default: + break; + } + } +} + +static void kdbus_minor_unref(enum kdbus_minor_type type, void *ptr) +{ + if (ptr) { + switch (type) { + case KDBUS_MINOR_CONTROL: + kdbus_domain_unref(ptr); + break; + case KDBUS_MINOR_EP: + kdbus_ep_unref(ptr); + break; + default: + break; + } + } +} + +int kdbus_minor_alloc(enum kdbus_minor_type type, void *ptr, dev_t *out) +{ + int ret; + + ptr = kdbus_minor_pack(type, ptr); + + idr_preload(GFP_KERNEL); + spin_lock(&kdbus_minor_lock); + ret = idr_alloc(&kdbus_minor_idr, ptr, 0, 0, GFP_NOWAIT); + spin_unlock(&kdbus_minor_lock); + idr_preload_end(); + + if (ret < 0) + return ret; + + *out = MKDEV(kdbus_major, ret); + return 0; +} + +void kdbus_minor_free(dev_t devt) +{ + unsigned int minor = MINOR(devt); + + if (!devt) + return; + + spin_lock(&kdbus_minor_lock); + idr_remove(&kdbus_minor_idr, minor); + spin_unlock(&kdbus_minor_lock); +} + +void kdbus_minor_set(dev_t devt, enum kdbus_minor_type type, void *ptr) +{ + unsigned int minor = MINOR(devt); + + ptr = kdbus_minor_pack(type, ptr); + + spin_lock(&kdbus_minor_lock); + ptr = idr_replace(&kdbus_minor_idr, ptr, minor); + spin_unlock(&kdbus_minor_lock); +} + +static int kdbus_minor_lookup(dev_t devt, void **out) +{ + unsigned int minor = MINOR(devt); + enum kdbus_minor_type type; + void *ptr; + + spin_lock(&kdbus_minor_lock); + ptr = idr_find(&kdbus_minor_idr, minor); + type = kdbus_minor_unpack(&ptr); + kdbus_minor_ref(type, ptr); + spin_unlock(&kdbus_minor_lock); + + if (!ptr) + return -ESHUTDOWN; + + *out = ptr; + return type; +} + static int kdbus_handle_open(struct inode *inode, struct file *file) { + enum kdbus_minor_type minor_type; struct kdbus_handle *handle; - struct kdbus_domain *domain; - struct kdbus_ep *ep; + void *minor_ptr; int ret; - /* find and reference domain */ - domain = kdbus_domain_find_by_major(MAJOR(inode->i_rdev)); - if (!domain || domain->disconnected) - return -ESHUTDOWN; + ret = kdbus_minor_lookup(inode->i_rdev, &minor_ptr); + if (ret < 0) + return ret; + + minor_type = ret; handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) + if (!handle) { + kdbus_minor_unref(minor_type, minor_ptr); return -ENOMEM; + } - handle->domain = domain; file->private_data = handle; - /* control device node */ - if (MINOR(inode->i_rdev) == 0) { + switch (minor_type) { + case KDBUS_MINOR_CONTROL: handle->type = KDBUS_HANDLE_CONTROL; - return 0; - } + handle->domain = minor_ptr; - /* find endpoint for device node */ - mutex_lock(&handle->domain->lock); - ep = idr_find(&handle->domain->idr, MINOR(inode->i_rdev)); - if (!ep || ep->disconnected) { - ret = -ESHUTDOWN; - goto exit_unlock; - } + break; - /* create endpoint connection */ - handle->type = KDBUS_HANDLE_EP; - handle->ep = kdbus_ep_ref(ep); + case KDBUS_MINOR_EP: + handle->type = KDBUS_HANDLE_EP; + handle->ep = minor_ptr; + handle->domain = kdbus_domain_ref(handle->ep->bus->domain); - /* cache the metadata/credentials of the creator of the connection */ - ret = kdbus_meta_new(&handle->meta); - if (ret < 0) - goto exit_ep_unref; - - ret = kdbus_meta_append(handle->meta, NULL, 0, - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_EXE | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_AUDIT); - if (ret < 0) - goto exit_meta_free; + /* cache the metadata/credentials of the creator */ + ret = kdbus_meta_new(&handle->meta); + if (ret < 0) + goto exit_free; + + ret = kdbus_meta_append(handle->meta, NULL, 0, + KDBUS_ATTACH_CREDS | + KDBUS_ATTACH_TID_COMM | + KDBUS_ATTACH_PID_COMM | + KDBUS_ATTACH_EXE | + KDBUS_ATTACH_CMDLINE | + KDBUS_ATTACH_CGROUP | + KDBUS_ATTACH_CAPS | + KDBUS_ATTACH_SECLABEL | + KDBUS_ATTACH_AUDIT); + if (ret < 0) + goto exit_free; + + break; + + default: + kdbus_minor_unref(minor_type, minor_ptr); + ret = -EINVAL; + goto exit_free; + } - mutex_unlock(&handle->domain->lock); return 0; -exit_meta_free: +exit_free: kdbus_meta_free(handle->meta); -exit_ep_unref: kdbus_ep_unref(handle->ep); -exit_unlock: - mutex_unlock(&handle->domain->lock); kdbus_domain_unref(handle->domain); kfree(handle); return ret; @@ -1055,7 +1196,7 @@ static int kdbus_handle_mmap(struct file *file, struct vm_area_struct *vma) return kdbus_pool_mmap(handle->conn->pool, vma); } -const struct file_operations kdbus_device_ops = { +const struct file_operations kdbus_handle_ops = { .owner = THIS_MODULE, .open = kdbus_handle_open, .release = kdbus_handle_release, @@ -14,5 +14,33 @@ #ifndef __KDBUS_HANDLE_H #define __KDBUS_HANDLE_H -extern const struct file_operations kdbus_device_ops; +struct kdbus_domain; +struct kdbus_ep; + +extern const struct file_operations kdbus_handle_ops; + +enum kdbus_minor_type { + KDBUS_MINOR_CONTROL, + KDBUS_MINOR_EP, + KDBUS_MINOR_CNT +}; + +int kdbus_minor_init(void); +void kdbus_minor_exit(void); +int kdbus_minor_alloc(enum kdbus_minor_type type, void *ptr, dev_t *out); +void kdbus_minor_free(dev_t devt); +void kdbus_minor_set(dev_t devt, enum kdbus_minor_type type, void *ptr); + +/* type-safe kdbus_minor_set() */ +static inline void kdbus_minor_set_control(dev_t devt, struct kdbus_domain *d) +{ + kdbus_minor_set(devt, KDBUS_MINOR_CONTROL, d); +} + +/* type-safe kdbus_minor_set() */ +static inline void kdbus_minor_set_ep(dev_t devt, struct kdbus_ep *e) +{ + kdbus_minor_set(devt, KDBUS_MINOR_EP, e); +} + #endif @@ -19,6 +19,7 @@ #include "util.h" #include "domain.h" +#include "handle.h" /* kdbus initial domain */ static struct kdbus_domain *kdbus_domain_init; @@ -31,25 +32,35 @@ static int __init kdbus_init(void) if (ret < 0) return ret; + ret = kdbus_minor_init(); + if (ret < 0) + goto exit_subsys; + /* * Create the initial domain; it is world-accessible and * provides the /dev/kdbus/control device node. */ ret = kdbus_domain_new(NULL, NULL, 0666, &kdbus_domain_init); if (ret < 0) { - bus_unregister(&kdbus_subsys); pr_err("failed to initialize, error=%i\n", ret); - return ret; + goto exit_minor; } pr_info("initialized\n"); return 0; + +exit_minor: + kdbus_minor_exit(); +exit_subsys: + bus_unregister(&kdbus_subsys); + return ret; } static void __exit kdbus_exit(void) { kdbus_domain_disconnect(kdbus_domain_init); kdbus_domain_unref(kdbus_domain_init); + kdbus_minor_exit(); bus_unregister(&kdbus_subsys); } diff --git a/message.c b/message.c index 9881801af74..89dfd4afe0a 100644 --- a/message.c +++ b/message.c @@ -90,7 +90,7 @@ static int kdbus_handle_check_file(struct file *file) * unix domain sockets and kdbus share a generic garbage collector. */ - if (file->f_op == &kdbus_device_ops) + if (file->f_op == &kdbus_handle_ops) return -EOPNOTSUPP; if (!S_ISSOCK(inode->i_mode)) |