13ad20fe3SChristian Brauner /* SPDX-License-Identifier: GPL-2.0 */ 23ad20fe3SChristian Brauner 33ad20fe3SChristian Brauner #include <linux/compiler_types.h> 43ad20fe3SChristian Brauner #include <linux/errno.h> 53ad20fe3SChristian Brauner #include <linux/fs.h> 63ad20fe3SChristian Brauner #include <linux/fsnotify.h> 73ad20fe3SChristian Brauner #include <linux/gfp.h> 83ad20fe3SChristian Brauner #include <linux/idr.h> 93ad20fe3SChristian Brauner #include <linux/init.h> 103ad20fe3SChristian Brauner #include <linux/ipc_namespace.h> 113ad20fe3SChristian Brauner #include <linux/kdev_t.h> 123ad20fe3SChristian Brauner #include <linux/kernel.h> 133ad20fe3SChristian Brauner #include <linux/list.h> 1401b3f1fcSChristian Brauner #include <linux/namei.h> 153ad20fe3SChristian Brauner #include <linux/magic.h> 163ad20fe3SChristian Brauner #include <linux/major.h> 173ad20fe3SChristian Brauner #include <linux/miscdevice.h> 183ad20fe3SChristian Brauner #include <linux/module.h> 193ad20fe3SChristian Brauner #include <linux/mutex.h> 203ad20fe3SChristian Brauner #include <linux/mount.h> 213ad20fe3SChristian Brauner #include <linux/parser.h> 223ad20fe3SChristian Brauner #include <linux/radix-tree.h> 233ad20fe3SChristian Brauner #include <linux/sched.h> 24849d540dSChristian Brauner #include <linux/seq_file.h> 253ad20fe3SChristian Brauner #include <linux/slab.h> 263ad20fe3SChristian Brauner #include <linux/spinlock_types.h> 273ad20fe3SChristian Brauner #include <linux/stddef.h> 283ad20fe3SChristian Brauner #include <linux/string.h> 293ad20fe3SChristian Brauner #include <linux/types.h> 303ad20fe3SChristian Brauner #include <linux/uaccess.h> 313ad20fe3SChristian Brauner #include <linux/user_namespace.h> 323ad20fe3SChristian Brauner #include <linux/xarray.h> 333ad20fe3SChristian Brauner #include <uapi/asm-generic/errno-base.h> 343ad20fe3SChristian Brauner #include <uapi/linux/android/binder.h> 35c13295adSChristian Brauner #include <uapi/linux/android/binderfs.h> 363ad20fe3SChristian Brauner 373ad20fe3SChristian Brauner #include "binder_internal.h" 383ad20fe3SChristian Brauner 393ad20fe3SChristian Brauner #define FIRST_INODE 1 403ad20fe3SChristian Brauner #define SECOND_INODE 2 413ad20fe3SChristian Brauner #define INODE_OFFSET 3 423ad20fe3SChristian Brauner #define INTSTRLEN 21 433ad20fe3SChristian Brauner #define BINDERFS_MAX_MINOR (1U << MINORBITS) 4436bdf3caSChristian Brauner /* Ensure that the initial ipc namespace always has devices available. */ 4536bdf3caSChristian Brauner #define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) 463ad20fe3SChristian Brauner 473ad20fe3SChristian Brauner static dev_t binderfs_dev; 483ad20fe3SChristian Brauner static DEFINE_MUTEX(binderfs_minors_mutex); 493ad20fe3SChristian Brauner static DEFINE_IDA(binderfs_minors); 503ad20fe3SChristian Brauner 513ad20fe3SChristian Brauner /** 52849d540dSChristian Brauner * binderfs_mount_opts - mount options for binderfs 53849d540dSChristian Brauner * @max: maximum number of allocatable binderfs binder devices 54f0083451SHridya Valsaraju * @stats_mode: enable binder stats in binderfs. 55849d540dSChristian Brauner */ 56849d540dSChristian Brauner struct binderfs_mount_opts { 57849d540dSChristian Brauner int max; 58f0083451SHridya Valsaraju int stats_mode; 59849d540dSChristian Brauner }; 60849d540dSChristian Brauner 61849d540dSChristian Brauner enum { 62849d540dSChristian Brauner Opt_max, 63f0083451SHridya Valsaraju Opt_stats_mode, 64849d540dSChristian Brauner Opt_err 65849d540dSChristian Brauner }; 66849d540dSChristian Brauner 67f0083451SHridya Valsaraju enum binderfs_stats_mode { 68f0083451SHridya Valsaraju STATS_NONE, 69f0083451SHridya Valsaraju STATS_GLOBAL, 70f0083451SHridya Valsaraju }; 71f0083451SHridya Valsaraju 72849d540dSChristian Brauner static const match_table_t tokens = { 73849d540dSChristian Brauner { Opt_max, "max=%d" }, 74f0083451SHridya Valsaraju { Opt_stats_mode, "stats=%s" }, 75849d540dSChristian Brauner { Opt_err, NULL } 76849d540dSChristian Brauner }; 77849d540dSChristian Brauner 78849d540dSChristian Brauner /** 793ad20fe3SChristian Brauner * binderfs_info - information about a binderfs mount 803ad20fe3SChristian Brauner * @ipc_ns: The ipc namespace the binderfs mount belongs to. 813ad20fe3SChristian Brauner * @control_dentry: This records the dentry of this binderfs mount 823ad20fe3SChristian Brauner * binder-control device. 833ad20fe3SChristian Brauner * @root_uid: uid that needs to be used when a new binder device is 843ad20fe3SChristian Brauner * created. 853ad20fe3SChristian Brauner * @root_gid: gid that needs to be used when a new binder device is 863ad20fe3SChristian Brauner * created. 87849d540dSChristian Brauner * @mount_opts: The mount options in use. 88849d540dSChristian Brauner * @device_count: The current number of allocated binder devices. 893ad20fe3SChristian Brauner */ 903ad20fe3SChristian Brauner struct binderfs_info { 913ad20fe3SChristian Brauner struct ipc_namespace *ipc_ns; 923ad20fe3SChristian Brauner struct dentry *control_dentry; 933ad20fe3SChristian Brauner kuid_t root_uid; 943ad20fe3SChristian Brauner kgid_t root_gid; 95849d540dSChristian Brauner struct binderfs_mount_opts mount_opts; 96849d540dSChristian Brauner int device_count; 973ad20fe3SChristian Brauner }; 983ad20fe3SChristian Brauner 993ad20fe3SChristian Brauner static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) 1003ad20fe3SChristian Brauner { 1013ad20fe3SChristian Brauner return inode->i_sb->s_fs_info; 1023ad20fe3SChristian Brauner } 1033ad20fe3SChristian Brauner 1043ad20fe3SChristian Brauner bool is_binderfs_device(const struct inode *inode) 1053ad20fe3SChristian Brauner { 1063ad20fe3SChristian Brauner if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC) 1073ad20fe3SChristian Brauner return true; 1083ad20fe3SChristian Brauner 1093ad20fe3SChristian Brauner return false; 1103ad20fe3SChristian Brauner } 1113ad20fe3SChristian Brauner 1123ad20fe3SChristian Brauner /** 1133ad20fe3SChristian Brauner * binderfs_binder_device_create - allocate inode from super block of a 1143ad20fe3SChristian Brauner * binderfs mount 1153ad20fe3SChristian Brauner * @ref_inode: inode from wich the super block will be taken 1163ad20fe3SChristian Brauner * @userp: buffer to copy information about new device for userspace to 1173ad20fe3SChristian Brauner * @req: struct binderfs_device as copied from userspace 1183ad20fe3SChristian Brauner * 11901b3f1fcSChristian Brauner * This function allocates a new binder_device and reserves a new minor 1203ad20fe3SChristian Brauner * number for it. 1213ad20fe3SChristian Brauner * Minor numbers are limited and tracked globally in binderfs_minors. The 1223ad20fe3SChristian Brauner * function will stash a struct binder_device for the specific binder 1233ad20fe3SChristian Brauner * device in i_private of the inode. 1243ad20fe3SChristian Brauner * It will go on to allocate a new inode from the super block of the 1253ad20fe3SChristian Brauner * filesystem mount, stash a struct binder_device in its i_private field 1263ad20fe3SChristian Brauner * and attach a dentry to that inode. 1273ad20fe3SChristian Brauner * 1283ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 1293ad20fe3SChristian Brauner */ 1303ad20fe3SChristian Brauner static int binderfs_binder_device_create(struct inode *ref_inode, 1313ad20fe3SChristian Brauner struct binderfs_device __user *userp, 1323ad20fe3SChristian Brauner struct binderfs_device *req) 1333ad20fe3SChristian Brauner { 1343ad20fe3SChristian Brauner int minor, ret; 13501b3f1fcSChristian Brauner struct dentry *dentry, *root; 1363ad20fe3SChristian Brauner struct binder_device *device; 1373ad20fe3SChristian Brauner char *name = NULL; 13801b3f1fcSChristian Brauner size_t name_len; 1393ad20fe3SChristian Brauner struct inode *inode = NULL; 1403ad20fe3SChristian Brauner struct super_block *sb = ref_inode->i_sb; 1413ad20fe3SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 1427fefaaddSChristian Brauner #if defined(CONFIG_IPC_NS) 14336bdf3caSChristian Brauner bool use_reserve = (info->ipc_ns == &init_ipc_ns); 1447fefaaddSChristian Brauner #else 1457fefaaddSChristian Brauner bool use_reserve = true; 1467fefaaddSChristian Brauner #endif 1473ad20fe3SChristian Brauner 1483ad20fe3SChristian Brauner /* Reserve new minor number for the new device. */ 1493ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 150849d540dSChristian Brauner if (++info->device_count <= info->mount_opts.max) 15136bdf3caSChristian Brauner minor = ida_alloc_max(&binderfs_minors, 15236bdf3caSChristian Brauner use_reserve ? BINDERFS_MAX_MINOR : 15336bdf3caSChristian Brauner BINDERFS_MAX_MINOR_CAPPED, 154849d540dSChristian Brauner GFP_KERNEL); 155849d540dSChristian Brauner else 156849d540dSChristian Brauner minor = -ENOSPC; 157849d540dSChristian Brauner if (minor < 0) { 158849d540dSChristian Brauner --info->device_count; 1593ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 1603ad20fe3SChristian Brauner return minor; 161849d540dSChristian Brauner } 162849d540dSChristian Brauner mutex_unlock(&binderfs_minors_mutex); 1633ad20fe3SChristian Brauner 1643ad20fe3SChristian Brauner ret = -ENOMEM; 1653ad20fe3SChristian Brauner device = kzalloc(sizeof(*device), GFP_KERNEL); 1663ad20fe3SChristian Brauner if (!device) 1673ad20fe3SChristian Brauner goto err; 1683ad20fe3SChristian Brauner 1693ad20fe3SChristian Brauner inode = new_inode(sb); 1703ad20fe3SChristian Brauner if (!inode) 1713ad20fe3SChristian Brauner goto err; 1723ad20fe3SChristian Brauner 1733ad20fe3SChristian Brauner inode->i_ino = minor + INODE_OFFSET; 1743ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 1753ad20fe3SChristian Brauner init_special_inode(inode, S_IFCHR | 0600, 1763ad20fe3SChristian Brauner MKDEV(MAJOR(binderfs_dev), minor)); 1773ad20fe3SChristian Brauner inode->i_fop = &binder_fops; 1783ad20fe3SChristian Brauner inode->i_uid = info->root_uid; 1793ad20fe3SChristian Brauner inode->i_gid = info->root_gid; 1803ad20fe3SChristian Brauner 18101b3f1fcSChristian Brauner req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ 18201b3f1fcSChristian Brauner name_len = strlen(req->name); 18301b3f1fcSChristian Brauner /* Make sure to include terminating NUL byte */ 18401b3f1fcSChristian Brauner name = kmemdup(req->name, name_len + 1, GFP_KERNEL); 1853ad20fe3SChristian Brauner if (!name) 1863ad20fe3SChristian Brauner goto err; 1873ad20fe3SChristian Brauner 1883ad20fe3SChristian Brauner device->binderfs_inode = inode; 1893ad20fe3SChristian Brauner device->context.binder_context_mgr_uid = INVALID_UID; 1903ad20fe3SChristian Brauner device->context.name = name; 1913ad20fe3SChristian Brauner device->miscdev.name = name; 1923ad20fe3SChristian Brauner device->miscdev.minor = minor; 1933ad20fe3SChristian Brauner mutex_init(&device->context.context_mgr_node_lock); 1943ad20fe3SChristian Brauner 1953ad20fe3SChristian Brauner req->major = MAJOR(binderfs_dev); 1963ad20fe3SChristian Brauner req->minor = minor; 1973ad20fe3SChristian Brauner 198ca2864c6SHridya Valsaraju if (userp && copy_to_user(userp, req, sizeof(*req))) { 1993ad20fe3SChristian Brauner ret = -EFAULT; 2003ad20fe3SChristian Brauner goto err; 2013ad20fe3SChristian Brauner } 2023ad20fe3SChristian Brauner 2033ad20fe3SChristian Brauner root = sb->s_root; 2043ad20fe3SChristian Brauner inode_lock(d_inode(root)); 20501b3f1fcSChristian Brauner 20601b3f1fcSChristian Brauner /* look it up */ 20701b3f1fcSChristian Brauner dentry = lookup_one_len(name, root, name_len); 20801b3f1fcSChristian Brauner if (IS_ERR(dentry)) { 2093ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 21001b3f1fcSChristian Brauner ret = PTR_ERR(dentry); 2113ad20fe3SChristian Brauner goto err; 2123ad20fe3SChristian Brauner } 2133ad20fe3SChristian Brauner 21401b3f1fcSChristian Brauner if (d_really_is_positive(dentry)) { 21501b3f1fcSChristian Brauner /* already exists */ 2163ad20fe3SChristian Brauner dput(dentry); 2173ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 2183ad20fe3SChristian Brauner ret = -EEXIST; 2193ad20fe3SChristian Brauner goto err; 2203ad20fe3SChristian Brauner } 2213ad20fe3SChristian Brauner 2223ad20fe3SChristian Brauner inode->i_private = device; 22301684db9SChristian Brauner d_instantiate(dentry, inode); 2243ad20fe3SChristian Brauner fsnotify_create(root->d_inode, dentry); 2253ad20fe3SChristian Brauner inode_unlock(d_inode(root)); 2263ad20fe3SChristian Brauner 2273ad20fe3SChristian Brauner return 0; 2283ad20fe3SChristian Brauner 2293ad20fe3SChristian Brauner err: 2303ad20fe3SChristian Brauner kfree(name); 2313ad20fe3SChristian Brauner kfree(device); 2323ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 233849d540dSChristian Brauner --info->device_count; 2343ad20fe3SChristian Brauner ida_free(&binderfs_minors, minor); 2353ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 2363ad20fe3SChristian Brauner iput(inode); 2373ad20fe3SChristian Brauner 2383ad20fe3SChristian Brauner return ret; 2393ad20fe3SChristian Brauner } 2403ad20fe3SChristian Brauner 2413ad20fe3SChristian Brauner /** 2423ad20fe3SChristian Brauner * binderfs_ctl_ioctl - handle binder device node allocation requests 2433ad20fe3SChristian Brauner * 2443ad20fe3SChristian Brauner * The request handler for the binder-control device. All requests operate on 2453ad20fe3SChristian Brauner * the binderfs mount the binder-control device resides in: 2463ad20fe3SChristian Brauner * - BINDER_CTL_ADD 2473ad20fe3SChristian Brauner * Allocate a new binder device. 2483ad20fe3SChristian Brauner * 2493ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 2503ad20fe3SChristian Brauner */ 2513ad20fe3SChristian Brauner static long binder_ctl_ioctl(struct file *file, unsigned int cmd, 2523ad20fe3SChristian Brauner unsigned long arg) 2533ad20fe3SChristian Brauner { 2543ad20fe3SChristian Brauner int ret = -EINVAL; 2553ad20fe3SChristian Brauner struct inode *inode = file_inode(file); 2563ad20fe3SChristian Brauner struct binderfs_device __user *device = (struct binderfs_device __user *)arg; 2573ad20fe3SChristian Brauner struct binderfs_device device_req; 2583ad20fe3SChristian Brauner 2593ad20fe3SChristian Brauner switch (cmd) { 2603ad20fe3SChristian Brauner case BINDER_CTL_ADD: 2613ad20fe3SChristian Brauner ret = copy_from_user(&device_req, device, sizeof(device_req)); 2623ad20fe3SChristian Brauner if (ret) { 2633ad20fe3SChristian Brauner ret = -EFAULT; 2643ad20fe3SChristian Brauner break; 2653ad20fe3SChristian Brauner } 2663ad20fe3SChristian Brauner 2673ad20fe3SChristian Brauner ret = binderfs_binder_device_create(inode, device, &device_req); 2683ad20fe3SChristian Brauner break; 2693ad20fe3SChristian Brauner default: 2703ad20fe3SChristian Brauner break; 2713ad20fe3SChristian Brauner } 2723ad20fe3SChristian Brauner 2733ad20fe3SChristian Brauner return ret; 2743ad20fe3SChristian Brauner } 2753ad20fe3SChristian Brauner 2763ad20fe3SChristian Brauner static void binderfs_evict_inode(struct inode *inode) 2773ad20fe3SChristian Brauner { 2783ad20fe3SChristian Brauner struct binder_device *device = inode->i_private; 279849d540dSChristian Brauner struct binderfs_info *info = BINDERFS_I(inode); 2803ad20fe3SChristian Brauner 2813ad20fe3SChristian Brauner clear_inode(inode); 2823ad20fe3SChristian Brauner 2830e13e452SHridya Valsaraju if (!S_ISCHR(inode->i_mode) || !device) 2843ad20fe3SChristian Brauner return; 2853ad20fe3SChristian Brauner 2863ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 287849d540dSChristian Brauner --info->device_count; 2883ad20fe3SChristian Brauner ida_free(&binderfs_minors, device->miscdev.minor); 2893ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 2903ad20fe3SChristian Brauner 2913ad20fe3SChristian Brauner kfree(device->context.name); 2923ad20fe3SChristian Brauner kfree(device); 2933ad20fe3SChristian Brauner } 2943ad20fe3SChristian Brauner 295849d540dSChristian Brauner /** 296849d540dSChristian Brauner * binderfs_parse_mount_opts - parse binderfs mount options 297849d540dSChristian Brauner * @data: options to set (can be NULL in which case defaults are used) 298849d540dSChristian Brauner */ 299849d540dSChristian Brauner static int binderfs_parse_mount_opts(char *data, 300849d540dSChristian Brauner struct binderfs_mount_opts *opts) 301849d540dSChristian Brauner { 302f0083451SHridya Valsaraju char *p, *stats; 303849d540dSChristian Brauner opts->max = BINDERFS_MAX_MINOR; 304f0083451SHridya Valsaraju opts->stats_mode = STATS_NONE; 305849d540dSChristian Brauner 306849d540dSChristian Brauner while ((p = strsep(&data, ",")) != NULL) { 307849d540dSChristian Brauner substring_t args[MAX_OPT_ARGS]; 308849d540dSChristian Brauner int token; 309849d540dSChristian Brauner int max_devices; 310849d540dSChristian Brauner 311849d540dSChristian Brauner if (!*p) 312849d540dSChristian Brauner continue; 313849d540dSChristian Brauner 314849d540dSChristian Brauner token = match_token(p, tokens, args); 315849d540dSChristian Brauner switch (token) { 316849d540dSChristian Brauner case Opt_max: 317849d540dSChristian Brauner if (match_int(&args[0], &max_devices) || 318849d540dSChristian Brauner (max_devices < 0 || 319849d540dSChristian Brauner (max_devices > BINDERFS_MAX_MINOR))) 320849d540dSChristian Brauner return -EINVAL; 321849d540dSChristian Brauner 322849d540dSChristian Brauner opts->max = max_devices; 323849d540dSChristian Brauner break; 324f0083451SHridya Valsaraju case Opt_stats_mode: 325f0083451SHridya Valsaraju if (!capable(CAP_SYS_ADMIN)) 326f0083451SHridya Valsaraju return -EINVAL; 327f0083451SHridya Valsaraju 328f0083451SHridya Valsaraju stats = match_strdup(&args[0]); 329f0083451SHridya Valsaraju if (!stats) 330f0083451SHridya Valsaraju return -ENOMEM; 331f0083451SHridya Valsaraju 332f0083451SHridya Valsaraju if (strcmp(stats, "global") != 0) { 333f0083451SHridya Valsaraju kfree(stats); 334f0083451SHridya Valsaraju return -EINVAL; 335f0083451SHridya Valsaraju } 336f0083451SHridya Valsaraju 337f0083451SHridya Valsaraju opts->stats_mode = STATS_GLOBAL; 338f0083451SHridya Valsaraju kfree(stats); 339f0083451SHridya Valsaraju break; 340849d540dSChristian Brauner default: 341849d540dSChristian Brauner pr_err("Invalid mount options\n"); 342849d540dSChristian Brauner return -EINVAL; 343849d540dSChristian Brauner } 344849d540dSChristian Brauner } 345849d540dSChristian Brauner 346849d540dSChristian Brauner return 0; 347849d540dSChristian Brauner } 348849d540dSChristian Brauner 349849d540dSChristian Brauner static int binderfs_remount(struct super_block *sb, int *flags, char *data) 350849d540dSChristian Brauner { 351f0083451SHridya Valsaraju int prev_stats_mode, ret; 352849d540dSChristian Brauner struct binderfs_info *info = sb->s_fs_info; 353f0083451SHridya Valsaraju 354f0083451SHridya Valsaraju prev_stats_mode = info->mount_opts.stats_mode; 355f0083451SHridya Valsaraju ret = binderfs_parse_mount_opts(data, &info->mount_opts); 356f0083451SHridya Valsaraju if (ret) 357f0083451SHridya Valsaraju return ret; 358f0083451SHridya Valsaraju 359f0083451SHridya Valsaraju if (prev_stats_mode != info->mount_opts.stats_mode) { 360f0083451SHridya Valsaraju pr_err("Binderfs stats mode cannot be changed during a remount\n"); 361f0083451SHridya Valsaraju info->mount_opts.stats_mode = prev_stats_mode; 362f0083451SHridya Valsaraju return -EINVAL; 363f0083451SHridya Valsaraju } 364f0083451SHridya Valsaraju 365f0083451SHridya Valsaraju return 0; 366849d540dSChristian Brauner } 367849d540dSChristian Brauner 368849d540dSChristian Brauner static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) 369849d540dSChristian Brauner { 370849d540dSChristian Brauner struct binderfs_info *info; 371849d540dSChristian Brauner 372849d540dSChristian Brauner info = root->d_sb->s_fs_info; 373849d540dSChristian Brauner if (info->mount_opts.max <= BINDERFS_MAX_MINOR) 374849d540dSChristian Brauner seq_printf(seq, ",max=%d", info->mount_opts.max); 375f0083451SHridya Valsaraju if (info->mount_opts.stats_mode == STATS_GLOBAL) 376f0083451SHridya Valsaraju seq_printf(seq, ",stats=global"); 377849d540dSChristian Brauner 378849d540dSChristian Brauner return 0; 379849d540dSChristian Brauner } 380849d540dSChristian Brauner 3813ad20fe3SChristian Brauner static const struct super_operations binderfs_super_ops = { 3823ad20fe3SChristian Brauner .evict_inode = binderfs_evict_inode, 383849d540dSChristian Brauner .remount_fs = binderfs_remount, 384849d540dSChristian Brauner .show_options = binderfs_show_mount_opts, 385849d540dSChristian Brauner .statfs = simple_statfs, 3863ad20fe3SChristian Brauner }; 3873ad20fe3SChristian Brauner 388e98e6fa1SChristian Brauner static inline bool is_binderfs_control_device(const struct dentry *dentry) 389e98e6fa1SChristian Brauner { 390e98e6fa1SChristian Brauner struct binderfs_info *info = dentry->d_sb->s_fs_info; 391e98e6fa1SChristian Brauner return info->control_dentry == dentry; 392e98e6fa1SChristian Brauner } 393e98e6fa1SChristian Brauner 3943ad20fe3SChristian Brauner static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, 3953ad20fe3SChristian Brauner struct inode *new_dir, struct dentry *new_dentry, 3963ad20fe3SChristian Brauner unsigned int flags) 3973ad20fe3SChristian Brauner { 398e98e6fa1SChristian Brauner if (is_binderfs_control_device(old_dentry) || 399e98e6fa1SChristian Brauner is_binderfs_control_device(new_dentry)) 4003ad20fe3SChristian Brauner return -EPERM; 4013ad20fe3SChristian Brauner 402e98e6fa1SChristian Brauner return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags); 4033ad20fe3SChristian Brauner } 4043ad20fe3SChristian Brauner 4053ad20fe3SChristian Brauner static int binderfs_unlink(struct inode *dir, struct dentry *dentry) 4063ad20fe3SChristian Brauner { 407e98e6fa1SChristian Brauner if (is_binderfs_control_device(dentry)) 4083ad20fe3SChristian Brauner return -EPERM; 4093ad20fe3SChristian Brauner 4103ad20fe3SChristian Brauner return simple_unlink(dir, dentry); 4113ad20fe3SChristian Brauner } 4123ad20fe3SChristian Brauner 4133ad20fe3SChristian Brauner static const struct file_operations binder_ctl_fops = { 4143ad20fe3SChristian Brauner .owner = THIS_MODULE, 4153ad20fe3SChristian Brauner .open = nonseekable_open, 4163ad20fe3SChristian Brauner .unlocked_ioctl = binder_ctl_ioctl, 4173ad20fe3SChristian Brauner .compat_ioctl = binder_ctl_ioctl, 4183ad20fe3SChristian Brauner .llseek = noop_llseek, 4193ad20fe3SChristian Brauner }; 4203ad20fe3SChristian Brauner 4213ad20fe3SChristian Brauner /** 4223ad20fe3SChristian Brauner * binderfs_binder_ctl_create - create a new binder-control device 4233ad20fe3SChristian Brauner * @sb: super block of the binderfs mount 4243ad20fe3SChristian Brauner * 4253ad20fe3SChristian Brauner * This function creates a new binder-control device node in the binderfs mount 4263ad20fe3SChristian Brauner * referred to by @sb. 4273ad20fe3SChristian Brauner * 4283ad20fe3SChristian Brauner * Return: 0 on success, negative errno on failure 4293ad20fe3SChristian Brauner */ 4303ad20fe3SChristian Brauner static int binderfs_binder_ctl_create(struct super_block *sb) 4313ad20fe3SChristian Brauner { 4323ad20fe3SChristian Brauner int minor, ret; 4333ad20fe3SChristian Brauner struct dentry *dentry; 4343ad20fe3SChristian Brauner struct binder_device *device; 4353ad20fe3SChristian Brauner struct inode *inode = NULL; 4363ad20fe3SChristian Brauner struct dentry *root = sb->s_root; 4373ad20fe3SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 438da8ddba5SChristian Brauner #if defined(CONFIG_IPC_NS) 439da8ddba5SChristian Brauner bool use_reserve = (info->ipc_ns == &init_ipc_ns); 440da8ddba5SChristian Brauner #else 441da8ddba5SChristian Brauner bool use_reserve = true; 442da8ddba5SChristian Brauner #endif 4433ad20fe3SChristian Brauner 4443ad20fe3SChristian Brauner device = kzalloc(sizeof(*device), GFP_KERNEL); 4453ad20fe3SChristian Brauner if (!device) 4463ad20fe3SChristian Brauner return -ENOMEM; 4473ad20fe3SChristian Brauner 4483ad20fe3SChristian Brauner /* If we have already created a binder-control node, return. */ 4493ad20fe3SChristian Brauner if (info->control_dentry) { 4503ad20fe3SChristian Brauner ret = 0; 4513ad20fe3SChristian Brauner goto out; 4523ad20fe3SChristian Brauner } 4533ad20fe3SChristian Brauner 4543ad20fe3SChristian Brauner ret = -ENOMEM; 4553ad20fe3SChristian Brauner inode = new_inode(sb); 4563ad20fe3SChristian Brauner if (!inode) 4573ad20fe3SChristian Brauner goto out; 4583ad20fe3SChristian Brauner 4593ad20fe3SChristian Brauner /* Reserve a new minor number for the new device. */ 4603ad20fe3SChristian Brauner mutex_lock(&binderfs_minors_mutex); 461da8ddba5SChristian Brauner minor = ida_alloc_max(&binderfs_minors, 462da8ddba5SChristian Brauner use_reserve ? BINDERFS_MAX_MINOR : 463da8ddba5SChristian Brauner BINDERFS_MAX_MINOR_CAPPED, 464da8ddba5SChristian Brauner GFP_KERNEL); 4653ad20fe3SChristian Brauner mutex_unlock(&binderfs_minors_mutex); 4663ad20fe3SChristian Brauner if (minor < 0) { 4673ad20fe3SChristian Brauner ret = minor; 4683ad20fe3SChristian Brauner goto out; 4693ad20fe3SChristian Brauner } 4703ad20fe3SChristian Brauner 4713ad20fe3SChristian Brauner inode->i_ino = SECOND_INODE; 4723ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 4733ad20fe3SChristian Brauner init_special_inode(inode, S_IFCHR | 0600, 4743ad20fe3SChristian Brauner MKDEV(MAJOR(binderfs_dev), minor)); 4753ad20fe3SChristian Brauner inode->i_fop = &binder_ctl_fops; 4763ad20fe3SChristian Brauner inode->i_uid = info->root_uid; 4773ad20fe3SChristian Brauner inode->i_gid = info->root_gid; 4783ad20fe3SChristian Brauner 4793ad20fe3SChristian Brauner device->binderfs_inode = inode; 4803ad20fe3SChristian Brauner device->miscdev.minor = minor; 4813ad20fe3SChristian Brauner 4823ad20fe3SChristian Brauner dentry = d_alloc_name(root, "binder-control"); 4833ad20fe3SChristian Brauner if (!dentry) 4843ad20fe3SChristian Brauner goto out; 4853ad20fe3SChristian Brauner 4863ad20fe3SChristian Brauner inode->i_private = device; 4873ad20fe3SChristian Brauner info->control_dentry = dentry; 4883ad20fe3SChristian Brauner d_add(dentry, inode); 4893ad20fe3SChristian Brauner 4903ad20fe3SChristian Brauner return 0; 4913ad20fe3SChristian Brauner 4923ad20fe3SChristian Brauner out: 4933ad20fe3SChristian Brauner kfree(device); 4943ad20fe3SChristian Brauner iput(inode); 4953ad20fe3SChristian Brauner 4963ad20fe3SChristian Brauner return ret; 4973ad20fe3SChristian Brauner } 4983ad20fe3SChristian Brauner 4993ad20fe3SChristian Brauner static const struct inode_operations binderfs_dir_inode_operations = { 5003ad20fe3SChristian Brauner .lookup = simple_lookup, 5013ad20fe3SChristian Brauner .rename = binderfs_rename, 5023ad20fe3SChristian Brauner .unlink = binderfs_unlink, 5033ad20fe3SChristian Brauner }; 5043ad20fe3SChristian Brauner 5050e13e452SHridya Valsaraju static struct inode *binderfs_make_inode(struct super_block *sb, int mode) 5060e13e452SHridya Valsaraju { 5070e13e452SHridya Valsaraju struct inode *ret; 5080e13e452SHridya Valsaraju 5090e13e452SHridya Valsaraju ret = new_inode(sb); 5100e13e452SHridya Valsaraju if (ret) { 5110e13e452SHridya Valsaraju ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET); 5120e13e452SHridya Valsaraju ret->i_mode = mode; 5130e13e452SHridya Valsaraju ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret); 5140e13e452SHridya Valsaraju } 5150e13e452SHridya Valsaraju return ret; 5160e13e452SHridya Valsaraju } 5170e13e452SHridya Valsaraju 5180e13e452SHridya Valsaraju static struct dentry *binderfs_create_dentry(struct dentry *parent, 5190e13e452SHridya Valsaraju const char *name) 5200e13e452SHridya Valsaraju { 5210e13e452SHridya Valsaraju struct dentry *dentry; 5220e13e452SHridya Valsaraju 5230e13e452SHridya Valsaraju dentry = lookup_one_len(name, parent, strlen(name)); 5240e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5250e13e452SHridya Valsaraju return dentry; 5260e13e452SHridya Valsaraju 5270e13e452SHridya Valsaraju /* Return error if the file/dir already exists. */ 5280e13e452SHridya Valsaraju if (d_really_is_positive(dentry)) { 5290e13e452SHridya Valsaraju dput(dentry); 5300e13e452SHridya Valsaraju return ERR_PTR(-EEXIST); 5310e13e452SHridya Valsaraju } 5320e13e452SHridya Valsaraju 5330e13e452SHridya Valsaraju return dentry; 5340e13e452SHridya Valsaraju } 5350e13e452SHridya Valsaraju 5360e13e452SHridya Valsaraju static struct dentry *binderfs_create_file(struct dentry *parent, 5370e13e452SHridya Valsaraju const char *name, 5380e13e452SHridya Valsaraju const struct file_operations *fops, 5390e13e452SHridya Valsaraju void *data) 5400e13e452SHridya Valsaraju { 5410e13e452SHridya Valsaraju struct dentry *dentry; 5420e13e452SHridya Valsaraju struct inode *new_inode, *parent_inode; 5430e13e452SHridya Valsaraju struct super_block *sb; 5440e13e452SHridya Valsaraju 5450e13e452SHridya Valsaraju parent_inode = d_inode(parent); 5460e13e452SHridya Valsaraju inode_lock(parent_inode); 5470e13e452SHridya Valsaraju 5480e13e452SHridya Valsaraju dentry = binderfs_create_dentry(parent, name); 5490e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5500e13e452SHridya Valsaraju goto out; 5510e13e452SHridya Valsaraju 5520e13e452SHridya Valsaraju sb = parent_inode->i_sb; 5530e13e452SHridya Valsaraju new_inode = binderfs_make_inode(sb, S_IFREG | 0444); 5540e13e452SHridya Valsaraju if (!new_inode) { 5550e13e452SHridya Valsaraju dput(dentry); 5560e13e452SHridya Valsaraju dentry = ERR_PTR(-ENOMEM); 5570e13e452SHridya Valsaraju goto out; 5580e13e452SHridya Valsaraju } 5590e13e452SHridya Valsaraju 5600e13e452SHridya Valsaraju new_inode->i_fop = fops; 5610e13e452SHridya Valsaraju new_inode->i_private = data; 5620e13e452SHridya Valsaraju d_instantiate(dentry, new_inode); 5630e13e452SHridya Valsaraju fsnotify_create(parent_inode, dentry); 5640e13e452SHridya Valsaraju 5650e13e452SHridya Valsaraju out: 5660e13e452SHridya Valsaraju inode_unlock(parent_inode); 5670e13e452SHridya Valsaraju return dentry; 5680e13e452SHridya Valsaraju } 5690e13e452SHridya Valsaraju 5700e13e452SHridya Valsaraju static struct dentry *binderfs_create_dir(struct dentry *parent, 5710e13e452SHridya Valsaraju const char *name) 5720e13e452SHridya Valsaraju { 5730e13e452SHridya Valsaraju struct dentry *dentry; 5740e13e452SHridya Valsaraju struct inode *new_inode, *parent_inode; 5750e13e452SHridya Valsaraju struct super_block *sb; 5760e13e452SHridya Valsaraju 5770e13e452SHridya Valsaraju parent_inode = d_inode(parent); 5780e13e452SHridya Valsaraju inode_lock(parent_inode); 5790e13e452SHridya Valsaraju 5800e13e452SHridya Valsaraju dentry = binderfs_create_dentry(parent, name); 5810e13e452SHridya Valsaraju if (IS_ERR(dentry)) 5820e13e452SHridya Valsaraju goto out; 5830e13e452SHridya Valsaraju 5840e13e452SHridya Valsaraju sb = parent_inode->i_sb; 5850e13e452SHridya Valsaraju new_inode = binderfs_make_inode(sb, S_IFDIR | 0755); 5860e13e452SHridya Valsaraju if (!new_inode) { 5870e13e452SHridya Valsaraju dput(dentry); 5880e13e452SHridya Valsaraju dentry = ERR_PTR(-ENOMEM); 5890e13e452SHridya Valsaraju goto out; 5900e13e452SHridya Valsaraju } 5910e13e452SHridya Valsaraju 5920e13e452SHridya Valsaraju new_inode->i_fop = &simple_dir_operations; 5930e13e452SHridya Valsaraju new_inode->i_op = &simple_dir_inode_operations; 5940e13e452SHridya Valsaraju 5950e13e452SHridya Valsaraju set_nlink(new_inode, 2); 5960e13e452SHridya Valsaraju d_instantiate(dentry, new_inode); 5970e13e452SHridya Valsaraju inc_nlink(parent_inode); 5980e13e452SHridya Valsaraju fsnotify_mkdir(parent_inode, dentry); 5990e13e452SHridya Valsaraju 6000e13e452SHridya Valsaraju out: 6010e13e452SHridya Valsaraju inode_unlock(parent_inode); 6020e13e452SHridya Valsaraju return dentry; 6030e13e452SHridya Valsaraju } 6040e13e452SHridya Valsaraju 6050e13e452SHridya Valsaraju static int init_binder_logs(struct super_block *sb) 6060e13e452SHridya Valsaraju { 6070e13e452SHridya Valsaraju struct dentry *binder_logs_root_dir, *dentry; 6080e13e452SHridya Valsaraju int ret = 0; 6090e13e452SHridya Valsaraju 6100e13e452SHridya Valsaraju binder_logs_root_dir = binderfs_create_dir(sb->s_root, 6110e13e452SHridya Valsaraju "binder_logs"); 6120e13e452SHridya Valsaraju if (IS_ERR(binder_logs_root_dir)) { 6130e13e452SHridya Valsaraju ret = PTR_ERR(binder_logs_root_dir); 6140e13e452SHridya Valsaraju goto out; 6150e13e452SHridya Valsaraju } 6160e13e452SHridya Valsaraju 6170e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "stats", 6180e13e452SHridya Valsaraju &binder_stats_fops, NULL); 6190e13e452SHridya Valsaraju if (IS_ERR(dentry)) { 6200e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6210e13e452SHridya Valsaraju goto out; 6220e13e452SHridya Valsaraju } 6230e13e452SHridya Valsaraju 6240e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "state", 6250e13e452SHridya Valsaraju &binder_state_fops, NULL); 6260e13e452SHridya Valsaraju if (IS_ERR(dentry)) { 6270e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6280e13e452SHridya Valsaraju goto out; 6290e13e452SHridya Valsaraju } 6300e13e452SHridya Valsaraju 6310e13e452SHridya Valsaraju dentry = binderfs_create_file(binder_logs_root_dir, "transactions", 6320e13e452SHridya Valsaraju &binder_transactions_fops, NULL); 6330e13e452SHridya Valsaraju if (IS_ERR(dentry)) 6340e13e452SHridya Valsaraju ret = PTR_ERR(dentry); 6350e13e452SHridya Valsaraju 6360e13e452SHridya Valsaraju out: 6370e13e452SHridya Valsaraju return ret; 6380e13e452SHridya Valsaraju } 6390e13e452SHridya Valsaraju 6403ad20fe3SChristian Brauner static int binderfs_fill_super(struct super_block *sb, void *data, int silent) 6413ad20fe3SChristian Brauner { 64236975fc3SChristian Brauner int ret; 6433ad20fe3SChristian Brauner struct binderfs_info *info; 6443ad20fe3SChristian Brauner struct inode *inode = NULL; 645ca2864c6SHridya Valsaraju struct binderfs_device device_info = { 0 }; 646ca2864c6SHridya Valsaraju const char *name; 647ca2864c6SHridya Valsaraju size_t len; 6483ad20fe3SChristian Brauner 6493ad20fe3SChristian Brauner sb->s_blocksize = PAGE_SIZE; 6503ad20fe3SChristian Brauner sb->s_blocksize_bits = PAGE_SHIFT; 6513ad20fe3SChristian Brauner 6523ad20fe3SChristian Brauner /* 6533ad20fe3SChristian Brauner * The binderfs filesystem can be mounted by userns root in a 6543ad20fe3SChristian Brauner * non-initial userns. By default such mounts have the SB_I_NODEV flag 6553ad20fe3SChristian Brauner * set in s_iflags to prevent security issues where userns root can 6563ad20fe3SChristian Brauner * just create random device nodes via mknod() since it owns the 6573ad20fe3SChristian Brauner * filesystem mount. But binderfs does not allow to create any files 6583ad20fe3SChristian Brauner * including devices nodes. The only way to create binder devices nodes 6593ad20fe3SChristian Brauner * is through the binder-control device which userns root is explicitly 6603ad20fe3SChristian Brauner * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both 6613ad20fe3SChristian Brauner * necessary and safe. 6623ad20fe3SChristian Brauner */ 6633ad20fe3SChristian Brauner sb->s_iflags &= ~SB_I_NODEV; 6643ad20fe3SChristian Brauner sb->s_iflags |= SB_I_NOEXEC; 6653ad20fe3SChristian Brauner sb->s_magic = BINDERFS_SUPER_MAGIC; 6663ad20fe3SChristian Brauner sb->s_op = &binderfs_super_ops; 6673ad20fe3SChristian Brauner sb->s_time_gran = 1; 6683ad20fe3SChristian Brauner 66936975fc3SChristian Brauner sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); 67036975fc3SChristian Brauner if (!sb->s_fs_info) 67136975fc3SChristian Brauner return -ENOMEM; 67236975fc3SChristian Brauner info = sb->s_fs_info; 67336975fc3SChristian Brauner 67436975fc3SChristian Brauner info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); 6753ad20fe3SChristian Brauner 676849d540dSChristian Brauner ret = binderfs_parse_mount_opts(data, &info->mount_opts); 677849d540dSChristian Brauner if (ret) 67836975fc3SChristian Brauner return ret; 679849d540dSChristian Brauner 6803ad20fe3SChristian Brauner info->root_gid = make_kgid(sb->s_user_ns, 0); 6813ad20fe3SChristian Brauner if (!gid_valid(info->root_gid)) 6823ad20fe3SChristian Brauner info->root_gid = GLOBAL_ROOT_GID; 6833ad20fe3SChristian Brauner info->root_uid = make_kuid(sb->s_user_ns, 0); 6843ad20fe3SChristian Brauner if (!uid_valid(info->root_uid)) 6853ad20fe3SChristian Brauner info->root_uid = GLOBAL_ROOT_UID; 6863ad20fe3SChristian Brauner 6873ad20fe3SChristian Brauner inode = new_inode(sb); 6883ad20fe3SChristian Brauner if (!inode) 68936975fc3SChristian Brauner return -ENOMEM; 6903ad20fe3SChristian Brauner 6913ad20fe3SChristian Brauner inode->i_ino = FIRST_INODE; 6923ad20fe3SChristian Brauner inode->i_fop = &simple_dir_operations; 6933ad20fe3SChristian Brauner inode->i_mode = S_IFDIR | 0755; 6943ad20fe3SChristian Brauner inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 6953ad20fe3SChristian Brauner inode->i_op = &binderfs_dir_inode_operations; 6963ad20fe3SChristian Brauner set_nlink(inode, 2); 6973ad20fe3SChristian Brauner 6983ad20fe3SChristian Brauner sb->s_root = d_make_root(inode); 6993ad20fe3SChristian Brauner if (!sb->s_root) 70036975fc3SChristian Brauner return -ENOMEM; 7013ad20fe3SChristian Brauner 702ca2864c6SHridya Valsaraju ret = binderfs_binder_ctl_create(sb); 703ca2864c6SHridya Valsaraju if (ret) 704ca2864c6SHridya Valsaraju return ret; 705ca2864c6SHridya Valsaraju 706ca2864c6SHridya Valsaraju name = binder_devices_param; 707ca2864c6SHridya Valsaraju for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 708ca2864c6SHridya Valsaraju strscpy(device_info.name, name, len + 1); 709ca2864c6SHridya Valsaraju ret = binderfs_binder_device_create(inode, NULL, &device_info); 710ca2864c6SHridya Valsaraju if (ret) 711ca2864c6SHridya Valsaraju return ret; 712ca2864c6SHridya Valsaraju name += len; 713ca2864c6SHridya Valsaraju if (*name == ',') 714ca2864c6SHridya Valsaraju name++; 715ca2864c6SHridya Valsaraju } 716ca2864c6SHridya Valsaraju 7170e13e452SHridya Valsaraju if (info->mount_opts.stats_mode == STATS_GLOBAL) 7180e13e452SHridya Valsaraju return init_binder_logs(sb); 7190e13e452SHridya Valsaraju 720ca2864c6SHridya Valsaraju return 0; 7213ad20fe3SChristian Brauner } 7223ad20fe3SChristian Brauner 7233ad20fe3SChristian Brauner static struct dentry *binderfs_mount(struct file_system_type *fs_type, 7243ad20fe3SChristian Brauner int flags, const char *dev_name, 7253ad20fe3SChristian Brauner void *data) 7263ad20fe3SChristian Brauner { 727b6c770d7SChristian Brauner return mount_nodev(fs_type, flags, data, binderfs_fill_super); 7283ad20fe3SChristian Brauner } 7293ad20fe3SChristian Brauner 7303ad20fe3SChristian Brauner static void binderfs_kill_super(struct super_block *sb) 7313ad20fe3SChristian Brauner { 7323ad20fe3SChristian Brauner struct binderfs_info *info = sb->s_fs_info; 7333ad20fe3SChristian Brauner 73441984795SChristian Brauner kill_litter_super(sb); 73541984795SChristian Brauner 7363ad20fe3SChristian Brauner if (info && info->ipc_ns) 7373ad20fe3SChristian Brauner put_ipc_ns(info->ipc_ns); 7383ad20fe3SChristian Brauner 7393ad20fe3SChristian Brauner kfree(info); 7403ad20fe3SChristian Brauner } 7413ad20fe3SChristian Brauner 7423ad20fe3SChristian Brauner static struct file_system_type binder_fs_type = { 7433ad20fe3SChristian Brauner .name = "binder", 7443ad20fe3SChristian Brauner .mount = binderfs_mount, 7453ad20fe3SChristian Brauner .kill_sb = binderfs_kill_super, 7463ad20fe3SChristian Brauner .fs_flags = FS_USERNS_MOUNT, 7473ad20fe3SChristian Brauner }; 7483ad20fe3SChristian Brauner 7495b9633afSChristian Brauner int __init init_binderfs(void) 7503ad20fe3SChristian Brauner { 7513ad20fe3SChristian Brauner int ret; 752028fb582SHridya Valsaraju const char *name; 753028fb582SHridya Valsaraju size_t len; 754028fb582SHridya Valsaraju 755028fb582SHridya Valsaraju /* Verify that the default binderfs device names are valid. */ 756028fb582SHridya Valsaraju name = binder_devices_param; 757028fb582SHridya Valsaraju for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) { 758028fb582SHridya Valsaraju if (len > BINDERFS_MAX_NAME) 759028fb582SHridya Valsaraju return -E2BIG; 760028fb582SHridya Valsaraju name += len; 761028fb582SHridya Valsaraju if (*name == ',') 762028fb582SHridya Valsaraju name++; 763028fb582SHridya Valsaraju } 7643ad20fe3SChristian Brauner 7653ad20fe3SChristian Brauner /* Allocate new major number for binderfs. */ 7663ad20fe3SChristian Brauner ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR, 7673ad20fe3SChristian Brauner "binder"); 7683ad20fe3SChristian Brauner if (ret) 7693ad20fe3SChristian Brauner return ret; 7703ad20fe3SChristian Brauner 7713ad20fe3SChristian Brauner ret = register_filesystem(&binder_fs_type); 7723ad20fe3SChristian Brauner if (ret) { 7733ad20fe3SChristian Brauner unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); 7743ad20fe3SChristian Brauner return ret; 7753ad20fe3SChristian Brauner } 7763ad20fe3SChristian Brauner 7773ad20fe3SChristian Brauner return ret; 7783ad20fe3SChristian Brauner } 779