Commit 7da5565c authored by Zhang Yi's avatar Zhang Yi Committed by Theodore Ts'o
Browse files

ext4: make ext4_es_lookup_extent() pass out the extent seq counter



When querying extents in the extent status tree, we should hold the
data_sem if we want to obtain the sequence number as a valid cookie
simultaneously. However, currently, ext4_map_blocks() calls
ext4_es_lookup_extent() without holding data_sem. Therefore, we should
acquire i_es_lock instead, which also ensures that the sequence cookie
and the extent remain consistent. Consequently, make
ext4_es_lookup_extent() to pass out the sequence number when necessary.

Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Message-ID: <20251013015128.499308-4-yi.zhang@huaweicloud.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent dd064d51
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2213,7 +2213,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
	while (block <= end) {
		next = 0;
		flags = 0;
		if (!ext4_es_lookup_extent(inode, block, &next, &es))
		if (!ext4_es_lookup_extent(inode, block, &next, &es, NULL))
			break;
		if (ext4_es_is_unwritten(&es))
			flags |= FIEMAP_EXTENT_UNWRITTEN;
+4 −2
Original line number Diff line number Diff line
@@ -1039,8 +1039,8 @@ void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
 * Return: 1 on found, 0 on not
 */
int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
			  ext4_lblk_t *next_lblk,
			  struct extent_status *es)
			  ext4_lblk_t *next_lblk, struct extent_status *es,
			  u64 *pseq)
{
	struct ext4_es_tree *tree;
	struct ext4_es_stats *stats;
@@ -1099,6 +1099,8 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
			} else
				*next_lblk = 0;
		}
		if (pseq)
			*pseq = EXT4_I(inode)->i_es_seq;
	} else {
		percpu_counter_inc(&stats->es_stats_cache_misses);
	}
+1 −1
Original line number Diff line number Diff line
@@ -148,7 +148,7 @@ extern void ext4_es_find_extent_range(struct inode *inode,
				      struct extent_status *es);
extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
				 ext4_lblk_t *next_lblk,
				 struct extent_status *es);
				 struct extent_status *es, u64 *pseq);
extern bool ext4_es_scan_range(struct inode *inode,
			       int (*matching_fn)(struct extent_status *es),
			       ext4_lblk_t lblk, ext4_lblk_t end);
+4 −4
Original line number Diff line number Diff line
@@ -649,7 +649,7 @@ static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
	 * extent status tree.
	 */
	if (flags & EXT4_GET_BLOCKS_PRE_IO &&
	    ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
	    ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
		if (ext4_es_is_written(&es))
			return retval;
	}
@@ -723,7 +723,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
		ext4_check_map_extents_env(inode);

	/* Lookup extent status tree firstly */
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
		if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
			map->m_pblk = ext4_es_pblock(&es) +
					map->m_lblk - es.es_lblk;
@@ -1908,7 +1908,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
	ext4_check_map_extents_env(inode);

	/* Lookup extent status tree firstly */
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
		map->m_len = min_t(unsigned int, map->m_len,
				   es.es_len - (map->m_lblk - es.es_lblk));

@@ -1961,7 +1961,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
	 * is held in write mode, before inserting a new da entry in
	 * the extent status tree.
	 */
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
		map->m_len = min_t(unsigned int, map->m_len,
				   es.es_len - (map->m_lblk - es.es_lblk));