Commit f0083451 authored by Hridya Valsaraju's avatar Hridya Valsaraju Committed by Greg Kroah-Hartman

binder: add a mount option to show global stats

Currently, all binder state and statistics live in debugfs.
We need this information even when debugfs is not mounted.
This patch adds the mount option 'stats' to enable a binderfs
instance to have binder debug information present in the same.
'stats=global' will enable the global binder statistics. In
the future, 'stats=local' will enable binder statistics local
to the binderfs instance. The two modes 'global' and 'local'
will be mutually exclusive. 'stats=global' option is only available
for a binderfs instance mounted in the initial user namespace.
An attempt to use the option to mount a binderfs instance in
another user namespace will return an EPERM error.
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-2-hridya@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ca2864c6
......@@ -51,18 +51,27 @@ 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,
Opt_err
};
enum binderfs_stats_mode {
STATS_NONE,
STATS_GLOBAL,
};
static const match_table_t tokens = {
{ Opt_max, "max=%d" },
{ Opt_stats_mode, "stats=%s" },
{ Opt_err, NULL }
};
......@@ -290,8 +299,9 @@ static void binderfs_evict_inode(struct inode *inode)
static int binderfs_parse_mount_opts(char *data,
struct binderfs_mount_opts *opts)
{
char *p;
char *p, *stats;
opts->max = BINDERFS_MAX_MINOR;
opts->stats_mode = STATS_NONE;
while ((p = strsep(&data, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
......@@ -311,6 +321,22 @@ static int binderfs_parse_mount_opts(char *data,
opts->max = max_devices;
break;
case Opt_stats_mode:
if (!capable(CAP_SYS_ADMIN))
return -EINVAL;
stats = match_strdup(&args[0]);
if (!stats)
return -ENOMEM;
if (strcmp(stats, "global") != 0) {
kfree(stats);
return -EINVAL;
}
opts->stats_mode = STATS_GLOBAL;
kfree(stats);
break;
default:
pr_err("Invalid mount options\n");
return -EINVAL;
......@@ -322,8 +348,21 @@ static int binderfs_parse_mount_opts(char *data,
static int binderfs_remount(struct super_block *sb, int *flags, char *data)
{
int prev_stats_mode, ret;
struct binderfs_info *info = sb->s_fs_info;
return binderfs_parse_mount_opts(data, &info->mount_opts);
prev_stats_mode = info->mount_opts.stats_mode;
ret = binderfs_parse_mount_opts(data, &info->mount_opts);
if (ret)
return ret;
if (prev_stats_mode != info->mount_opts.stats_mode) {
pr_err("Binderfs stats mode cannot be changed during a remount\n");
info->mount_opts.stats_mode = prev_stats_mode;
return -EINVAL;
}
return 0;
}
static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root)
......@@ -333,6 +372,8 @@ static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root)
info = root->d_sb->s_fs_info;
if (info->mount_opts.max <= BINDERFS_MAX_MINOR)
seq_printf(seq, ",max=%d", info->mount_opts.max);
if (info->mount_opts.stats_mode == STATS_GLOBAL)
seq_printf(seq, ",stats=global");
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment