Commit 5328e635 authored by Eric Sandeen's avatar Eric Sandeen Committed by Theodore Ts'o

ext4: make trim/discard optional (and off by default)

It is anticipated that when sb_issue_discard starts doing
real work on trim-capable devices, we may see issues.  Make
this mount-time optional, and default it to off until we know
that things are working out OK.
Signed-off-by: default avatarEric Sandeen <sandeen@redhat.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 2bba702d
...@@ -353,6 +353,12 @@ noauto_da_alloc replacing existing files via patterns such as ...@@ -353,6 +353,12 @@ noauto_da_alloc replacing existing files via patterns such as
system crashes before the delayed allocation system crashes before the delayed allocation
blocks are forced to disk. blocks are forced to disk.
discard Controls whether ext4 should issue discard/TRIM
nodiscard(*) commands to the underlying block device when
blocks are freed. This is useful for SSD devices
and sparse/thinly-provisioned LUNs, but it is off
by default until sufficient testing has been done.
Data Mode Data Mode
========= =========
There are 3 different data modes: There are 3 different data modes:
......
...@@ -750,6 +750,7 @@ struct ext4_inode_info { ...@@ -750,6 +750,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
#define set_opt(o, opt) o |= EXT4_MOUNT_##opt #define set_opt(o, opt) o |= EXT4_MOUNT_##opt
......
...@@ -2529,7 +2529,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) ...@@ -2529,7 +2529,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
struct ext4_group_info *db; struct ext4_group_info *db;
int err, count = 0, count2 = 0; int err, count = 0, count2 = 0;
struct ext4_free_data *entry; struct ext4_free_data *entry;
ext4_fsblk_t discard_block;
struct list_head *l, *ltmp; struct list_head *l, *ltmp;
list_for_each_safe(l, ltmp, &txn->t_private_list) { list_for_each_safe(l, ltmp, &txn->t_private_list) {
...@@ -2559,13 +2558,19 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) ...@@ -2559,13 +2558,19 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
page_cache_release(e4b.bd_bitmap_page); page_cache_release(e4b.bd_bitmap_page);
} }
ext4_unlock_group(sb, entry->group); ext4_unlock_group(sb, entry->group);
discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) if (test_opt(sb, DISCARD)) {
ext4_fsblk_t discard_block;
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
discard_block = (ext4_fsblk_t)entry->group *
EXT4_BLOCKS_PER_GROUP(sb)
+ entry->start_blk + entry->start_blk
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); + le32_to_cpu(es->s_first_data_block);
trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, trace_ext4_discard_blocks(sb,
(unsigned long long)discard_block,
entry->count); entry->count);
sb_issue_discard(sb, discard_block, entry->count); sb_issue_discard(sb, discard_block, entry->count);
}
kmem_cache_free(ext4_free_ext_cachep, entry); kmem_cache_free(ext4_free_ext_cachep, entry);
ext4_mb_release_desc(&e4b); ext4_mb_release_desc(&e4b);
} }
......
...@@ -899,6 +899,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) ...@@ -899,6 +899,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
if (test_opt(sb, NO_AUTO_DA_ALLOC)) if (test_opt(sb, NO_AUTO_DA_ALLOC))
seq_puts(seq, ",noauto_da_alloc"); seq_puts(seq, ",noauto_da_alloc");
if (test_opt(sb, DISCARD))
seq_puts(seq, ",discard");
ext4_show_quota_options(seq, sb); ext4_show_quota_options(seq, sb);
return 0; return 0;
...@@ -1079,7 +1082,8 @@ enum { ...@@ -1079,7 +1082,8 @@ enum {
Opt_usrquota, Opt_grpquota, Opt_i_version, Opt_usrquota, Opt_grpquota, Opt_i_version,
Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_stripe, Opt_delalloc, Opt_nodelalloc,
Opt_block_validity, Opt_noblock_validity, Opt_block_validity, Opt_noblock_validity,
Opt_inode_readahead_blks, Opt_journal_ioprio Opt_inode_readahead_blks, Opt_journal_ioprio,
Opt_discard, Opt_nodiscard,
}; };
static const match_table_t tokens = { static const match_table_t tokens = {
...@@ -1144,6 +1148,8 @@ static const match_table_t tokens = { ...@@ -1144,6 +1148,8 @@ static const match_table_t tokens = {
{Opt_auto_da_alloc, "auto_da_alloc=%u"}, {Opt_auto_da_alloc, "auto_da_alloc=%u"},
{Opt_auto_da_alloc, "auto_da_alloc"}, {Opt_auto_da_alloc, "auto_da_alloc"},
{Opt_noauto_da_alloc, "noauto_da_alloc"}, {Opt_noauto_da_alloc, "noauto_da_alloc"},
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
...@@ -1565,6 +1571,12 @@ static int parse_options(char *options, struct super_block *sb, ...@@ -1565,6 +1571,12 @@ static int parse_options(char *options, struct super_block *sb,
else else
set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
break; break;
case Opt_discard:
set_opt(sbi->s_mount_opt, DISCARD);
break;
case Opt_nodiscard:
clear_opt(sbi->s_mount_opt, DISCARD);
break;
default: default:
ext4_msg(sb, KERN_ERR, ext4_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" " "Unrecognized mount option \"%s\" "
......
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