binder: Support multiple /dev instances
authorMartijn Coenen <maco@google.com>
Fri, 3 Feb 2017 22:40:48 +0000 (14:40 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Feb 2017 15:00:01 +0000 (16:00 +0100)
Add a new module parameter 'devices', that can be
used to specify the names of the binder device
nodes we want to populate in /dev.

Each device node has its own context manager, and
is therefore logically separated from all the other
device nodes.

The config option CONFIG_ANDROID_BINDER_DEVICES can
be used to set the default value of the parameter.

This approach was favored over using IPC namespaces,
mostly because we require a single process to be a
part of multiple binder contexts, which seemed harder
to achieve with namespaces.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Martijn Coenen <maco@google.com>
Cc: Arve Hjønnevåg <arve@android.com>
Cc: Amit Pundir <amit.pundir@linaro.org>
Cc: Serban Constantinescu <serban.constantinescu@arm.com>
Cc: Dmitry Shmidt <dimitrysh@google.com>
Cc: Rom Lemarchand <romlem@google.com>
Cc: Android Kernel Team <kernel-team@android.com>
Signed-off-by: Martijn Coenen <maco@google.com>
[jstultz: minor checkpatch warning fix]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/android/Kconfig
drivers/android/binder.c

index bdfc6c6..a82fc02 100644 (file)
@@ -19,6 +19,18 @@ config ANDROID_BINDER_IPC
          Android process, using Binder to identify, invoke and pass arguments
          between said processes.
 
+config ANDROID_BINDER_DEVICES
+       string "Android Binder devices"
+       depends on ANDROID_BINDER_IPC
+       default "binder"
+       ---help---
+         Default value for the binder.devices parameter.
+
+         The binder.devices parameter is a comma-separated list of strings
+         that specifies the names of the binder device nodes that will be
+         created. Each binder device has its own context manager, and is
+         therefore logically separated from the other devices.
+
 config ANDROID_BINDER_IPC_32BIT
        bool
        depends on !64BIT && ANDROID_BINDER_IPC
index 97e4ed4..705caf5 100644 (file)
@@ -50,6 +50,7 @@ static DEFINE_MUTEX(binder_main_lock);
 static DEFINE_MUTEX(binder_deferred_lock);
 static DEFINE_MUTEX(binder_mmap_lock);
 
+static HLIST_HEAD(binder_devices);
 static HLIST_HEAD(binder_procs);
 static HLIST_HEAD(binder_deferred_list);
 static HLIST_HEAD(binder_dead_nodes);
@@ -113,6 +114,9 @@ module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
 static bool binder_debug_no_lock;
 module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO);
 
+static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;
+module_param_named(devices, binder_devices_param, charp, 0444);
+
 static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait);
 static int binder_stop_on_user_error;
 
@@ -220,9 +224,10 @@ struct binder_context {
        const char *name;
 };
 
-static struct binder_context global_context = {
-       .binder_context_mgr_uid = INVALID_UID,
-       .name = "binder",
+struct binder_device {
+       struct hlist_node hlist;
+       struct miscdevice miscdev;
+       struct binder_context context;
 };
 
 struct binder_work {
@@ -3047,6 +3052,7 @@ err_bad_arg:
 static int binder_open(struct inode *nodp, struct file *filp)
 {
        struct binder_proc *proc;
+       struct binder_device *binder_dev;
 
        binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
                     current->group_leader->pid, current->pid);
@@ -3057,10 +3063,12 @@ static int binder_open(struct inode *nodp, struct file *filp)
        get_task_struct(current);
        proc->tsk = current;
        proc->vma_vm_mm = current->mm;
-       proc->context = &global_context;
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
+       binder_dev = container_of(filp->private_data, struct binder_device,
+                                 miscdev);
+       proc->context = &binder_dev->context;
 
        binder_lock(__func__);
 
@@ -3767,26 +3775,50 @@ static const struct file_operations binder_fops = {
        .release = binder_release,
 };
 
-static struct miscdevice binder_miscdev = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "binder",
-       .fops = &binder_fops
-};
-
 BINDER_DEBUG_ENTRY(state);
 BINDER_DEBUG_ENTRY(stats);
 BINDER_DEBUG_ENTRY(transactions);
 BINDER_DEBUG_ENTRY(transaction_log);
 
+static int __init init_binder_device(const char *name)
+{
+       int ret;
+       struct binder_device *binder_device;
+
+       binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
+       if (!binder_device)
+               return -ENOMEM;
+
+       binder_device->miscdev.fops = &binder_fops;
+       binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
+       binder_device->miscdev.name = name;
+
+       binder_device->context.binder_context_mgr_uid = INVALID_UID;
+       binder_device->context.name = name;
+
+       ret = misc_register(&binder_device->miscdev);
+       if (ret < 0) {
+               kfree(binder_device);
+               return ret;
+       }
+
+       hlist_add_head(&binder_device->hlist, &binder_devices);
+
+       return ret;
+}
+
 static int __init binder_init(void)
 {
        int ret;
+       char *device_name, *device_names;
+       struct binder_device *device;
+       struct hlist_node *tmp;
 
        binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
        if (binder_debugfs_dir_entry_root)
                binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                                                 binder_debugfs_dir_entry_root);
-       ret = misc_register(&binder_miscdev);
+
        if (binder_debugfs_dir_entry_root) {
                debugfs_create_file("state",
                                    S_IRUGO,
@@ -3814,6 +3846,35 @@ static int __init binder_init(void)
                                    &binder_transaction_log_failed,
                                    &binder_transaction_log_fops);
        }
+
+       /*
+        * Copy the module_parameter string, because we don't want to
+        * tokenize it in-place.
+        */
+       device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
+       if (!device_names) {
+               ret = -ENOMEM;
+               goto err_alloc_device_names_failed;
+       }
+       strcpy(device_names, binder_devices_param);
+
+       while ((device_name = strsep(&device_names, ","))) {
+               ret = init_binder_device(device_name);
+               if (ret)
+                       goto err_init_binder_device_failed;
+       }
+
+       return ret;
+
+err_init_binder_device_failed:
+       hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
+               misc_deregister(&device->miscdev);
+               hlist_del(&device->hlist);
+               kfree(device);
+       }
+err_alloc_device_names_failed:
+       debugfs_remove_recursive(binder_debugfs_dir_entry_root);
+
        return ret;
 }