From: Ojaswin Mujoo <ojaswin@linux.ibm.com>
To: linux-ext4@vger.kernel.org, "Theodore Ts'o" <tytso@mit.edu>
Cc: John Garry <john.g.garry@oracle.com>,
dchinner@redhat.com, "Darrick J . Wong" <djwong@kernel.org>,
Ritesh Harjani <ritesh.list@gmail.com>,
linux-kernel@vger.kernel.org
Subject: [RFC v3 09/11] ext4: add forcealign support to ext4_map_blocks
Date: Mon, 24 Mar 2025 13:07:07 +0530 [thread overview]
Message-ID: <003d7711c71a8f515687045f5b74fe045c0f01d1.1742800203.git.ojaswin@linux.ibm.com> (raw)
In-Reply-To: <cover.1742800203.git.ojaswin@linux.ibm.com>
Introduce EXT4_GET_BLOCKS_FORCEALIGN that works with EXT4_GET_BLOCKS_EXTSIZE
and guarantees that the extent returned by allocator is physically as
well as logically aligned to the extsize hint set on the inode.
This feature will be used to guranatee aligned allocations for HW accelerated
atomic writes
Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
---
fs/ext4/ext4.h | 1 +
fs/ext4/extents.c | 24 ++++++++++++++++++++++--
fs/ext4/inode.c | 43 ++++++++++++++++++++++++++++++++++++++++---
3 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 9b9d7a354736..a7429797c1d2 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -730,6 +730,7 @@ enum {
/* Caller is in the atomic contex, find extent if it has been cached */
#define EXT4_GET_BLOCKS_CACHED_NOWAIT 0x0800
#define EXT4_GET_BLOCKS_EXTSIZE 0x1000
+#define EXT4_GET_BLOCKS_FORCEALIGN 0x2000
/*
* The bit position of these flags must not overlap with any of the
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index a86cc3e76f14..25c1368b49bb 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4414,13 +4414,27 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
ar.flags |= EXT4_MB_USE_RESERVED;
if (flags & EXT4_GET_BLOCKS_EXTSIZE)
ar.flags |= EXT4_MB_HINT_ALIGNED;
+ if (flags & EXT4_GET_BLOCKS_FORCEALIGN) {
+ if (WARN_ON(ar.logical != map->m_lblk || ar.len != map->m_len ||
+ !(flags & EXT4_GET_BLOCKS_EXTSIZE))) {
+ /*
+ * This should ideally not happen but if does then error
+ * out
+ */
+ err = -ENOSPC;
+ goto out;
+ }
+ ar.flags |= EXT4_MB_FORCE_ALIGN;
+ }
newblock = ext4_mb_new_blocks(handle, &ar, &err);
if (!newblock)
goto out;
allocated_clusters = ar.len;
ar.len = EXT4_C2B(sbi, ar.len) - offset;
- ext_debug(inode, "allocate new block: goal %llu, found %llu/%u, requested %u\n",
- ar.goal, newblock, ar.len, allocated);
+ ext_debug(
+ inode,
+ "allocate new block: goal %llu, found %llu/%u, requested %u\n",
+ ar.goal, newblock, ar.len, allocated);
if (ar.len > allocated)
ar.len = allocated;
@@ -4435,6 +4449,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
map->m_flags |= EXT4_MAP_UNWRITTEN;
}
+ if ((flags & EXT4_GET_BLOCKS_FORCEALIGN) &&
+ (ar.len != map->m_len || pblk % map->m_len)) {
+ err = -ENOSPC;
+ goto insert_error;
+ }
+
if ((flags & EXT4_GET_BLOCKS_EXTSIZE) &&
(flags & EXT4_GET_BLOCKS_PRE_IO)) {
/*
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e41c97584f35..93ab76cb4818 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -753,6 +753,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
__u32 extsize = ext4_inode_get_extsize(EXT4_I(inode));
bool should_extsize = false;
+ bool should_forcealign = false;
#ifdef ES_AGGRESSIVE_TEST
struct ext4_map_blocks test_map;
@@ -793,6 +794,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
* ext4_extents.h here?
*/
int max_unwrit_len = ((1UL << 15) - 1);
+ should_forcealign = (flags & EXT4_GET_BLOCKS_FORCEALIGN);
align = orig_map->m_lblk % extsize;
len = orig_map->m_len + align;
@@ -802,7 +804,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
max_t(unsigned int, roundup_pow_of_two(len), extsize);
/* Fallback to normal allocation if we go beyond max len */
- if (extsize_map.m_len >= max_unwrit_len) {
+ if (WARN_ON(extsize_map.m_len >= max_unwrit_len)) {
+ if (should_forcealign)
+ /* forcealign has no fallback */
+ return -EINVAL;
+
flags = orig_flags & ~EXT4_GET_BLOCKS_EXTSIZE;
goto set_map;
}
@@ -814,8 +820,10 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
* dioread nolock to achieve this. Hence the caller has to pass
* CREATE_UNWRIT with EXTSIZE
*/
- if (!(flags | EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)) {
- WARN_ON(true);
+ if (WARN_ON(!(flags | EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT))) {
+ if (should_forcealign)
+ /* forcealign has no fallback */
+ return -EINVAL;
/* Fallback to non extsize allocation */
flags = orig_flags & ~EXT4_GET_BLOCKS_EXTSIZE;
@@ -905,6 +913,29 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
if (retval >= 0 && flags & EXT4_GET_BLOCKS_EXTSIZE) {
bool orig_in_range =
in_range(orig_mlblk, (__u64)map->m_lblk, map->m_len);
+
+ if (should_forcealign) {
+ /*
+ * For forcealign, irrespective of it it's a hole or not,
+ * the mapping we got should be exactly equal to the
+ * extsize mapping we requested since allocation and
+ * deallocation both respect extsize. If
+ * not, something has gone terribly wrong.
+ */
+ if (WARN_ON((map->m_lblk != extsize_mlblk) ||
+ (map->m_len != extsize_mlen))) {
+ ext4_error_adjust_map(map, orig_map);
+ ext4_warning(
+ inode->i_sb,
+ "%s: Unaligned blocks found! Disable forcealign and try again."
+ "requested:(%u, %u) extsize:(%u, %u) got:(%u, %u)\n",
+ __func__, orig_mlblk, orig_mlen,
+ extsize_mlblk, extsize_mlen,
+ map->m_lblk, map->m_len);
+ return -EUCLEAN;
+ }
+ }
+
/*
* Special case: if the extsize range is mapped already and
* covers the original start, we return it.
@@ -925,6 +956,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
if (map->m_lblk != extsize_mlblk ||
map->m_len != extsize_mlen) {
+ WARN_ON(should_forcealign);
flags = orig_flags & ~EXT4_GET_BLOCKS_EXTSIZE;
goto set_map;
}
@@ -1011,6 +1043,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
* not used. Can we avoid that?
*/
if (!in_range(orig_mlblk, (__u64)map->m_lblk, map->m_len)) {
+ if (WARN_ON(should_forcealign)) {
+ /* this should never happen */
+ ext4_error_adjust_map(map, orig_map);
+ return -ENOSPC;
+ }
flags = orig_flags & ~EXT4_GET_BLOCKS_EXTSIZE;
goto set_map;
}
--
2.48.1
next prev parent reply other threads:[~2025-03-24 7:37 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-24 7:36 [RFC v3 00/11] ext4: Add extsize and forcealign support (groundwork for multi block atomic writes) Ojaswin Mujoo
2025-03-24 7:36 ` [RFC v3 01/11] ext4: add aligned allocation hint in mballoc Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 02/11] ext4: allow inode preallocation for aligned alloc Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 03/11] ext4: support for extsize hint using FS_IOC_FS(GET/SET)XATTR Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 04/11] ext4: pass lblk and len explicitly to ext4_split_extent*() Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 05/11] ext4: add extsize hint support Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 06/11] ext4: make extsize work with EOF allocations Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 07/11] ext4: add ext4_map_blocks_extsize() wrapper to handle overwrites Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 08/11] ext4: add forcealign support of mballoc Ojaswin Mujoo
2025-03-24 7:37 ` Ojaswin Mujoo [this message]
2025-03-24 7:37 ` [RFC v3 10/11] ext4: add support for adding focealign via SETXATTR ioctl Ojaswin Mujoo
2025-03-24 7:37 ` [RFC v3 11/11] ext4: disallow unaligned deallocations on forcealign inodes Ojaswin Mujoo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=003d7711c71a8f515687045f5b74fe045c0f01d1.1742800203.git.ojaswin@linux.ibm.com \
--to=ojaswin@linux.ibm.com \
--cc=dchinner@redhat.com \
--cc=djwong@kernel.org \
--cc=john.g.garry@oracle.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ritesh.list@gmail.com \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®