|
@@ -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,
|