ext4: get rid of EXT4_GET_BLOCKS_NO_LOCK flag
When dioread_nolock mode is enabled, we grab i_data_sem in ext4_ext_direct_IO() and therefore we need to instruct _ext4_get_block() not to grab i_data_sem again using EXT4_GET_BLOCKS_NO_LOCK. However holding i_data_sem over overwrite direct IO isn't needed these days. We have exclusion against truncate / hole punching because we increase i_dio_count under i_mutex in ext4_ext_direct_IO() so once ext4_file_write_iter() verifies blocks are allocated & written, they are guaranteed to stay so during the whole direct IO even after we drop i_mutex. So we can just remove this locking abuse and the no longer necessary EXT4_GET_BLOCKS_NO_LOCK flag. Signed-off-by: Jan Kara <jack@suse.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
@@ -555,10 +555,8 @@ enum {
|
|||||||
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
|
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
|
||||||
/* Request will not result in inode size update (user for fallocate) */
|
/* Request will not result in inode size update (user for fallocate) */
|
||||||
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
|
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
|
||||||
/* Do not take i_data_sem locking in ext4_map_blocks */
|
|
||||||
#define EXT4_GET_BLOCKS_NO_LOCK 0x0100
|
|
||||||
/* Convert written extents to unwritten */
|
/* Convert written extents to unwritten */
|
||||||
#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0200
|
#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The bit position of these flags must not overlap with any of the
|
* The bit position of these flags must not overlap with any of the
|
||||||
|
@@ -403,7 +403,6 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
|
|||||||
* out taking i_data_sem. So at the time the unwritten extent
|
* out taking i_data_sem. So at the time the unwritten extent
|
||||||
* could be converted.
|
* could be converted.
|
||||||
*/
|
*/
|
||||||
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
|
|
||||||
down_read(&EXT4_I(inode)->i_data_sem);
|
down_read(&EXT4_I(inode)->i_data_sem);
|
||||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||||
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
||||||
@@ -412,7 +411,6 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
|
|||||||
retval = ext4_ind_map_blocks(handle, inode, map, flags &
|
retval = ext4_ind_map_blocks(handle, inode, map, flags &
|
||||||
EXT4_GET_BLOCKS_KEEP_SIZE);
|
EXT4_GET_BLOCKS_KEEP_SIZE);
|
||||||
}
|
}
|
||||||
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
|
|
||||||
up_read((&EXT4_I(inode)->i_data_sem));
|
up_read((&EXT4_I(inode)->i_data_sem));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -509,7 +507,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
|||||||
* Try to see if we can get the block without requesting a new
|
* Try to see if we can get the block without requesting a new
|
||||||
* file system block.
|
* file system block.
|
||||||
*/
|
*/
|
||||||
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
|
|
||||||
down_read(&EXT4_I(inode)->i_data_sem);
|
down_read(&EXT4_I(inode)->i_data_sem);
|
||||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||||
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
||||||
@@ -541,7 +538,6 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
retval = ret;
|
retval = ret;
|
||||||
}
|
}
|
||||||
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
|
|
||||||
up_read((&EXT4_I(inode)->i_data_sem));
|
up_read((&EXT4_I(inode)->i_data_sem));
|
||||||
|
|
||||||
found:
|
found:
|
||||||
@@ -674,7 +670,7 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock,
|
|||||||
map.m_lblk = iblock;
|
map.m_lblk = iblock;
|
||||||
map.m_len = bh->b_size >> inode->i_blkbits;
|
map.m_len = bh->b_size >> inode->i_blkbits;
|
||||||
|
|
||||||
if (flags && !(flags & EXT4_GET_BLOCKS_NO_LOCK) && !handle) {
|
if (flags && !handle) {
|
||||||
/* Direct IO write... */
|
/* Direct IO write... */
|
||||||
if (map.m_len > DIO_MAX_BLOCKS)
|
if (map.m_len > DIO_MAX_BLOCKS)
|
||||||
map.m_len = DIO_MAX_BLOCKS;
|
map.m_len = DIO_MAX_BLOCKS;
|
||||||
@@ -879,9 +875,6 @@ int do_journal_get_write_access(handle_t *handle,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock,
|
|
||||||
struct buffer_head *bh_result, int create);
|
|
||||||
|
|
||||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
|
static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
|
||||||
get_block_t *get_block)
|
get_block_t *get_block)
|
||||||
@@ -3054,13 +3047,21 @@ int ext4_get_block_write(struct inode *inode, sector_t iblock,
|
|||||||
EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock,
|
static int ext4_get_block_overwrite(struct inode *inode, sector_t iblock,
|
||||||
struct buffer_head *bh_result, int create)
|
struct buffer_head *bh_result, int create)
|
||||||
{
|
{
|
||||||
ext4_debug("ext4_get_block_write_nolock: inode %lu, create flag %d\n",
|
int ret;
|
||||||
|
|
||||||
|
ext4_debug("ext4_get_block_overwrite: inode %lu, create flag %d\n",
|
||||||
inode->i_ino, create);
|
inode->i_ino, create);
|
||||||
return _ext4_get_block(inode, iblock, bh_result,
|
ret = _ext4_get_block(inode, iblock, bh_result, 0);
|
||||||
EXT4_GET_BLOCKS_NO_LOCK);
|
/*
|
||||||
|
* Blocks should have been preallocated! ext4_file_write_iter() checks
|
||||||
|
* that.
|
||||||
|
*/
|
||||||
|
WARN_ON_ONCE(!buffer_mapped(bh_result));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ext4_get_block_dax(struct inode *inode, sector_t iblock,
|
int ext4_get_block_dax(struct inode *inode, sector_t iblock,
|
||||||
@@ -3143,10 +3144,8 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
|
|||||||
/* If we do a overwrite dio, i_mutex locking can be released */
|
/* If we do a overwrite dio, i_mutex locking can be released */
|
||||||
overwrite = *((int *)iocb->private);
|
overwrite = *((int *)iocb->private);
|
||||||
|
|
||||||
if (overwrite) {
|
if (overwrite)
|
||||||
down_read(&EXT4_I(inode)->i_data_sem);
|
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We could direct write to holes and fallocate.
|
* We could direct write to holes and fallocate.
|
||||||
@@ -3189,7 +3188,7 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (overwrite) {
|
if (overwrite) {
|
||||||
get_block_func = ext4_get_block_write_nolock;
|
get_block_func = ext4_get_block_overwrite;
|
||||||
} else {
|
} else {
|
||||||
get_block_func = ext4_get_block_write;
|
get_block_func = ext4_get_block_write;
|
||||||
dio_flags = DIO_LOCKING;
|
dio_flags = DIO_LOCKING;
|
||||||
@@ -3245,10 +3244,8 @@ retake_lock:
|
|||||||
if (iov_iter_rw(iter) == WRITE)
|
if (iov_iter_rw(iter) == WRITE)
|
||||||
inode_dio_end(inode);
|
inode_dio_end(inode);
|
||||||
/* take i_mutex locking again if we do a ovewrite dio */
|
/* take i_mutex locking again if we do a ovewrite dio */
|
||||||
if (overwrite) {
|
if (overwrite)
|
||||||
up_read(&EXT4_I(inode)->i_data_sem);
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -42,8 +42,7 @@ struct extent_status;
|
|||||||
{ EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \
|
{ EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \
|
||||||
{ EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
|
{ EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
|
||||||
{ EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
|
{ EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
|
||||||
{ EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \
|
{ EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" })
|
||||||
{ EXT4_GET_BLOCKS_NO_LOCK, "NO_LOCK" })
|
|
||||||
|
|
||||||
#define show_mflags(flags) __print_flags(flags, "", \
|
#define show_mflags(flags) __print_flags(flags, "", \
|
||||||
{ EXT4_MAP_NEW, "N" }, \
|
{ EXT4_MAP_NEW, "N" }, \
|
||||||
|
Reference in New Issue
Block a user