18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/compiler_types.h>
48c2ecf20Sopenharmony_ci#include <linux/errno.h>
58c2ecf20Sopenharmony_ci#include <linux/fs.h>
68c2ecf20Sopenharmony_ci#include <linux/fsnotify.h>
78c2ecf20Sopenharmony_ci#include <linux/gfp.h>
88c2ecf20Sopenharmony_ci#include <linux/idr.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/ipc_namespace.h>
118c2ecf20Sopenharmony_ci#include <linux/kdev_t.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/namei.h>
158c2ecf20Sopenharmony_ci#include <linux/magic.h>
168c2ecf20Sopenharmony_ci#include <linux/major.h>
178c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/mutex.h>
208c2ecf20Sopenharmony_ci#include <linux/mount.h>
218c2ecf20Sopenharmony_ci#include <linux/fs_parser.h>
228c2ecf20Sopenharmony_ci#include <linux/radix-tree.h>
238c2ecf20Sopenharmony_ci#include <linux/sched.h>
248c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
258c2ecf20Sopenharmony_ci#include <linux/slab.h>
268c2ecf20Sopenharmony_ci#include <linux/spinlock_types.h>
278c2ecf20Sopenharmony_ci#include <linux/stddef.h>
288c2ecf20Sopenharmony_ci#include <linux/string.h>
298c2ecf20Sopenharmony_ci#include <linux/types.h>
308c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
318c2ecf20Sopenharmony_ci#include <linux/user_namespace.h>
328c2ecf20Sopenharmony_ci#include <linux/xarray.h>
338c2ecf20Sopenharmony_ci#include <uapi/asm-generic/errno-base.h>
348c2ecf20Sopenharmony_ci#include <uapi/linux/android/binder.h>
358c2ecf20Sopenharmony_ci#include <uapi/linux/android/binderfs.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "binder_internal.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define FIRST_INODE 1
408c2ecf20Sopenharmony_ci#define SECOND_INODE 2
418c2ecf20Sopenharmony_ci#define INODE_OFFSET 3
428c2ecf20Sopenharmony_ci#define INTSTRLEN 21
438c2ecf20Sopenharmony_ci#define BINDERFS_MAX_MINOR (1U << MINORBITS)
448c2ecf20Sopenharmony_ci/* Ensure that the initial ipc namespace always has devices available. */
458c2ecf20Sopenharmony_ci#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic dev_t binderfs_dev;
488c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(binderfs_minors_mutex);
498c2ecf20Sopenharmony_cistatic DEFINE_IDA(binderfs_minors);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cienum binderfs_param {
528c2ecf20Sopenharmony_ci	Opt_max,
538c2ecf20Sopenharmony_ci	Opt_stats_mode,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cienum binderfs_stats_mode {
578c2ecf20Sopenharmony_ci	binderfs_stats_mode_unset,
588c2ecf20Sopenharmony_ci	binderfs_stats_mode_global,
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const struct constant_table binderfs_param_stats[] = {
628c2ecf20Sopenharmony_ci	{ "global", binderfs_stats_mode_global },
638c2ecf20Sopenharmony_ci	{}
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec binderfs_fs_parameters[] = {
678c2ecf20Sopenharmony_ci	fsparam_u32("max",	Opt_max),
688c2ecf20Sopenharmony_ci	fsparam_enum("stats",	Opt_stats_mode, binderfs_param_stats),
698c2ecf20Sopenharmony_ci	{}
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return sb->s_fs_info;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cibool is_binderfs_device(const struct inode *inode)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC)
808c2ecf20Sopenharmony_ci		return true;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return false;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/**
868c2ecf20Sopenharmony_ci * binderfs_binder_device_create - allocate inode from super block of a
878c2ecf20Sopenharmony_ci *                                 binderfs mount
888c2ecf20Sopenharmony_ci * @ref_inode: inode from wich the super block will be taken
898c2ecf20Sopenharmony_ci * @userp:     buffer to copy information about new device for userspace to
908c2ecf20Sopenharmony_ci * @req:       struct binderfs_device as copied from userspace
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * This function allocates a new binder_device and reserves a new minor
938c2ecf20Sopenharmony_ci * number for it.
948c2ecf20Sopenharmony_ci * Minor numbers are limited and tracked globally in binderfs_minors. The
958c2ecf20Sopenharmony_ci * function will stash a struct binder_device for the specific binder
968c2ecf20Sopenharmony_ci * device in i_private of the inode.
978c2ecf20Sopenharmony_ci * It will go on to allocate a new inode from the super block of the
988c2ecf20Sopenharmony_ci * filesystem mount, stash a struct binder_device in its i_private field
998c2ecf20Sopenharmony_ci * and attach a dentry to that inode.
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno on failure
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cistatic int binderfs_binder_device_create(struct inode *ref_inode,
1048c2ecf20Sopenharmony_ci					 struct binderfs_device __user *userp,
1058c2ecf20Sopenharmony_ci					 struct binderfs_device *req)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int minor, ret;
1088c2ecf20Sopenharmony_ci	struct dentry *dentry, *root;
1098c2ecf20Sopenharmony_ci	struct binder_device *device;
1108c2ecf20Sopenharmony_ci	char *name = NULL;
1118c2ecf20Sopenharmony_ci	size_t name_len;
1128c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
1138c2ecf20Sopenharmony_ci	struct super_block *sb = ref_inode->i_sb;
1148c2ecf20Sopenharmony_ci	struct binderfs_info *info = sb->s_fs_info;
1158c2ecf20Sopenharmony_ci#if defined(CONFIG_IPC_NS)
1168c2ecf20Sopenharmony_ci	bool use_reserve = (info->ipc_ns == &init_ipc_ns);
1178c2ecf20Sopenharmony_ci#else
1188c2ecf20Sopenharmony_ci	bool use_reserve = true;
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Reserve new minor number for the new device. */
1228c2ecf20Sopenharmony_ci	mutex_lock(&binderfs_minors_mutex);
1238c2ecf20Sopenharmony_ci	if (++info->device_count <= info->mount_opts.max)
1248c2ecf20Sopenharmony_ci		minor = ida_alloc_max(&binderfs_minors,
1258c2ecf20Sopenharmony_ci				      use_reserve ? BINDERFS_MAX_MINOR :
1268c2ecf20Sopenharmony_ci						    BINDERFS_MAX_MINOR_CAPPED,
1278c2ecf20Sopenharmony_ci				      GFP_KERNEL);
1288c2ecf20Sopenharmony_ci	else
1298c2ecf20Sopenharmony_ci		minor = -ENOSPC;
1308c2ecf20Sopenharmony_ci	if (minor < 0) {
1318c2ecf20Sopenharmony_ci		--info->device_count;
1328c2ecf20Sopenharmony_ci		mutex_unlock(&binderfs_minors_mutex);
1338c2ecf20Sopenharmony_ci		return minor;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci	mutex_unlock(&binderfs_minors_mutex);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ret = -ENOMEM;
1388c2ecf20Sopenharmony_ci	device = kzalloc(sizeof(*device), GFP_KERNEL);
1398c2ecf20Sopenharmony_ci	if (!device)
1408c2ecf20Sopenharmony_ci		goto err;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	inode = new_inode(sb);
1438c2ecf20Sopenharmony_ci	if (!inode)
1448c2ecf20Sopenharmony_ci		goto err;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	inode->i_ino = minor + INODE_OFFSET;
1478c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
1488c2ecf20Sopenharmony_ci	init_special_inode(inode, S_IFCHR | 0600,
1498c2ecf20Sopenharmony_ci			   MKDEV(MAJOR(binderfs_dev), minor));
1508c2ecf20Sopenharmony_ci	inode->i_fop = &binder_fops;
1518c2ecf20Sopenharmony_ci	inode->i_uid = info->root_uid;
1528c2ecf20Sopenharmony_ci	inode->i_gid = info->root_gid;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */
1558c2ecf20Sopenharmony_ci	name_len = strlen(req->name);
1568c2ecf20Sopenharmony_ci	/* Make sure to include terminating NUL byte */
1578c2ecf20Sopenharmony_ci	name = kmemdup(req->name, name_len + 1, GFP_KERNEL);
1588c2ecf20Sopenharmony_ci	if (!name)
1598c2ecf20Sopenharmony_ci		goto err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	refcount_set(&device->ref, 1);
1628c2ecf20Sopenharmony_ci	device->binderfs_inode = inode;
1638c2ecf20Sopenharmony_ci	device->context.binder_context_mgr_uid = INVALID_UID;
1648c2ecf20Sopenharmony_ci	device->context.name = name;
1658c2ecf20Sopenharmony_ci	device->miscdev.name = name;
1668c2ecf20Sopenharmony_ci	device->miscdev.minor = minor;
1678c2ecf20Sopenharmony_ci	mutex_init(&device->context.context_mgr_node_lock);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	req->major = MAJOR(binderfs_dev);
1708c2ecf20Sopenharmony_ci	req->minor = minor;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (userp && copy_to_user(userp, req, sizeof(*req))) {
1738c2ecf20Sopenharmony_ci		ret = -EFAULT;
1748c2ecf20Sopenharmony_ci		goto err;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	root = sb->s_root;
1788c2ecf20Sopenharmony_ci	inode_lock(d_inode(root));
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* look it up */
1818c2ecf20Sopenharmony_ci	dentry = lookup_one_len(name, root, name_len);
1828c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
1838c2ecf20Sopenharmony_ci		inode_unlock(d_inode(root));
1848c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
1858c2ecf20Sopenharmony_ci		goto err;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (d_really_is_positive(dentry)) {
1898c2ecf20Sopenharmony_ci		/* already exists */
1908c2ecf20Sopenharmony_ci		dput(dentry);
1918c2ecf20Sopenharmony_ci		inode_unlock(d_inode(root));
1928c2ecf20Sopenharmony_ci		ret = -EEXIST;
1938c2ecf20Sopenharmony_ci		goto err;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	inode->i_private = device;
1978c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
1988c2ecf20Sopenharmony_ci	fsnotify_create(root->d_inode, dentry);
1998c2ecf20Sopenharmony_ci	inode_unlock(d_inode(root));
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cierr:
2048c2ecf20Sopenharmony_ci	kfree(name);
2058c2ecf20Sopenharmony_ci	kfree(device);
2068c2ecf20Sopenharmony_ci	mutex_lock(&binderfs_minors_mutex);
2078c2ecf20Sopenharmony_ci	--info->device_count;
2088c2ecf20Sopenharmony_ci	ida_free(&binderfs_minors, minor);
2098c2ecf20Sopenharmony_ci	mutex_unlock(&binderfs_minors_mutex);
2108c2ecf20Sopenharmony_ci	iput(inode);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return ret;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/**
2168c2ecf20Sopenharmony_ci * binderfs_ctl_ioctl - handle binder device node allocation requests
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci * The request handler for the binder-control device. All requests operate on
2198c2ecf20Sopenharmony_ci * the binderfs mount the binder-control device resides in:
2208c2ecf20Sopenharmony_ci * - BINDER_CTL_ADD
2218c2ecf20Sopenharmony_ci *   Allocate a new binder device.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno on failure
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic long binder_ctl_ioctl(struct file *file, unsigned int cmd,
2268c2ecf20Sopenharmony_ci			     unsigned long arg)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	int ret = -EINVAL;
2298c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
2308c2ecf20Sopenharmony_ci	struct binderfs_device __user *device = (struct binderfs_device __user *)arg;
2318c2ecf20Sopenharmony_ci	struct binderfs_device device_req;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	switch (cmd) {
2348c2ecf20Sopenharmony_ci	case BINDER_CTL_ADD:
2358c2ecf20Sopenharmony_ci		ret = copy_from_user(&device_req, device, sizeof(device_req));
2368c2ecf20Sopenharmony_ci		if (ret) {
2378c2ecf20Sopenharmony_ci			ret = -EFAULT;
2388c2ecf20Sopenharmony_ci			break;
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		ret = binderfs_binder_device_create(inode, device, &device_req);
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	default:
2448c2ecf20Sopenharmony_ci		break;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return ret;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void binderfs_evict_inode(struct inode *inode)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct binder_device *device = inode->i_private;
2538c2ecf20Sopenharmony_ci	struct binderfs_info *info = BINDERFS_SB(inode->i_sb);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	clear_inode(inode);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (!S_ISCHR(inode->i_mode) || !device)
2588c2ecf20Sopenharmony_ci		return;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	mutex_lock(&binderfs_minors_mutex);
2618c2ecf20Sopenharmony_ci	--info->device_count;
2628c2ecf20Sopenharmony_ci	ida_free(&binderfs_minors, device->miscdev.minor);
2638c2ecf20Sopenharmony_ci	mutex_unlock(&binderfs_minors_mutex);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&device->ref)) {
2668c2ecf20Sopenharmony_ci		kfree(device->context.name);
2678c2ecf20Sopenharmony_ci		kfree(device);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int binderfs_fs_context_parse_param(struct fs_context *fc,
2728c2ecf20Sopenharmony_ci					   struct fs_parameter *param)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	int opt;
2758c2ecf20Sopenharmony_ci	struct binderfs_mount_opts *ctx = fc->fs_private;
2768c2ecf20Sopenharmony_ci	struct fs_parse_result result;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	opt = fs_parse(fc, binderfs_fs_parameters, param, &result);
2798c2ecf20Sopenharmony_ci	if (opt < 0)
2808c2ecf20Sopenharmony_ci		return opt;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	switch (opt) {
2838c2ecf20Sopenharmony_ci	case Opt_max:
2848c2ecf20Sopenharmony_ci		if (result.uint_32 > BINDERFS_MAX_MINOR)
2858c2ecf20Sopenharmony_ci			return invalfc(fc, "Bad value for '%s'", param->key);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		ctx->max = result.uint_32;
2888c2ecf20Sopenharmony_ci		break;
2898c2ecf20Sopenharmony_ci	case Opt_stats_mode:
2908c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
2918c2ecf20Sopenharmony_ci			return -EPERM;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		ctx->stats_mode = result.uint_32;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	default:
2968c2ecf20Sopenharmony_ci		return invalfc(fc, "Unsupported parameter '%s'", param->key);
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int binderfs_fs_context_reconfigure(struct fs_context *fc)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct binderfs_mount_opts *ctx = fc->fs_private;
3058c2ecf20Sopenharmony_ci	struct binderfs_info *info = BINDERFS_SB(fc->root->d_sb);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (info->mount_opts.stats_mode != ctx->stats_mode)
3088c2ecf20Sopenharmony_ci		return invalfc(fc, "Binderfs stats mode cannot be changed during a remount");
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	info->mount_opts.stats_mode = ctx->stats_mode;
3118c2ecf20Sopenharmony_ci	info->mount_opts.max = ctx->max;
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int binderfs_show_options(struct seq_file *seq, struct dentry *root)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct binderfs_info *info = BINDERFS_SB(root->d_sb);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (info->mount_opts.max <= BINDERFS_MAX_MINOR)
3208c2ecf20Sopenharmony_ci		seq_printf(seq, ",max=%d", info->mount_opts.max);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	switch (info->mount_opts.stats_mode) {
3238c2ecf20Sopenharmony_ci	case binderfs_stats_mode_unset:
3248c2ecf20Sopenharmony_ci		break;
3258c2ecf20Sopenharmony_ci	case binderfs_stats_mode_global:
3268c2ecf20Sopenharmony_ci		seq_printf(seq, ",stats=global");
3278c2ecf20Sopenharmony_ci		break;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return 0;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic const struct super_operations binderfs_super_ops = {
3348c2ecf20Sopenharmony_ci	.evict_inode    = binderfs_evict_inode,
3358c2ecf20Sopenharmony_ci	.show_options	= binderfs_show_options,
3368c2ecf20Sopenharmony_ci	.statfs         = simple_statfs,
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic inline bool is_binderfs_control_device(const struct dentry *dentry)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct binderfs_info *info = dentry->d_sb->s_fs_info;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return info->control_dentry == dentry;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry,
3478c2ecf20Sopenharmony_ci			   struct inode *new_dir, struct dentry *new_dentry,
3488c2ecf20Sopenharmony_ci			   unsigned int flags)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	if (is_binderfs_control_device(old_dentry) ||
3518c2ecf20Sopenharmony_ci	    is_binderfs_control_device(new_dentry))
3528c2ecf20Sopenharmony_ci		return -EPERM;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic int binderfs_unlink(struct inode *dir, struct dentry *dentry)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	if (is_binderfs_control_device(dentry))
3608c2ecf20Sopenharmony_ci		return -EPERM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return simple_unlink(dir, dentry);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic const struct file_operations binder_ctl_fops = {
3668c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
3678c2ecf20Sopenharmony_ci	.open		= nonseekable_open,
3688c2ecf20Sopenharmony_ci	.unlocked_ioctl	= binder_ctl_ioctl,
3698c2ecf20Sopenharmony_ci	.compat_ioctl	= binder_ctl_ioctl,
3708c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/**
3748c2ecf20Sopenharmony_ci * binderfs_binder_ctl_create - create a new binder-control device
3758c2ecf20Sopenharmony_ci * @sb: super block of the binderfs mount
3768c2ecf20Sopenharmony_ci *
3778c2ecf20Sopenharmony_ci * This function creates a new binder-control device node in the binderfs mount
3788c2ecf20Sopenharmony_ci * referred to by @sb.
3798c2ecf20Sopenharmony_ci *
3808c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno on failure
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_cistatic int binderfs_binder_ctl_create(struct super_block *sb)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	int minor, ret;
3858c2ecf20Sopenharmony_ci	struct dentry *dentry;
3868c2ecf20Sopenharmony_ci	struct binder_device *device;
3878c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
3888c2ecf20Sopenharmony_ci	struct dentry *root = sb->s_root;
3898c2ecf20Sopenharmony_ci	struct binderfs_info *info = sb->s_fs_info;
3908c2ecf20Sopenharmony_ci#if defined(CONFIG_IPC_NS)
3918c2ecf20Sopenharmony_ci	bool use_reserve = (info->ipc_ns == &init_ipc_ns);
3928c2ecf20Sopenharmony_ci#else
3938c2ecf20Sopenharmony_ci	bool use_reserve = true;
3948c2ecf20Sopenharmony_ci#endif
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	device = kzalloc(sizeof(*device), GFP_KERNEL);
3978c2ecf20Sopenharmony_ci	if (!device)
3988c2ecf20Sopenharmony_ci		return -ENOMEM;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* If we have already created a binder-control node, return. */
4018c2ecf20Sopenharmony_ci	if (info->control_dentry) {
4028c2ecf20Sopenharmony_ci		ret = 0;
4038c2ecf20Sopenharmony_ci		goto out;
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	ret = -ENOMEM;
4078c2ecf20Sopenharmony_ci	inode = new_inode(sb);
4088c2ecf20Sopenharmony_ci	if (!inode)
4098c2ecf20Sopenharmony_ci		goto out;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* Reserve a new minor number for the new device. */
4128c2ecf20Sopenharmony_ci	mutex_lock(&binderfs_minors_mutex);
4138c2ecf20Sopenharmony_ci	minor = ida_alloc_max(&binderfs_minors,
4148c2ecf20Sopenharmony_ci			      use_reserve ? BINDERFS_MAX_MINOR :
4158c2ecf20Sopenharmony_ci					    BINDERFS_MAX_MINOR_CAPPED,
4168c2ecf20Sopenharmony_ci			      GFP_KERNEL);
4178c2ecf20Sopenharmony_ci	mutex_unlock(&binderfs_minors_mutex);
4188c2ecf20Sopenharmony_ci	if (minor < 0) {
4198c2ecf20Sopenharmony_ci		ret = minor;
4208c2ecf20Sopenharmony_ci		goto out;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	inode->i_ino = SECOND_INODE;
4248c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
4258c2ecf20Sopenharmony_ci	init_special_inode(inode, S_IFCHR | 0600,
4268c2ecf20Sopenharmony_ci			   MKDEV(MAJOR(binderfs_dev), minor));
4278c2ecf20Sopenharmony_ci	inode->i_fop = &binder_ctl_fops;
4288c2ecf20Sopenharmony_ci	inode->i_uid = info->root_uid;
4298c2ecf20Sopenharmony_ci	inode->i_gid = info->root_gid;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	refcount_set(&device->ref, 1);
4328c2ecf20Sopenharmony_ci	device->binderfs_inode = inode;
4338c2ecf20Sopenharmony_ci	device->miscdev.minor = minor;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	dentry = d_alloc_name(root, "binder-control");
4368c2ecf20Sopenharmony_ci	if (!dentry)
4378c2ecf20Sopenharmony_ci		goto out;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	inode->i_private = device;
4408c2ecf20Sopenharmony_ci	info->control_dentry = dentry;
4418c2ecf20Sopenharmony_ci	d_add(dentry, inode);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ciout:
4468c2ecf20Sopenharmony_ci	kfree(device);
4478c2ecf20Sopenharmony_ci	iput(inode);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return ret;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic const struct inode_operations binderfs_dir_inode_operations = {
4538c2ecf20Sopenharmony_ci	.lookup = simple_lookup,
4548c2ecf20Sopenharmony_ci	.rename = binderfs_rename,
4558c2ecf20Sopenharmony_ci	.unlink = binderfs_unlink,
4568c2ecf20Sopenharmony_ci};
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic struct inode *binderfs_make_inode(struct super_block *sb, int mode)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct inode *ret;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	ret = new_inode(sb);
4638c2ecf20Sopenharmony_ci	if (ret) {
4648c2ecf20Sopenharmony_ci		ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET);
4658c2ecf20Sopenharmony_ci		ret->i_mode = mode;
4668c2ecf20Sopenharmony_ci		ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci	return ret;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic struct dentry *binderfs_create_dentry(struct dentry *parent,
4728c2ecf20Sopenharmony_ci					     const char *name)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct dentry *dentry;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	dentry = lookup_one_len(name, parent, strlen(name));
4778c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
4788c2ecf20Sopenharmony_ci		return dentry;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* Return error if the file/dir already exists. */
4818c2ecf20Sopenharmony_ci	if (d_really_is_positive(dentry)) {
4828c2ecf20Sopenharmony_ci		dput(dentry);
4838c2ecf20Sopenharmony_ci		return ERR_PTR(-EEXIST);
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return dentry;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_civoid binderfs_remove_file(struct dentry *dentry)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	struct inode *parent_inode;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	parent_inode = d_inode(dentry->d_parent);
4948c2ecf20Sopenharmony_ci	inode_lock(parent_inode);
4958c2ecf20Sopenharmony_ci	if (simple_positive(dentry)) {
4968c2ecf20Sopenharmony_ci		dget(dentry);
4978c2ecf20Sopenharmony_ci		simple_unlink(parent_inode, dentry);
4988c2ecf20Sopenharmony_ci		d_delete(dentry);
4998c2ecf20Sopenharmony_ci		dput(dentry);
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	inode_unlock(parent_inode);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistruct dentry *binderfs_create_file(struct dentry *parent, const char *name,
5058c2ecf20Sopenharmony_ci				    const struct file_operations *fops,
5068c2ecf20Sopenharmony_ci				    void *data)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct dentry *dentry;
5098c2ecf20Sopenharmony_ci	struct inode *new_inode, *parent_inode;
5108c2ecf20Sopenharmony_ci	struct super_block *sb;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	parent_inode = d_inode(parent);
5138c2ecf20Sopenharmony_ci	inode_lock(parent_inode);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	dentry = binderfs_create_dentry(parent, name);
5168c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
5178c2ecf20Sopenharmony_ci		goto out;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	sb = parent_inode->i_sb;
5208c2ecf20Sopenharmony_ci	new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
5218c2ecf20Sopenharmony_ci	if (!new_inode) {
5228c2ecf20Sopenharmony_ci		dput(dentry);
5238c2ecf20Sopenharmony_ci		dentry = ERR_PTR(-ENOMEM);
5248c2ecf20Sopenharmony_ci		goto out;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	new_inode->i_fop = fops;
5288c2ecf20Sopenharmony_ci	new_inode->i_private = data;
5298c2ecf20Sopenharmony_ci	d_instantiate(dentry, new_inode);
5308c2ecf20Sopenharmony_ci	fsnotify_create(parent_inode, dentry);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ciout:
5338c2ecf20Sopenharmony_ci	inode_unlock(parent_inode);
5348c2ecf20Sopenharmony_ci	return dentry;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic struct dentry *binderfs_create_dir(struct dentry *parent,
5388c2ecf20Sopenharmony_ci					  const char *name)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct dentry *dentry;
5418c2ecf20Sopenharmony_ci	struct inode *new_inode, *parent_inode;
5428c2ecf20Sopenharmony_ci	struct super_block *sb;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	parent_inode = d_inode(parent);
5458c2ecf20Sopenharmony_ci	inode_lock(parent_inode);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	dentry = binderfs_create_dentry(parent, name);
5488c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
5498c2ecf20Sopenharmony_ci		goto out;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	sb = parent_inode->i_sb;
5528c2ecf20Sopenharmony_ci	new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
5538c2ecf20Sopenharmony_ci	if (!new_inode) {
5548c2ecf20Sopenharmony_ci		dput(dentry);
5558c2ecf20Sopenharmony_ci		dentry = ERR_PTR(-ENOMEM);
5568c2ecf20Sopenharmony_ci		goto out;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	new_inode->i_fop = &simple_dir_operations;
5608c2ecf20Sopenharmony_ci	new_inode->i_op = &simple_dir_inode_operations;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	set_nlink(new_inode, 2);
5638c2ecf20Sopenharmony_ci	d_instantiate(dentry, new_inode);
5648c2ecf20Sopenharmony_ci	inc_nlink(parent_inode);
5658c2ecf20Sopenharmony_ci	fsnotify_mkdir(parent_inode, dentry);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ciout:
5688c2ecf20Sopenharmony_ci	inode_unlock(parent_inode);
5698c2ecf20Sopenharmony_ci	return dentry;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic int init_binder_logs(struct super_block *sb)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
5758c2ecf20Sopenharmony_ci	struct binderfs_info *info;
5768c2ecf20Sopenharmony_ci	int ret = 0;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	binder_logs_root_dir = binderfs_create_dir(sb->s_root,
5798c2ecf20Sopenharmony_ci						   "binder_logs");
5808c2ecf20Sopenharmony_ci	if (IS_ERR(binder_logs_root_dir)) {
5818c2ecf20Sopenharmony_ci		ret = PTR_ERR(binder_logs_root_dir);
5828c2ecf20Sopenharmony_ci		goto out;
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	dentry = binderfs_create_file(binder_logs_root_dir, "stats",
5868c2ecf20Sopenharmony_ci				      &binder_stats_fops, NULL);
5878c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
5888c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
5898c2ecf20Sopenharmony_ci		goto out;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	dentry = binderfs_create_file(binder_logs_root_dir, "state",
5938c2ecf20Sopenharmony_ci				      &binder_state_fops, NULL);
5948c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
5958c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
5968c2ecf20Sopenharmony_ci		goto out;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	dentry = binderfs_create_file(binder_logs_root_dir, "transactions",
6008c2ecf20Sopenharmony_ci				      &binder_transactions_fops, NULL);
6018c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
6028c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
6038c2ecf20Sopenharmony_ci		goto out;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	dentry = binderfs_create_file(binder_logs_root_dir,
6078c2ecf20Sopenharmony_ci				      "transaction_log",
6088c2ecf20Sopenharmony_ci				      &binder_transaction_log_fops,
6098c2ecf20Sopenharmony_ci				      &binder_transaction_log);
6108c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
6118c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
6128c2ecf20Sopenharmony_ci		goto out;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	dentry = binderfs_create_file(binder_logs_root_dir,
6168c2ecf20Sopenharmony_ci				      "failed_transaction_log",
6178c2ecf20Sopenharmony_ci				      &binder_transaction_log_fops,
6188c2ecf20Sopenharmony_ci				      &binder_transaction_log_failed);
6198c2ecf20Sopenharmony_ci	if (IS_ERR(dentry)) {
6208c2ecf20Sopenharmony_ci		ret = PTR_ERR(dentry);
6218c2ecf20Sopenharmony_ci		goto out;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc");
6258c2ecf20Sopenharmony_ci	if (IS_ERR(proc_log_dir)) {
6268c2ecf20Sopenharmony_ci		ret = PTR_ERR(proc_log_dir);
6278c2ecf20Sopenharmony_ci		goto out;
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci	info = sb->s_fs_info;
6308c2ecf20Sopenharmony_ci	info->proc_log_dir = proc_log_dir;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ciout:
6338c2ecf20Sopenharmony_ci	return ret;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	int ret;
6398c2ecf20Sopenharmony_ci	struct binderfs_info *info;
6408c2ecf20Sopenharmony_ci	struct binderfs_mount_opts *ctx = fc->fs_private;
6418c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
6428c2ecf20Sopenharmony_ci	struct binderfs_device device_info = {};
6438c2ecf20Sopenharmony_ci	const char *name;
6448c2ecf20Sopenharmony_ci	size_t len;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	sb->s_blocksize = PAGE_SIZE;
6478c2ecf20Sopenharmony_ci	sb->s_blocksize_bits = PAGE_SHIFT;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/*
6508c2ecf20Sopenharmony_ci	 * The binderfs filesystem can be mounted by userns root in a
6518c2ecf20Sopenharmony_ci	 * non-initial userns. By default such mounts have the SB_I_NODEV flag
6528c2ecf20Sopenharmony_ci	 * set in s_iflags to prevent security issues where userns root can
6538c2ecf20Sopenharmony_ci	 * just create random device nodes via mknod() since it owns the
6548c2ecf20Sopenharmony_ci	 * filesystem mount. But binderfs does not allow to create any files
6558c2ecf20Sopenharmony_ci	 * including devices nodes. The only way to create binder devices nodes
6568c2ecf20Sopenharmony_ci	 * is through the binder-control device which userns root is explicitly
6578c2ecf20Sopenharmony_ci	 * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both
6588c2ecf20Sopenharmony_ci	 * necessary and safe.
6598c2ecf20Sopenharmony_ci	 */
6608c2ecf20Sopenharmony_ci	sb->s_iflags &= ~SB_I_NODEV;
6618c2ecf20Sopenharmony_ci	sb->s_iflags |= SB_I_NOEXEC;
6628c2ecf20Sopenharmony_ci	sb->s_magic = BINDERFS_SUPER_MAGIC;
6638c2ecf20Sopenharmony_ci	sb->s_op = &binderfs_super_ops;
6648c2ecf20Sopenharmony_ci	sb->s_time_gran = 1;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
6678c2ecf20Sopenharmony_ci	if (!sb->s_fs_info)
6688c2ecf20Sopenharmony_ci		return -ENOMEM;
6698c2ecf20Sopenharmony_ci	info = sb->s_fs_info;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	info->root_gid = make_kgid(sb->s_user_ns, 0);
6748c2ecf20Sopenharmony_ci	if (!gid_valid(info->root_gid))
6758c2ecf20Sopenharmony_ci		info->root_gid = GLOBAL_ROOT_GID;
6768c2ecf20Sopenharmony_ci	info->root_uid = make_kuid(sb->s_user_ns, 0);
6778c2ecf20Sopenharmony_ci	if (!uid_valid(info->root_uid))
6788c2ecf20Sopenharmony_ci		info->root_uid = GLOBAL_ROOT_UID;
6798c2ecf20Sopenharmony_ci	info->mount_opts.max = ctx->max;
6808c2ecf20Sopenharmony_ci	info->mount_opts.stats_mode = ctx->stats_mode;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	inode = new_inode(sb);
6838c2ecf20Sopenharmony_ci	if (!inode)
6848c2ecf20Sopenharmony_ci		return -ENOMEM;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	inode->i_ino = FIRST_INODE;
6878c2ecf20Sopenharmony_ci	inode->i_fop = &simple_dir_operations;
6888c2ecf20Sopenharmony_ci	inode->i_mode = S_IFDIR | 0755;
6898c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
6908c2ecf20Sopenharmony_ci	inode->i_op = &binderfs_dir_inode_operations;
6918c2ecf20Sopenharmony_ci	set_nlink(inode, 2);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	sb->s_root = d_make_root(inode);
6948c2ecf20Sopenharmony_ci	if (!sb->s_root)
6958c2ecf20Sopenharmony_ci		return -ENOMEM;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	ret = binderfs_binder_ctl_create(sb);
6988c2ecf20Sopenharmony_ci	if (ret)
6998c2ecf20Sopenharmony_ci		return ret;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	name = binder_devices_param;
7028c2ecf20Sopenharmony_ci	for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {
7038c2ecf20Sopenharmony_ci		strscpy(device_info.name, name, len + 1);
7048c2ecf20Sopenharmony_ci		ret = binderfs_binder_device_create(inode, NULL, &device_info);
7058c2ecf20Sopenharmony_ci		if (ret)
7068c2ecf20Sopenharmony_ci			return ret;
7078c2ecf20Sopenharmony_ci		name += len;
7088c2ecf20Sopenharmony_ci		if (*name == ',')
7098c2ecf20Sopenharmony_ci			name++;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
7138c2ecf20Sopenharmony_ci		return init_binder_logs(sb);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic int binderfs_fs_context_get_tree(struct fs_context *fc)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	return get_tree_nodev(fc, binderfs_fill_super);
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void binderfs_fs_context_free(struct fs_context *fc)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	struct binderfs_mount_opts *ctx = fc->fs_private;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	kfree(ctx);
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic const struct fs_context_operations binderfs_fs_context_ops = {
7318c2ecf20Sopenharmony_ci	.free		= binderfs_fs_context_free,
7328c2ecf20Sopenharmony_ci	.get_tree	= binderfs_fs_context_get_tree,
7338c2ecf20Sopenharmony_ci	.parse_param	= binderfs_fs_context_parse_param,
7348c2ecf20Sopenharmony_ci	.reconfigure	= binderfs_fs_context_reconfigure,
7358c2ecf20Sopenharmony_ci};
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cistatic int binderfs_init_fs_context(struct fs_context *fc)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct binderfs_mount_opts *ctx;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(struct binderfs_mount_opts), GFP_KERNEL);
7428c2ecf20Sopenharmony_ci	if (!ctx)
7438c2ecf20Sopenharmony_ci		return -ENOMEM;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	ctx->max = BINDERFS_MAX_MINOR;
7468c2ecf20Sopenharmony_ci	ctx->stats_mode = binderfs_stats_mode_unset;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	fc->fs_private = ctx;
7498c2ecf20Sopenharmony_ci	fc->ops = &binderfs_fs_context_ops;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic void binderfs_kill_super(struct super_block *sb)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct binderfs_info *info = sb->s_fs_info;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/*
7598c2ecf20Sopenharmony_ci	 * During inode eviction struct binderfs_info is needed.
7608c2ecf20Sopenharmony_ci	 * So first wipe the super_block then free struct binderfs_info.
7618c2ecf20Sopenharmony_ci	 */
7628c2ecf20Sopenharmony_ci	kill_litter_super(sb);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (info && info->ipc_ns)
7658c2ecf20Sopenharmony_ci		put_ipc_ns(info->ipc_ns);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	kfree(info);
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic struct file_system_type binder_fs_type = {
7718c2ecf20Sopenharmony_ci	.name			= "binder",
7728c2ecf20Sopenharmony_ci	.init_fs_context	= binderfs_init_fs_context,
7738c2ecf20Sopenharmony_ci	.parameters		= binderfs_fs_parameters,
7748c2ecf20Sopenharmony_ci	.kill_sb		= binderfs_kill_super,
7758c2ecf20Sopenharmony_ci	.fs_flags		= FS_USERNS_MOUNT,
7768c2ecf20Sopenharmony_ci};
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ciint __init init_binderfs(void)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	int ret;
7818c2ecf20Sopenharmony_ci	const char *name;
7828c2ecf20Sopenharmony_ci	size_t len;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	/* Verify that the default binderfs device names are valid. */
7858c2ecf20Sopenharmony_ci	name = binder_devices_param;
7868c2ecf20Sopenharmony_ci	for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {
7878c2ecf20Sopenharmony_ci		if (len > BINDERFS_MAX_NAME)
7888c2ecf20Sopenharmony_ci			return -E2BIG;
7898c2ecf20Sopenharmony_ci		name += len;
7908c2ecf20Sopenharmony_ci		if (*name == ',')
7918c2ecf20Sopenharmony_ci			name++;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* Allocate new major number for binderfs. */
7958c2ecf20Sopenharmony_ci	ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR,
7968c2ecf20Sopenharmony_ci				  "binder");
7978c2ecf20Sopenharmony_ci	if (ret)
7988c2ecf20Sopenharmony_ci		return ret;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	ret = register_filesystem(&binder_fs_type);
8018c2ecf20Sopenharmony_ci	if (ret) {
8028c2ecf20Sopenharmony_ci		unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);
8038c2ecf20Sopenharmony_ci		return ret;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	return ret;
8078c2ecf20Sopenharmony_ci}
808