| From 1cc420c479f028e811b68b3e67a0695c26642223 Mon Sep 17 00:00:00 2001 |
| From: Eric Sandeen <sandeen@redhat.com> |
| Date: Thu, 19 Nov 2009 14:25:42 -0500 |
| Subject: [PATCH 71/85] ext4: make trim/discard optional (and off by default) |
| |
| (cherry picked from commit 5328e635315734d42080de9a5a1ee87bf4cae0a4) |
| |
| 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: Eric Sandeen <sandeen@redhat.com> |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| Documentation/filesystems/ext4.txt | 6 ++++++ |
| fs/ext4/ext4.h | 1 + |
| fs/ext4/mballoc.c | 21 +++++++++++++-------- |
| fs/ext4/super.c | 14 +++++++++++++- |
| 4 files changed, 33 insertions(+), 9 deletions(-) |
| |
| --- a/Documentation/filesystems/ext4.txt |
| +++ b/Documentation/filesystems/ext4.txt |
| @@ -338,6 +338,12 @@ noauto_da_alloc replacing existing file |
| system crashes before the delayed allocation |
| 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 |
| ========= |
| There are 3 different data modes: |
| --- a/fs/ext4/ext4.h |
| +++ b/fs/ext4/ext4.h |
| @@ -747,6 +747,7 @@ struct ext4_inode_info { |
| #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ |
| #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ |
| #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 set_opt(o, opt) o |= EXT4_MOUNT_##opt |
| --- a/fs/ext4/mballoc.c |
| +++ b/fs/ext4/mballoc.c |
| @@ -2810,7 +2810,6 @@ static void release_blocks_on_commit(jou |
| struct ext4_group_info *db; |
| int err, count = 0, count2 = 0; |
| struct ext4_free_data *entry; |
| - ext4_fsblk_t discard_block; |
| struct list_head *l, *ltmp; |
| |
| list_for_each_safe(l, ltmp, &txn->t_private_list) { |
| @@ -2840,13 +2839,19 @@ static void release_blocks_on_commit(jou |
| page_cache_release(e4b.bd_bitmap_page); |
| } |
| ext4_unlock_group(sb, entry->group); |
| - discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) |
| - + entry->start_blk |
| - + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); |
| - trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, |
| - entry->count); |
| - sb_issue_discard(sb, discard_block, entry->count); |
| - |
| + 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 |
| + + le32_to_cpu(es->s_first_data_block); |
| + trace_ext4_discard_blocks(sb, |
| + (unsigned long long)discard_block, |
| + entry->count); |
| + sb_issue_discard(sb, discard_block, entry->count); |
| + } |
| kmem_cache_free(ext4_free_ext_cachep, entry); |
| ext4_mb_release_desc(&e4b); |
| } |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -906,6 +906,9 @@ static int ext4_show_options(struct seq_ |
| if (test_opt(sb, NO_AUTO_DA_ALLOC)) |
| seq_puts(seq, ",noauto_da_alloc"); |
| |
| + if (test_opt(sb, DISCARD)) |
| + seq_puts(seq, ",discard"); |
| + |
| ext4_show_quota_options(seq, sb); |
| |
| return 0; |
| @@ -1086,7 +1089,8 @@ enum { |
| Opt_usrquota, Opt_grpquota, Opt_i_version, |
| Opt_stripe, Opt_delalloc, Opt_nodelalloc, |
| 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 = { |
| @@ -1152,6 +1156,8 @@ static const match_table_t tokens = { |
| {Opt_auto_da_alloc, "auto_da_alloc=%u"}, |
| {Opt_auto_da_alloc, "auto_da_alloc"}, |
| {Opt_noauto_da_alloc, "noauto_da_alloc"}, |
| + {Opt_discard, "discard"}, |
| + {Opt_nodiscard, "nodiscard"}, |
| {Opt_err, NULL}, |
| }; |
| |
| @@ -1580,6 +1586,12 @@ set_qf_format: |
| else |
| set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); |
| break; |
| + case Opt_discard: |
| + set_opt(sbi->s_mount_opt, DISCARD); |
| + break; |
| + case Opt_nodiscard: |
| + clear_opt(sbi->s_mount_opt, DISCARD); |
| + break; |
| default: |
| ext4_msg(sb, KERN_ERR, |
| "Unrecognized mount option \"%s\" " |