diff options
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 128 |
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) |
