Commit 66acdcf4 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: add debugging /proc file showing file system options

Now that /proc/mounts is consistently showing only those mount options
which need to be specified in /etc/fstab or on the mount command line,
it is useful to have file which shows exactly which file system
options are enabled.  This can be useful when debugging a user
problem.
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 5a916be1
...@@ -847,6 +847,7 @@ static void ext4_put_super(struct super_block *sb) ...@@ -847,6 +847,7 @@ static void ext4_put_super(struct super_block *sb)
ext4_commit_super(sb, 1); ext4_commit_super(sb, 1);
} }
if (sbi->s_proc) { if (sbi->s_proc) {
remove_proc_entry("options", sbi->s_proc);
remove_proc_entry(sb->s_id, ext4_proc_root); remove_proc_entry(sb->s_id, ext4_proc_root);
} }
kobject_del(&sbi->s_kobj); kobject_del(&sbi->s_kobj);
...@@ -1683,16 +1684,17 @@ static const char *token2str(int token) ...@@ -1683,16 +1684,17 @@ static const char *token2str(int token)
* - it's set to a non-default value OR * - it's set to a non-default value OR
* - if the per-sb default is different from the global default * - if the per-sb default is different from the global default
*/ */
static int ext4_show_options(struct seq_file *seq, struct dentry *root) static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
int nodefs)
{ {
int def_errors;
struct super_block *sb = root->d_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es; struct ext4_super_block *es = sbi->s_es;
int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt;
const struct mount_opts *m; const struct mount_opts *m;
char sep = nodefs ? '\n' : ',';
#define SEQ_OPTS_PUTS(str) seq_printf(seq, "," str) #define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "," str, arg) #define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
if (sbi->s_sb_block != 1) if (sbi->s_sb_block != 1)
SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block); SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
...@@ -1702,7 +1704,7 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root) ...@@ -1702,7 +1704,7 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root)
if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) || if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
(m->flags & MOPT_CLEAR_ERR)) (m->flags & MOPT_CLEAR_ERR))
continue; continue;
if (!(m->mount_opt & (sbi->s_mount_opt ^ sbi->s_def_mount_opt))) if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
continue; /* skip if same as the default */ continue; /* skip if same as the default */
if ((want_set && if ((want_set &&
(sbi->s_mount_opt & m->mount_opt) != m->mount_opt) || (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) ||
...@@ -1711,30 +1713,30 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root) ...@@ -1711,30 +1713,30 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root)
SEQ_OPTS_PRINT("%s", token2str(m->token)); SEQ_OPTS_PRINT("%s", token2str(m->token));
} }
if (sbi->s_resuid != EXT4_DEF_RESUID || if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid); SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
if (sbi->s_resgid != EXT4_DEF_RESGID || if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid); SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
def_errors = le16_to_cpu(es->s_errors); def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
SEQ_OPTS_PUTS("errors=remount-ro"); SEQ_OPTS_PUTS("errors=remount-ro");
if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE) if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
SEQ_OPTS_PUTS("errors=continue"); SEQ_OPTS_PUTS("errors=continue");
if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC) if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
SEQ_OPTS_PUTS("errors=panic"); SEQ_OPTS_PUTS("errors=panic");
if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ)
SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ); SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ);
if (sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME)
SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time); SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time); SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
if (sb->s_flags & MS_I_VERSION) if (sb->s_flags & MS_I_VERSION)
SEQ_OPTS_PUTS("i_version"); SEQ_OPTS_PUTS("i_version");
if (sbi->s_stripe) if (nodefs || sbi->s_stripe)
SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) { if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) {
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
SEQ_OPTS_PUTS("data=journal"); SEQ_OPTS_PUTS("data=journal");
else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
...@@ -1742,18 +1744,48 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root) ...@@ -1742,18 +1744,48 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root)
else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
SEQ_OPTS_PUTS("data=writeback"); SEQ_OPTS_PUTS("data=writeback");
} }
if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) if (nodefs ||
sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
SEQ_OPTS_PRINT("inode_readahead_blks=%u", SEQ_OPTS_PRINT("inode_readahead_blks=%u",
sbi->s_inode_readahead_blks); sbi->s_inode_readahead_blks);
if (test_opt(sb, INIT_INODE_TABLE) && if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
(sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)) (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
ext4_show_quota_options(seq, sb); ext4_show_quota_options(seq, sb);
return 0; return 0;
} }
static int ext4_show_options(struct seq_file *seq, struct dentry *root)
{
return _ext4_show_options(seq, root->d_sb, 0);
}
static int options_seq_show(struct seq_file *seq, void *offset)
{
struct super_block *sb = seq->private;
int rc;
seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
rc = _ext4_show_options(seq, sb, 1);
seq_puts(seq, "\n");
return rc;
}
static int options_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, options_seq_show, PDE(inode)->data);
}
static const struct file_operations ext4_seq_options_fops = {
.owner = THIS_MODULE,
.open = options_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
int read_only) int read_only)
{ {
...@@ -3350,6 +3382,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3350,6 +3382,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (ext4_proc_root) if (ext4_proc_root)
sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
if (sbi->s_proc)
proc_create_data("options", S_IRUGO, sbi->s_proc,
&ext4_seq_options_fops, sb);
bgl_lock_init(sbi->s_blockgroup_lock); bgl_lock_init(sbi->s_blockgroup_lock);
for (i = 0; i < db_count; i++) { for (i = 0; i < db_count; i++) {
...@@ -3674,6 +3710,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3674,6 +3710,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
ext4_kvfree(sbi->s_group_desc); ext4_kvfree(sbi->s_group_desc);
failed_mount: failed_mount:
if (sbi->s_proc) { if (sbi->s_proc) {
remove_proc_entry("options", sbi->s_proc);
remove_proc_entry(sb->s_id, ext4_proc_root); remove_proc_entry(sb->s_id, ext4_proc_root);
} }
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
......
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