Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7aeb384a authored by Hridya Valsaraju's avatar Hridya Valsaraju
Browse files

UPSTREAM: binder: Add stats, state and transactions files



The following binder stat files currently live in debugfs.

/sys/kernel/debug/binder/state
/sys/kernel/debug/binder/stats
/sys/kernel/debug/binder/transactions

This patch makes these files available in a binderfs instance
mounted with the mount option 'stats=global'. For example, if a binderfs
instance is mounted at path /dev/binderfs, the above files will be
available at the following locations:

/dev/binderfs/binder_logs/state
/dev/binderfs/binder_logs/stats
/dev/binderfs/binder_logs/transactions

This provides a way to access them even when debugfs is not mounted.

Acked-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: default avatarHridya Valsaraju <hridya@google.com>
Acked-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20190903161655.107408-3-hridya@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>

Bug: 136497735
(cherry picked from commit 0e13e452dafc009049a9a5a4153e2f9e51b23915)
Change-Id: Ieeb666a719fb3195133403054de7b103a358e1ae
parent 2c164059
Loading
Loading
Loading
Loading
+6 −9
Original line number Diff line number Diff line
@@ -5905,7 +5905,7 @@ static void print_binder_proc_stats(struct seq_file *m,
}


static int state_show(struct seq_file *m, void *unused)
int binder_state_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;
	struct binder_node *node;
@@ -5944,7 +5944,7 @@ static int state_show(struct seq_file *m, void *unused)
	return 0;
}

static int stats_show(struct seq_file *m, void *unused)
int binder_stats_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;

@@ -5960,7 +5960,7 @@ static int stats_show(struct seq_file *m, void *unused)
	return 0;
}

static int transactions_show(struct seq_file *m, void *unused)
int binder_transactions_show(struct seq_file *m, void *unused)
{
	struct binder_proc *proc;

@@ -6048,9 +6048,6 @@ const struct file_operations binder_fops = {
	.release = binder_release,
};

DEFINE_SHOW_ATTRIBUTE(state);
DEFINE_SHOW_ATTRIBUTE(stats);
DEFINE_SHOW_ATTRIBUTE(transactions);
DEFINE_SHOW_ATTRIBUTE(transaction_log);

static int __init init_binder_device(const char *name)
@@ -6106,17 +6103,17 @@ static int __init binder_init(void)
				    0444,
				    binder_debugfs_dir_entry_root,
				    NULL,
				    &state_fops);
				    &binder_state_fops);
		debugfs_create_file("stats",
				    0444,
				    binder_debugfs_dir_entry_root,
				    NULL,
				    &stats_fops);
				    &binder_stats_fops);
		debugfs_create_file("transactions",
				    0444,
				    binder_debugfs_dir_entry_root,
				    NULL,
				    &transactions_fops);
				    &binder_transactions_fops);
		debugfs_create_file("transaction_log",
				    0444,
				    binder_debugfs_dir_entry_root,
+8 −0
Original line number Diff line number Diff line
@@ -57,4 +57,12 @@ static inline int __init init_binderfs(void)
}
#endif

int binder_stats_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_stats);

int binder_state_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_state);

int binder_transactions_show(struct seq_file *m, void *unused);
DEFINE_SHOW_ATTRIBUTE(binder_transactions);
#endif /* _LINUX_BINDER_INTERNAL_H */
+139 −1
Original line number Diff line number Diff line
@@ -280,7 +280,7 @@ static void binderfs_evict_inode(struct inode *inode)

	clear_inode(inode);

	if (!device)
	if (!S_ISCHR(inode->i_mode) || !device)
		return;

	mutex_lock(&binderfs_minors_mutex);
@@ -502,6 +502,141 @@ static const struct inode_operations binderfs_dir_inode_operations = {
	.unlink = binderfs_unlink,
};

static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
{
	struct inode *ret;

	ret = new_inode(sb);
	if (ret) {
		ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET);
		ret->i_mode = mode;
		ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
	}
	return ret;
}

static struct dentry *binderfs_create_dentry(struct dentry *parent,
					     const char *name)
{
	struct dentry *dentry;

	dentry = lookup_one_len(name, parent, strlen(name));
	if (IS_ERR(dentry))
		return dentry;

	/* Return error if the file/dir already exists. */
	if (d_really_is_positive(dentry)) {
		dput(dentry);
		return ERR_PTR(-EEXIST);
	}

	return dentry;
}

static struct dentry *binderfs_create_file(struct dentry *parent,
					   const char *name,
					   const struct file_operations *fops,
					   void *data)
{
	struct dentry *dentry;
	struct inode *new_inode, *parent_inode;
	struct super_block *sb;

	parent_inode = d_inode(parent);
	inode_lock(parent_inode);

	dentry = binderfs_create_dentry(parent, name);
	if (IS_ERR(dentry))
		goto out;

	sb = parent_inode->i_sb;
	new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
	if (!new_inode) {
		dput(dentry);
		dentry = ERR_PTR(-ENOMEM);
		goto out;
	}

	new_inode->i_fop = fops;
	new_inode->i_private = data;
	d_instantiate(dentry, new_inode);
	fsnotify_create(parent_inode, dentry);

out:
	inode_unlock(parent_inode);
	return dentry;
}

static struct dentry *binderfs_create_dir(struct dentry *parent,
					  const char *name)
{
	struct dentry *dentry;
	struct inode *new_inode, *parent_inode;
	struct super_block *sb;

	parent_inode = d_inode(parent);
	inode_lock(parent_inode);

	dentry = binderfs_create_dentry(parent, name);
	if (IS_ERR(dentry))
		goto out;

	sb = parent_inode->i_sb;
	new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
	if (!new_inode) {
		dput(dentry);
		dentry = ERR_PTR(-ENOMEM);
		goto out;
	}

	new_inode->i_fop = &simple_dir_operations;
	new_inode->i_op = &simple_dir_inode_operations;

	set_nlink(new_inode, 2);
	d_instantiate(dentry, new_inode);
	inc_nlink(parent_inode);
	fsnotify_mkdir(parent_inode, dentry);

out:
	inode_unlock(parent_inode);
	return dentry;
}

static int init_binder_logs(struct super_block *sb)
{
	struct dentry *binder_logs_root_dir, *dentry;
	int ret = 0;

	binder_logs_root_dir = binderfs_create_dir(sb->s_root,
						   "binder_logs");
	if (IS_ERR(binder_logs_root_dir)) {
		ret = PTR_ERR(binder_logs_root_dir);
		goto out;
	}

	dentry = binderfs_create_file(binder_logs_root_dir, "stats",
				      &binder_stats_fops, NULL);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
		goto out;
	}

	dentry = binderfs_create_file(binder_logs_root_dir, "state",
				      &binder_state_fops, NULL);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
		goto out;
	}

	dentry = binderfs_create_file(binder_logs_root_dir, "transactions",
				      &binder_transactions_fops, NULL);
	if (IS_ERR(dentry))
		ret = PTR_ERR(dentry);

out:
	return ret;
}

static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
{
	int ret;
@@ -579,6 +714,9 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
			name++;
	}

	if (info->mount_opts.stats_mode == STATS_GLOBAL)
		return init_binder_logs(sb);

	return 0;
}