Commit 0031462b authored by Mingming Cao's avatar Mingming Cao Committed by Theodore Ts'o

ext4: Split uninitialized extents for direct I/O

When writing into an unitialized extent via direct I/O, and the direct
I/O doesn't exactly cover the unitialized extent, split the extent
into uninitialized and initialized extents before submitting the I/O.
This avoids needing to deal with an ENOSPC error in the end_io
callback that gets used for direct I/O.

When the IO is complete, the written extent will be marked as initialized.

Singed-Off-By: Mingming Cao <cmm@us.ibm.com> 
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 9f0ccfd8
...@@ -128,6 +128,15 @@ struct mpage_da_data { ...@@ -128,6 +128,15 @@ struct mpage_da_data {
int retval; int retval;
}; };
typedef struct ext4_io_end {
struct inode *inode; /* file being written to */
unsigned int flag; /* sync IO or AIO */
int error; /* I/O error code */
ext4_lblk_t offset; /* offset in the file */
size_t size; /* size of the extent */
struct work_struct work; /* data work queue */
} ext4_io_end_t;
/* /*
* Special inodes numbers * Special inodes numbers
*/ */
...@@ -347,7 +356,16 @@ struct ext4_new_group_data { ...@@ -347,7 +356,16 @@ struct ext4_new_group_data {
/* Call ext4_da_update_reserve_space() after successfully /* Call ext4_da_update_reserve_space() after successfully
allocating the blocks */ allocating the blocks */
#define EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE 0x0008 #define EXT4_GET_BLOCKS_UPDATE_RESERVE_SPACE 0x0008
/* caller is from the direct IO path, request to creation of an
unitialized extents if not allocated, split the uninitialized
extent if blocks has been preallocated already*/
#define EXT4_GET_BLOCKS_DIO 0x0010
#define EXT4_GET_BLOCKS_CONVERT 0x0020
#define EXT4_GET_BLOCKS_DIO_CREATE_EXT (EXT4_GET_BLOCKS_DIO|\
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
/* Convert extent to initialized after direct IO complete */
#define EXT4_GET_BLOCKS_DIO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
EXT4_GET_BLOCKS_DIO_CREATE_EXT)
/* /*
* ioctl commands * ioctl commands
...@@ -1700,6 +1718,8 @@ extern void ext4_ext_init(struct super_block *); ...@@ -1700,6 +1718,8 @@ extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *); extern void ext4_ext_release(struct super_block *);
extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset, extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
loff_t len); loff_t len);
extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
loff_t len);
extern int ext4_get_blocks(handle_t *handle, struct inode *inode, extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
sector_t block, unsigned int max_blocks, sector_t block, unsigned int max_blocks,
struct buffer_head *bh, int flags); struct buffer_head *bh, int flags);
......
...@@ -220,6 +220,11 @@ static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) ...@@ -220,6 +220,11 @@ static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
(le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN)); (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
} }
static inline void ext4_ext_mark_initialized(struct ext4_extent *ext)
{
ext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ext));
}
extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks);
extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex); extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex);
extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *);
...@@ -235,7 +240,7 @@ extern int ext4_ext_try_to_merge(struct inode *inode, ...@@ -235,7 +240,7 @@ extern int ext4_ext_try_to_merge(struct inode *inode,
struct ext4_ext_path *path, struct ext4_ext_path *path,
struct ext4_extent *); struct ext4_extent *);
extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *); extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *); extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *, int);
extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t, extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t,
ext_prepare_callback, void *); ext_prepare_callback, void *);
extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
......
This diff is collapsed.
...@@ -1233,6 +1233,9 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, ...@@ -1233,6 +1233,9 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
clear_buffer_mapped(bh); clear_buffer_mapped(bh);
clear_buffer_unwritten(bh); clear_buffer_unwritten(bh);
ext_debug("ext4_get_blocks(): inode %lu, flag %d, max_blocks %u,"
"logical block %lu\n", inode->i_ino, flags, max_blocks,
(unsigned long)block);
/* /*
* 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.
......
...@@ -75,7 +75,7 @@ static int finish_range(handle_t *handle, struct inode *inode, ...@@ -75,7 +75,7 @@ static int finish_range(handle_t *handle, struct inode *inode,
goto err_out; goto err_out;
} }
} }
retval = ext4_ext_insert_extent(handle, inode, path, &newext); retval = ext4_ext_insert_extent(handle, inode, path, &newext, 0);
err_out: err_out:
if (path) { if (path) {
ext4_ext_drop_refs(path); ext4_ext_drop_refs(path);
......
...@@ -322,7 +322,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, ...@@ -322,7 +322,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode,
goto out; goto out;
if (ext4_ext_insert_extent(handle, orig_inode, if (ext4_ext_insert_extent(handle, orig_inode,
orig_path, new_ext)) orig_path, new_ext, 0))
goto out; goto out;
} }
...@@ -333,7 +333,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, ...@@ -333,7 +333,7 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode,
goto out; goto out;
if (ext4_ext_insert_extent(handle, orig_inode, if (ext4_ext_insert_extent(handle, orig_inode,
orig_path, end_ext)) orig_path, end_ext, 0))
goto out; goto out;
} }
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment