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

Commit 725ce554 authored by Hridya Valsaraju's avatar Hridya Valsaraju
Browse files

UPSTREAM: binder: Add binder_proc logging to binderfs



Currently /sys/kernel/debug/binder/proc contains
the debug data for every binder_proc instance.
This patch makes this information also available
in a binderfs instance mounted with a mount option
"stats=global" in addition to debugfs. The patch does
not affect the presence of the file in debugfs.

If a binderfs instance is mounted at path /dev/binderfs,
this file would be present at /dev/binderfs/binder_logs/proc.
This change provides an alternate way to access this file when debugfs
is not mounted.

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


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

Bug: 136497735
(cherry picked from commit 4feb80faf428a02d407a9ea1952004af01308765)
Change-Id: I3aa974979f2d4aebbe79ea9df30ede2813826157
parent ce106a8d
Loading
Loading
Loading
Loading
+44 −2
Original line number Diff line number Diff line
@@ -491,6 +491,7 @@ struct binder_priority {
 * @inner_lock:           can nest under outer_lock and/or node lock
 * @outer_lock:           no nesting under innor or node lock
 *                        Lock order: 1) outer, 2) node, 3) inner
 * @binderfs_entry:       process-specific binderfs log file
 *
 * Bookkeeping structure for binder processes
 */
@@ -522,6 +523,7 @@ struct binder_proc {
	struct binder_context *context;
	spinlock_t inner_lock;
	spinlock_t outer_lock;
	struct dentry *binderfs_entry;
};

enum {
@@ -5181,6 +5183,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc;
	struct binder_device *binder_dev;
	struct binderfs_info *info;
	struct dentry *binder_binderfs_dir_entry_proc = NULL;

	binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
		     current->group_leader->pid, current->pid);
@@ -5203,11 +5207,14 @@ static int binder_open(struct inode *nodp, struct file *filp)
	}

	/* binderfs stashes devices in i_private */
	if (is_binderfs_device(nodp))
	if (is_binderfs_device(nodp)) {
		binder_dev = nodp->i_private;
	else
		info = nodp->i_sb->s_fs_info;
		binder_binderfs_dir_entry_proc = info->proc_log_dir;
	} else {
		binder_dev = container_of(filp->private_data,
					  struct binder_device, miscdev);
	}
	proc->context = &binder_dev->context;
	binder_alloc_init(&proc->alloc);

@@ -5238,6 +5245,35 @@ static int binder_open(struct inode *nodp, struct file *filp)
			&proc_fops);
	}

	if (binder_binderfs_dir_entry_proc) {
		char strbuf[11];
		struct dentry *binderfs_entry;

		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		/*
		 * Similar to debugfs, the process specific log file is shared
		 * between contexts. If the file has already been created for a
		 * process, the following binderfs_create_file() call will
		 * fail with error code EEXIST if another context of the same
		 * process invoked binder_open(). This is ok since same as
		 * debugfs, the log file will contain information on all
		 * contexts of a given PID.
		 */
		binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
			strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
		if (!IS_ERR(binderfs_entry)) {
			proc->binderfs_entry = binderfs_entry;
		} else {
			int error;

			error = PTR_ERR(binderfs_entry);
			if (error != -EEXIST) {
				pr_warn("Unable to create file %s in binderfs (error %d)\n",
					strbuf, error);
			}
		}
	}

	return 0;
}

@@ -5277,6 +5313,12 @@ static int binder_release(struct inode *nodp, struct file *filp)
	struct binder_proc *proc = filp->private_data;

	debugfs_remove(proc->debugfs_entry);

	if (proc->binderfs_entry) {
		binderfs_remove_file(proc->binderfs_entry);
		proc->binderfs_entry = NULL;
	}

	binder_defer_work(proc, BINDER_DEFERRED_RELEASE);

	return 0;
+46 −0
Original line number Diff line number Diff line
@@ -35,17 +35,63 @@ struct binder_device {
	struct inode *binderfs_inode;
};

/**
 * binderfs_mount_opts - mount options for binderfs
 * @max: maximum number of allocatable binderfs binder devices
 * @stats_mode: enable binder stats in binderfs.
 */
struct binderfs_mount_opts {
	int max;
	int stats_mode;
};

