summaryrefslogtreecommitdiff
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c128
1 files changed, 38 insertions, 90 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 0c466ccbed69..396dc3a5d16b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -48,6 +48,8 @@
#include "acl.h"
#include "truncate.h"
+#include <kunit/static_stub.h>
+
#include <trace/events/ext4.h>
static void ext4_journalled_zero_new_buffers(handle_t *handle,
@@ -400,6 +402,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
{
int ret;
+ KUNIT_STATIC_STUB_REDIRECT(ext4_issue_zeroout, inode, lblk, pblk, len);
+
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
return fscrypt_zeroout_range(inode, lblk, pblk, len);
@@ -503,8 +507,8 @@ static int ext4_map_query_blocks_next_in_leaf(handle_t *handle,
retval = ext4_ext_map_blocks(handle, inode, &map2, 0);
if (retval <= 0) {
- ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
- map->m_pblk, status, false);
+ ext4_es_cache_extent(inode, map->m_lblk, map->m_len,
+ map->m_pblk, status);
return map->m_len;
}
@@ -525,20 +529,20 @@ static int ext4_map_query_blocks_next_in_leaf(handle_t *handle,
*/
if (map->m_pblk + map->m_len == map2.m_pblk &&
status == status2) {
- ext4_es_insert_extent(inode, map->m_lblk,
- map->m_len + map2.m_len, map->m_pblk,
- status, false);
+ ext4_es_cache_extent(inode, map->m_lblk,
+ map->m_len + map2.m_len, map->m_pblk,
+ status);
map->m_len += map2.m_len;
} else {
- ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
- map->m_pblk, status, false);
+ ext4_es_cache_extent(inode, map->m_lblk, map->m_len,
+ map->m_pblk, status);
}
return map->m_len;
}
-static int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
- struct ext4_map_blocks *map, int flags)
+int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map, int flags)
{
unsigned int status;
int retval;
@@ -573,8 +577,8 @@ static int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
map->m_len == orig_mlen) {
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
- ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
- map->m_pblk, status, false);
+ ext4_es_cache_extent(inode, map->m_lblk, map->m_len,
+ map->m_pblk, status);
} else {
retval = ext4_map_query_blocks_next_in_leaf(handle, inode, map,
orig_mlen);
@@ -584,10 +588,9 @@ out:
return retval;
}
-static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
- struct ext4_map_blocks *map, int flags)
+int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map, int flags)
{
- struct extent_status es;
unsigned int status;
int err, retval = 0;
@@ -648,16 +651,6 @@ static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
return err;
}
- /*
- * If the extent has been zeroed out, we don't need to update
- * extent status tree.
- */
- if (flags & EXT4_GET_BLOCKS_SPLIT_NOMERGE &&
- ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, &map->m_seq)) {
- if (ext4_es_is_written(&es))
- return retval;
- }
-
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
ext4_es_insert_extent(inode, map->m_lblk, map->m_len, map->m_pblk,
@@ -2375,7 +2368,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
dioread_nolock = ext4_should_dioread_nolock(inode);
if (dioread_nolock)
- get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
+ get_blocks_flags |= EXT4_GET_BLOCKS_UNWRIT_EXT;
err = ext4_map_blocks(handle, inode, map, get_blocks_flags);
if (err < 0)
@@ -3305,8 +3298,7 @@ int ext4_alloc_da_blocks(struct inode *inode)
/*
* We do something simple for now. The filemap_flush() will
* also start triggering a write of the data blocks, which is
- * not strictly speaking necessary (and for users of
- * laptop_mode, not even desirable). However, to do otherwise
+ * not strictly speaking necessary. However, to do otherwise
* would require replicating code paths in:
*
* ext4_writepages() ->
@@ -3380,33 +3372,6 @@ out:
return ret;
}
-static int ext4_read_folio(struct file *file, struct folio *folio)
-{
- int ret = -EAGAIN;
- struct inode *inode = folio->mapping->host;
-
- trace_ext4_read_folio(inode, folio);
-
- if (ext4_has_inline_data(inode))
- ret = ext4_readpage_inline(inode, folio);
-
- if (ret == -EAGAIN)
- return ext4_mpage_readpages(inode, NULL, folio);
-
- return ret;
-}
-
-static void ext4_readahead(struct readahead_control *rac)
-{
- struct inode *inode = rac->mapping->host;
-
- /* If the file has inline data, no need to do readahead. */
- if (ext4_has_inline_data(inode))
- return;
-
- ext4_mpage_readpages(inode, rac, NULL);
-}
-
static void ext4_invalidate_folio(struct folio *folio, size_t offset,
size_t length)
{
@@ -3740,7 +3705,7 @@ retry:
else if (EXT4_LBLK_TO_B(inode, map->m_lblk) >= i_size_read(inode))
m_flags = EXT4_GET_BLOCKS_CREATE;
else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
- m_flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
+ m_flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
if (flags & IOMAP_ATOMIC)
ret = ext4_map_blocks_atomic_write(handle, inode, map, m_flags,
@@ -3812,22 +3777,25 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
if (offset + length <= i_size_read(inode)) {
ret = ext4_map_blocks(NULL, inode, &map, 0);
/*
- * For atomic writes the entire requested length should
- * be mapped.
+ * For DAX we convert extents to initialized ones before
+ * copying the data, otherwise we do it after I/O so
+ * there's no need to call into ext4_iomap_alloc().
*/
- if (map.m_flags & EXT4_MAP_MAPPED) {
- if ((!(flags & IOMAP_ATOMIC) && ret > 0) ||
- (flags & IOMAP_ATOMIC && ret >= orig_mlen))
+ if ((map.m_flags & EXT4_MAP_MAPPED) ||
+ (!(flags & IOMAP_DAX) &&
+ (map.m_flags & EXT4_MAP_UNWRITTEN))) {
+ /*
+ * For atomic writes the entire requested
+ * length should be mapped.
+ */
+ if (ret == orig_mlen ||
+ (!(flags & IOMAP_ATOMIC) && ret > 0))
goto out;
}
map.m_len = orig_mlen;
}
ret = ext4_iomap_alloc(inode, &map, flags);
} else {
- /*
- * This can be called for overwrites path from
- * ext4_iomap_overwrite_begin().
- */
ret = ext4_map_blocks(NULL, inode, &map, 0);
}
@@ -3856,30 +3824,10 @@ out:
return 0;
}
-static int ext4_iomap_overwrite_begin(struct inode *inode, loff_t offset,
- loff_t length, unsigned flags, struct iomap *iomap,
- struct iomap *srcmap)
-{
- int ret;
-
- /*
- * Even for writes we don't need to allocate blocks, so just pretend
- * we are reading to save overhead of starting a transaction.
- */
- flags &= ~IOMAP_WRITE;
- ret = ext4_iomap_begin(inode, offset, length, flags, iomap, srcmap);
- WARN_ON_ONCE(!ret && iomap->type != IOMAP_MAPPED);
- return ret;
-}
-
const struct iomap_ops ext4_iomap_ops = {
.iomap_begin = ext4_iomap_begin,
};
-const struct iomap_ops ext4_iomap_overwrite_ops = {
- .iomap_begin = ext4_iomap_overwrite_begin,
-};
-
static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
loff_t length, unsigned int flags,
struct iomap *iomap, struct iomap *srcmap)
@@ -4133,9 +4081,13 @@ static int __ext4_block_zero_page_range(handle_t *handle,
if (ext4_should_journal_data(inode)) {
err = ext4_dirty_journalled_data(handle, bh);
} else {
- err = 0;
mark_buffer_dirty(bh);
- if (ext4_should_order_data(inode))
+ /*
+ * Only the written block requires ordered data to prevent
+ * exposing stale data.
+ */
+ if (!buffer_unwritten(bh) && !buffer_delay(bh) &&
+ ext4_should_order_data(inode))
err = ext4_jbd2_inode_add_write(handle, inode, from,
length);
}
@@ -5835,10 +5787,6 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
if (error)
return error;
- error = fsverity_prepare_setattr(dentry, attr);
- if (error)
- return error;
-
if (is_quota_modification(idmap, inode, attr)) {
error = dquot_initialize(inode);
if (error)