|
@@ -714,16 +714,11 @@ static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags)
|
|
cmpxchg(&bh->b_state, old_state, new_state) != old_state));
|
|
cmpxchg(&bh->b_state, old_state, new_state) != old_state));
|
|
}
|
|
}
|
|
|
|
|
|
-/* Maximum number of blocks we map for direct IO at once. */
|
|
|
|
-#define DIO_MAX_BLOCKS 4096
|
|
|
|
-
|
|
|
|
static int _ext4_get_block(struct inode *inode, sector_t iblock,
|
|
static int _ext4_get_block(struct inode *inode, sector_t iblock,
|
|
struct buffer_head *bh, int flags)
|
|
struct buffer_head *bh, int flags)
|
|
{
|
|
{
|
|
- handle_t *handle = ext4_journal_current_handle();
|
|
|
|
struct ext4_map_blocks map;
|
|
struct ext4_map_blocks map;
|
|
- int ret = 0, started = 0;
|
|
|
|
- int dio_credits;
|
|
|
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (ext4_has_inline_data(inode))
|
|
if (ext4_has_inline_data(inode))
|
|
return -ERANGE;
|
|
return -ERANGE;
|
|
@@ -731,33 +726,14 @@ 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 && !handle) {
|
|
|
|
- /* Direct IO write... */
|
|
|
|
- if (map.m_len > DIO_MAX_BLOCKS)
|
|
|
|
- map.m_len = DIO_MAX_BLOCKS;
|
|
|
|
- dio_credits = ext4_chunk_trans_blocks(inode, map.m_len);
|
|
|
|
- handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
|
|
|
|
- dio_credits);
|
|
|
|
- if (IS_ERR(handle)) {
|
|
|
|
- ret = PTR_ERR(handle);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
- started = 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = ext4_map_blocks(handle, inode, &map, flags);
|
|
|
|
|
|
+ ret = ext4_map_blocks(ext4_journal_current_handle(), inode, &map,
|
|
|
|
+ flags);
|
|
if (ret > 0) {
|
|
if (ret > 0) {
|
|
- ext4_io_end_t *io_end = ext4_inode_aio(inode);
|
|
|
|
-
|
|
|
|
map_bh(bh, inode->i_sb, map.m_pblk);
|
|
map_bh(bh, inode->i_sb, map.m_pblk);
|
|
ext4_update_bh_state(bh, map.m_flags);
|
|
ext4_update_bh_state(bh, map.m_flags);
|
|
- if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN)
|
|
|
|
- set_buffer_defer_completion(bh);
|
|
|
|
bh->b_size = inode->i_sb->s_blocksize * map.m_len;
|
|
bh->b_size = inode->i_sb->s_blocksize * map.m_len;
|
|
ret = 0;
|
|
ret = 0;
|
|
}
|
|
}
|
|
- if (started)
|
|
|
|
- ext4_journal_stop(handle);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -782,12 +758,42 @@ int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
|
|
EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
|
EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Maximum number of blocks we map for direct IO at once. */
|
|
|
|
+#define DIO_MAX_BLOCKS 4096
|
|
|
|
+
|
|
|
|
+static handle_t *start_dio_trans(struct inode *inode,
|
|
|
|
+ struct buffer_head *bh_result)
|
|
|
|
+{
|
|
|
|
+ int dio_credits;
|
|
|
|
+
|
|
|
|
+ /* Trim mapping request to maximum we can map at once for DIO */
|
|
|
|
+ if (bh_result->b_size >> inode->i_blkbits > DIO_MAX_BLOCKS)
|
|
|
|
+ bh_result->b_size = DIO_MAX_BLOCKS << inode->i_blkbits;
|
|
|
|
+ dio_credits = ext4_chunk_trans_blocks(inode,
|
|
|
|
+ bh_result->b_size >> inode->i_blkbits);
|
|
|
|
+ return ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, dio_credits);
|
|
|
|
+}
|
|
|
|
+
|
|
/* Get block function for DIO reads and writes to inodes without extents */
|
|
/* Get block function for DIO reads and writes to inodes without extents */
|
|
int ext4_dio_get_block(struct inode *inode, sector_t iblock,
|
|
int ext4_dio_get_block(struct inode *inode, sector_t iblock,
|
|
struct buffer_head *bh, int create)
|
|
struct buffer_head *bh, int create)
|
|
{
|
|
{
|
|
- return _ext4_get_block(inode, iblock, bh,
|
|
|
|
- create ? EXT4_GET_BLOCKS_CREATE : 0);
|
|
|
|
|
|
+ handle_t *handle;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ /* We don't expect handle for direct IO */
|
|
|
|
+ WARN_ON_ONCE(ext4_journal_current_handle());
|
|
|
|
+
|
|
|
|
+ if (create) {
|
|
|
|
+ handle = start_dio_trans(inode, bh);
|
|
|
|
+ if (IS_ERR(handle))
|
|
|
|
+ return PTR_ERR(handle);
|
|
|
|
+ }
|
|
|
|
+ ret = _ext4_get_block(inode, iblock, bh,
|
|
|
|
+ create ? EXT4_GET_BLOCKS_CREATE : 0);
|
|
|
|
+ if (create)
|
|
|
|
+ ext4_journal_stop(handle);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -798,10 +804,28 @@ int ext4_dio_get_block(struct inode *inode, sector_t iblock,
|
|
static int ext4_dio_get_block_unwritten(struct inode *inode, sector_t iblock,
|
|
static int ext4_dio_get_block_unwritten(struct inode *inode, sector_t iblock,
|
|
struct buffer_head *bh_result, int create)
|
|
struct buffer_head *bh_result, int create)
|
|
{
|
|
{
|
|
|
|
+ handle_t *handle;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
ext4_debug("ext4_dio_get_block_unwritten: inode %lu, create flag %d\n",
|
|
ext4_debug("ext4_dio_get_block_unwritten: inode %lu, create flag %d\n",
|
|
inode->i_ino, create);
|
|
inode->i_ino, create);
|
|
- return _ext4_get_block(inode, iblock, bh_result,
|
|
|
|
- EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
|
|
|
|
|
+ /* We don't expect handle for direct IO */
|
|
|
|
+ WARN_ON_ONCE(ext4_journal_current_handle());
|
|
|
|
+
|
|
|
|
+ handle = start_dio_trans(inode, bh_result);
|
|
|
|
+ if (IS_ERR(handle))
|
|
|
|
+ return PTR_ERR(handle);
|
|
|
|
+ ret = _ext4_get_block(inode, iblock, bh_result,
|
|
|
|
+ EXT4_GET_BLOCKS_IO_CREATE_EXT);
|
|
|
|
+ ext4_journal_stop(handle);
|
|
|
|
+ if (!ret && buffer_unwritten(bh_result)) {
|
|
|
|
+ ext4_io_end_t *io_end = ext4_inode_aio(inode);
|
|
|
|
+
|
|
|
|
+ set_buffer_defer_completion(bh_result);
|
|
|
|
+ WARN_ON_ONCE(io_end && !(io_end->flag & EXT4_IO_END_UNWRITTEN));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock,
|
|
static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock,
|
|
@@ -811,12 +835,15 @@ static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock,
|
|
|
|
|
|
ext4_debug("ext4_dio_get_block_overwrite: inode %lu, create flag %d\n",
|
|
ext4_debug("ext4_dio_get_block_overwrite: inode %lu, create flag %d\n",
|
|
inode->i_ino, create);
|
|
inode->i_ino, create);
|
|
|
|
+ /* We don't expect handle for direct IO */
|
|
|
|
+ WARN_ON_ONCE(ext4_journal_current_handle());
|
|
|
|
+
|
|
ret = _ext4_get_block(inode, iblock, bh_result, 0);
|
|
ret = _ext4_get_block(inode, iblock, bh_result, 0);
|
|
/*
|
|
/*
|
|
* Blocks should have been preallocated! ext4_file_write_iter() checks
|
|
* Blocks should have been preallocated! ext4_file_write_iter() checks
|
|
* that.
|
|
* that.
|
|
*/
|
|
*/
|
|
- WARN_ON_ONCE(!buffer_mapped(bh_result));
|
|
|
|
|
|
+ WARN_ON_ONCE(!buffer_mapped(bh_result) || buffer_unwritten(bh_result));
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|