/**
 * binderfs_info - information about a binderfs mount
 * @ipc_ns:         The ipc namespace the binderfs mount belongs to.
 * @control_dentry: This records the dentry of this binderfs mount
 *                  binder-control device.
 * @root_uid:       uid that needs to be used when a new binder device is
 *                  created.
 * @root_gid:       gid that needs to be used when a new binder device is
 *                  created.
 * @mount_opts:     The mount options in use.
 * @device_count:   The current number of allocated binder devices.
 * @proc_log_dir:   Pointer to the directory dentry containing process-specific
 *                  logs.
 */
struct binderfs_info {
	struct ipc_namespace *ipc_ns;
	struct dentry *control_dentry;
	kuid_t root_uid;
	kgid_t root_gid;
	struct binderfs_mount_opts mount_opts;
	int device_count;
	struct dentry *proc_log_dir;
};

extern const struct file_operations binder_fops;

extern char *binder_devices_param;

#ifdef CONFIG_ANDROID_BINDERFS
extern bool is_binderfs_device(const struct inode *inode);
extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name,
					   const struct file_operations *fops,
					   void *data);
extern void binderfs_remove_file(struct dentry *dentry);
#else
static inline bool is_binderfs_device(const struct inode *inode)
{
	return false;
}
static inline struct dentry *binderfs_create_file(struct dentry *dir,
					   const char *name,
					   const struct file_operations *fops,
					   void *data)
{
	return NULL;
}
static inline void binderfs_remove_file(struct dentry *dentry) {}
#endif

#ifdef CONFIG_ANDROID_BINDERFS
+31 −37
Original line number Diff line number Diff line
@@ -48,16 +48,6 @@ static dev_t binderfs_dev;
static DEFINE_MUTEX(binderfs_minors_mutex);
static DEFINE_IDA(binderfs_minors);

/**
 * binderfs_mount_opts - mount options for binderfs
 * @max: maximum number of allocatable binderfs binder devices
 * @stats_mode: enable binder stats in binderfs.
 */
struct binderfs_mount_opts {
	int max;
	int stats_mode;
};

enum {
	Opt_max,
	Opt_stats_mode,
@@ -75,27 +65,6 @@ static const match_table_t tokens = {
	{ Opt_err, NULL     }
};

/**
 * binderfs_info - information about a binderfs mount
 * @ipc_ns:         The ipc namespace the binderfs mount belongs to.
 * @control_dentry: This records the dentry of this binderfs mount
 *                  binder-control device.
 * @root_uid:       uid that needs to be used when a new binder device is
 *                  created.
 * @root_gid:       gid that needs to be used when a new binder device is
 *                  created.
 * @mount_opts:     The mount options in use.
 * @device_count:   The current number of allocated binder devices.
 */
struct binderfs_info {
	struct ipc_namespace *ipc_ns;
	struct dentry *control_dentry;
	kuid_t root_uid;
	kgid_t root_gid;
	struct binderfs_mount_opts mount_opts;
	int device_count;
};

static inline struct binderfs_info *BINDERFS_I(const struct inode *inode)
{
	return inode->i_sb->s_fs_info;
@@ -533,8 +502,22 @@ static struct dentry *binderfs_create_dentry(struct dentry *parent,
	return dentry;
}

static struct dentry *binderfs_create_file(struct dentry *parent,
					   const char *name,
void binderfs_remove_file(struct dentry *dentry)
{
	struct inode *parent_inode;

	parent_inode = d_inode(dentry->d_parent);
	inode_lock(parent_inode);
	if (simple_positive(dentry)) {
		dget(dentry);
		simple_unlink(parent_inode, dentry);
		d_delete(dentry);
		dput(dentry);
	}
	inode_unlock(parent_inode);
}

struct dentry *binderfs_create_file(struct dentry *parent, const char *name,
				    const struct file_operations *fops,
				    void *data)
{
@@ -604,7 +587,8 @@ static struct dentry *binderfs_create_dir(struct dentry *parent,

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

	binder_logs_root_dir = binderfs_create_dir(sb->s_root,
@@ -648,8 +632,18 @@ static int init_binder_logs(struct super_block *sb)
				      "failed_transaction_log",
				      &binder_transaction_log_fops,
				      &binder_transaction_log_failed);
	if (IS_ERR(dentry))
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
		goto out;
	}

	proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc");
	if (IS_ERR(proc_log_dir)) {
		ret = PTR_ERR(proc_log_dir);
		goto out;
	}
	info = sb->s_fs_info;
	info->proc_log_dir = proc_log_dir;

out:
	return ret;