ext4: use transaction reservation for extent conversion in ext4_end_io
Later we would like to clear PageWriteback bit only after extent conversion from unwritten to written extents is performed. However it is not possible to start a transaction after PageWriteback is set because that violates lock ordering (and is easy to deadlock). So we have to reserve a transaction before locking pages and sending them for IO and later we use the transaction for extent conversion from ext4_end_io(). Reviewed-by: Zheng Liu <wenqing.lz@taobao.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
@ -184,10 +184,13 @@ struct ext4_map_blocks {
|
||||
#define EXT4_IO_END_DIRECT 0x0004
|
||||
|
||||
/*
|
||||
* For converting uninitialized extents on a work queue.
|
||||
* For converting uninitialized extents on a work queue. 'handle' is used for
|
||||
* buffered writeback.
|
||||
*/
|
||||
typedef struct ext4_io_end {
|
||||
struct list_head list; /* per-file finished IO list */
|
||||
handle_t *handle; /* handle reserved for extent
|
||||
* conversion */
|
||||
struct inode *inode; /* file being written to */
|
||||
unsigned int flag; /* unwritten or not */
|
||||
loff_t offset; /* offset in the file */
|
||||
@ -1322,6 +1325,9 @@ static inline void ext4_set_io_unwritten_flag(struct inode *inode,
|
||||
struct ext4_io_end *io_end)
|
||||
{
|
||||
if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
|
||||
/* Writeback has to have coversion transaction reserved */
|
||||
WARN_ON(EXT4_SB(inode->i_sb)->s_journal && !io_end->handle &&
|
||||
!(io_end->flag & EXT4_IO_END_DIRECT));
|
||||
io_end->flag |= EXT4_IO_END_UNWRITTEN;
|
||||
atomic_inc(&EXT4_I(inode)->i_unwritten);
|
||||
}
|
||||
@ -2591,8 +2597,8 @@ extern void ext4_ext_init(struct super_block *);
|
||||
extern void ext4_ext_release(struct super_block *);
|
||||
extern long ext4_fallocate(struct file *file, int mode, loff_t offset,
|
||||
loff_t len);
|
||||
extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
|
||||
ssize_t len);
|
||||
extern int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
|
||||
loff_t offset, ssize_t len);
|
||||
extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags);
|
||||
extern int ext4_ext_calc_metadata_amount(struct inode *inode,
|
||||
|
Reference in New Issue
Block a user