diff options
Diffstat (limited to 'fs/debugfs/inode.c')
| -rw-r--r-- | fs/debugfs/inode.c | 149 | 
1 files changed, 148 insertions, 1 deletions
| diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 956d5ddddf6e..b80bc846a15a 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -23,9 +23,13 @@  #include <linux/debugfs.h>  #include <linux/fsnotify.h>  #include <linux/string.h> +#include <linux/seq_file.h> +#include <linux/parser.h>  #include <linux/magic.h>  #include <linux/slab.h> +#define DEBUGFS_DEFAULT_MODE	0755 +  static struct vfsmount *debugfs_mount;  static int debugfs_mount_count;  static bool debugfs_registered; @@ -125,11 +129,154 @@ static inline int debugfs_positive(struct dentry *dentry)  	return dentry->d_inode && !d_unhashed(dentry);  } +struct debugfs_mount_opts { +	uid_t uid; +	gid_t gid; +	umode_t mode; +}; + +enum { +	Opt_uid, +	Opt_gid, +	Opt_mode, +	Opt_err +}; + +static const match_table_t tokens = { +	{Opt_uid, "uid=%u"}, +	{Opt_gid, "gid=%u"}, +	{Opt_mode, "mode=%o"}, +	{Opt_err, NULL} +}; + +struct debugfs_fs_info { +	struct debugfs_mount_opts mount_opts; +}; + +static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) +{ +	substring_t args[MAX_OPT_ARGS]; +	int option; +	int token; +	char *p; + +	opts->mode = DEBUGFS_DEFAULT_MODE; + +	while ((p = strsep(&data, ",")) != NULL) { +		if (!*p) +			continue; + +		token = match_token(p, tokens, args); +		switch (token) { +		case Opt_uid: +			if (match_int(&args[0], &option)) +				return -EINVAL; +			opts->uid = option; +			break; +		case Opt_gid: +			if (match_octal(&args[0], &option)) +				return -EINVAL; +			opts->gid = option; +			break; +		case Opt_mode: +			if (match_octal(&args[0], &option)) +				return -EINVAL; +			opts->mode = option & S_IALLUGO; +			break; +		/* +		 * We might like to report bad mount options here; +		 * but traditionally debugfs has ignored all mount options +		 */ +		} +	} + +	return 0; +} + +static int debugfs_apply_options(struct super_block *sb) +{ +	struct debugfs_fs_info *fsi = sb->s_fs_info; +	struct inode *inode = sb->s_root->d_inode; +	struct debugfs_mount_opts *opts = &fsi->mount_opts; + +	inode->i_mode &= ~S_IALLUGO; +	inode->i_mode |= opts->mode; + +	inode->i_uid = opts->uid; +	inode->i_gid = opts->gid; + +	return 0; +} + +static int debugfs_remount(struct super_block *sb, int *flags, char *data) +{ +	int err; +	struct debugfs_fs_info *fsi = sb->s_fs_info; + +	err = debugfs_parse_options(data, &fsi->mount_opts); +	if (err) +		goto fail; + +	debugfs_apply_options(sb); + +fail: +	return err; +} + +static int debugfs_show_options(struct seq_file *m, struct dentry *root) +{ +	struct debugfs_fs_info *fsi = root->d_sb->s_fs_info; +	struct debugfs_mount_opts *opts = &fsi->mount_opts; + +	if (opts->uid != 0) +		seq_printf(m, ",uid=%u", opts->uid); +	if (opts->gid != 0) +		seq_printf(m, ",gid=%u", opts->gid); +	if (opts->mode != DEBUGFS_DEFAULT_MODE) +		seq_printf(m, ",mode=%o", opts->mode); + +	return 0; +} + +static const struct super_operations debugfs_super_operations = { +	.statfs		= simple_statfs, +	.remount_fs	= debugfs_remount, +	.show_options	= debugfs_show_options, +}; +  static int debug_fill_super(struct super_block *sb, void *data, int silent)  {  	static struct tree_descr debug_files[] = {{""}}; +	struct debugfs_fs_info *fsi; +	int err; + +	save_mount_options(sb, data); + +	fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); +	sb->s_fs_info = fsi; +	if (!fsi) { +		err = -ENOMEM; +		goto fail; +	} + +	err = debugfs_parse_options(data, &fsi->mount_opts); +	if (err) +		goto fail; + +	err  =  simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); +	if (err) +		goto fail; + +	sb->s_op = &debugfs_super_operations; + +	debugfs_apply_options(sb); + +	return 0; -	return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); +fail: +	kfree(fsi); +	sb->s_fs_info = NULL; +	return err;  }  static struct dentry *debug_mount(struct file_system_type *fs_type, | 
