Introduce an EXT4_MB_FORCE_ALIGN flag that essentially enforces the same behavior as EXT4_MB_HINT_ALIGNED however the alignment requirements are no longer a hint but must be respected. If the allocator can't return aligned blocks, then ENOSPC will be thrown. This will be eventually used to guarantee aligned blocks to perform H/W accelerated atomic writes. Signed-off-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx> --- fs/ext4/ext4.h | 2 ++ fs/ext4/mballoc.c | 31 +++++++++++++++++++++++-------- include/trace/events/ext4.h | 1 + 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ab4f10f9031a..9b9d7a354736 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -224,6 +224,8 @@ enum criteria { #define EXT4_MB_CR_BEST_AVAIL_LEN_OPTIMIZED 0x00020000 /* mballoc will try to align physical start to length (aka natural alignment) */ #define EXT4_MB_HINT_ALIGNED 0x40000 +/* Same as HINT_ALIGNED but fail allocation if alginment can't be guaranteed */ +#define EXT4_MB_FORCE_ALIGN 0x80000 struct ext4_allocation_request { /* target inode for block we're allocating */ diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index db7c593873a9..412aa80bc6e7 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2872,12 +2872,21 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac) ac->ac_criteria = cr; if (ac->ac_criteria > CR_POWER2_ALIGNED && - ac->ac_flags & EXT4_MB_HINT_ALIGNED && ac->ac_g_ex.fe_len > 1) { - ext4_warning_inode( - ac->ac_inode, - "Aligned allocation not possible, using unaligned allocation"); - ac->ac_flags &= ~EXT4_MB_HINT_ALIGNED; + if (ac->ac_flags & EXT4_MB_FORCE_ALIGN) { + ext4_warning_inode( + ac->ac_inode, + "Aligned allocation not possible, failing allocation"); + ac->ac_status = AC_STATUS_BREAK; + goto exit; + } + + if (ac->ac_flags & EXT4_MB_HINT_ALIGNED) { + ext4_warning_inode( + ac->ac_inode, + "Aligned allocation not possible, using unaligned allocation"); + ac->ac_flags &= ~EXT4_MB_HINT_ALIGNED; + } } /* @@ -3023,9 +3032,15 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac) goto exit; } - WARN_ON_ONCE(!is_power_of_2(len)); - WARN_ON_ONCE(start % len); - WARN_ON_ONCE(ac->ac_b_ex.fe_len < ac->ac_o_ex.fe_len); + if (WARN_ON_ONCE(!is_power_of_2(len)) || + WARN_ON_ONCE(start % len) || + WARN_ON_ONCE(ac->ac_b_ex.fe_len < ac->ac_o_ex.fe_len)) { + /* FORCE_ALIGN should error out if aligned blocks can't be found */ + if (ac->ac_flags & EXT4_MB_FORCE_ALIGN) { + ac->ac_status = AC_STATUS_BREAK; + goto exit; + } + } } exit: diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index d9464ee764af..ebc1fb5ad57b 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -37,6 +37,7 @@ struct partial_cluster; { EXT4_MB_USE_ROOT_BLOCKS, "USE_ROOT_BLKS" }, \ { EXT4_MB_USE_RESERVED, "USE_RESV" }, \ { EXT4_MB_HINT_ALIGNED, "HINT_ALIGNED" }, \ + { EXT4_MB_FORCE_ALIGN, "FORCE_ALIGN" }, \ { EXT4_MB_STRICT_CHECK, "STRICT_CHECK" }) #define show_map_flags(flags) __print_flags(flags, "|", \ -- 2.48.1