Commit 16fe4101 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: partial revert to fix double brelse WARNING()
  ext4: Fix return value of ext4_split_unwritten_extents() to fix direct I/O
  ext4: code clean up for dio fallocate handling
  ext4: skip conversion of uninit extents after direct IO if there isn't any
  ext4: fix ext4_ext_direct_IO()'s return value after converting uninit extents
  ext4: discard preallocation when restarting a transaction during truncate
parents 7bbf8ef6 1e424a34
...@@ -322,6 +322,7 @@ static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) ...@@ -322,6 +322,7 @@ static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
#define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */ #define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */
#define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */ #define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */
#define EXT4_STATE_EXT_MIGRATE 0x00000020 /* Inode is migrating */ #define EXT4_STATE_EXT_MIGRATE 0x00000020 /* Inode is migrating */
#define EXT4_STATE_DIO_UNWRITTEN 0x00000040 /* need convert on dio done*/
/* Used to pass group descriptor data when online resize is done */ /* Used to pass group descriptor data when online resize is done */
struct ext4_new_group_input { struct ext4_new_group_input {
......
...@@ -2807,6 +2807,8 @@ fix_extent_len: ...@@ -2807,6 +2807,8 @@ fix_extent_len:
* into three uninitialized extent(at most). After IO complete, the part * into three uninitialized extent(at most). After IO complete, the part
* being filled will be convert to initialized by the end_io callback function * being filled will be convert to initialized by the end_io callback function
* via ext4_convert_unwritten_extents(). * via ext4_convert_unwritten_extents().
*
* Returns the size of uninitialized extent to be written on success.
*/ */
static int ext4_split_unwritten_extents(handle_t *handle, static int ext4_split_unwritten_extents(handle_t *handle,
struct inode *inode, struct inode *inode,
...@@ -2824,7 +2826,6 @@ static int ext4_split_unwritten_extents(handle_t *handle, ...@@ -2824,7 +2826,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
unsigned int allocated, ee_len, depth; unsigned int allocated, ee_len, depth;
ext4_fsblk_t newblock; ext4_fsblk_t newblock;
int err = 0; int err = 0;
int ret = 0;
ext_debug("ext4_split_unwritten_extents: inode %lu," ext_debug("ext4_split_unwritten_extents: inode %lu,"
"iblock %llu, max_blocks %u\n", inode->i_ino, "iblock %llu, max_blocks %u\n", inode->i_ino,
...@@ -2842,12 +2843,12 @@ static int ext4_split_unwritten_extents(handle_t *handle, ...@@ -2842,12 +2843,12 @@ static int ext4_split_unwritten_extents(handle_t *handle,
ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
/* /*
* if the entire unintialized extent length less than * If the uninitialized extent begins at the same logical
* the size of extent to write, there is no need to split * block where the write begins, and the write completely
* uninitialized extent * covers the extent, then we don't need to split it.
*/ */
if (allocated <= max_blocks) if ((iblock == ee_block) && (allocated <= max_blocks))
return ret; return allocated;
err = ext4_ext_get_access(handle, inode, path + depth); err = ext4_ext_get_access(handle, inode, path + depth);
if (err) if (err)
...@@ -3048,12 +3049,18 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, ...@@ -3048,12 +3049,18 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
ret = ext4_split_unwritten_extents(handle, ret = ext4_split_unwritten_extents(handle,
inode, path, iblock, inode, path, iblock,
max_blocks, flags); max_blocks, flags);
/* flag the io_end struct that we need convert when IO done */ /*
* Flag the inode(non aio case) or end_io struct (aio case)
* that this IO needs to convertion to written when IO is
* completed
*/
if (io) if (io)
io->flag = DIO_AIO_UNWRITTEN; io->flag = DIO_AIO_UNWRITTEN;
else
EXT4_I(inode)->i_state |= EXT4_STATE_DIO_UNWRITTEN;
goto out; goto out;
} }
/* DIO end_io complete, convert the filled extent to written */ /* async DIO end_io complete, convert the filled extent to written */
if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) {
ret = ext4_convert_unwritten_extents_dio(handle, inode, ret = ext4_convert_unwritten_extents_dio(handle, inode,
path); path);
...@@ -3295,10 +3302,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, ...@@ -3295,10 +3302,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
* To avoid unecessary convertion for every aio dio rewrite * To avoid unecessary convertion for every aio dio rewrite
* to the mid of file, here we flag the IO that is really * to the mid of file, here we flag the IO that is really
* need the convertion. * need the convertion.
* * For non asycn direct IO case, flag the inode state
* that we need to perform convertion when IO is done.
*/ */
if (io && flags == EXT4_GET_BLOCKS_DIO_CREATE_EXT) if (flags == EXT4_GET_BLOCKS_DIO_CREATE_EXT) {
if (io)
io->flag = DIO_AIO_UNWRITTEN; io->flag = DIO_AIO_UNWRITTEN;
else
EXT4_I(inode)->i_state |=
EXT4_STATE_DIO_UNWRITTEN;;
}
} }
err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
if (err) { if (err) {
...@@ -3519,6 +3532,7 @@ retry: ...@@ -3519,6 +3532,7 @@ retry:
* *
* This function is called from the direct IO end io call back * This function is called from the direct IO end io call back
* function, to convert the fallocated extents after IO is completed. * function, to convert the fallocated extents after IO is completed.
* Returns 0 on success.
*/ */
int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset, int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
loff_t len) loff_t len)
......
...@@ -193,7 +193,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) ...@@ -193,7 +193,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
* so before we call here everything must be consistently dirtied against * so before we call here everything must be consistently dirtied against
* this transaction. * this transaction.
*/ */
int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode, int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
int nblocks) int nblocks)
{ {
int ret; int ret;
...@@ -209,6 +209,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) ...@@ -209,6 +209,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
ret = ext4_journal_restart(handle, blocks_for_truncate(inode)); ret = ext4_journal_restart(handle, blocks_for_truncate(inode));
down_write(&EXT4_I(inode)->i_data_sem); down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode);
return ret; return ret;
} }
...@@ -3445,8 +3446,6 @@ out: ...@@ -3445,8 +3446,6 @@ out:
return ret; return ret;
} }
/* Maximum number of blocks we map for direct IO at once. */
static int ext4_get_block_dio_write(struct inode *inode, sector_t iblock, static int ext4_get_block_dio_write(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
...@@ -3654,13 +3653,14 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, ...@@ -3654,13 +3653,14 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
ext4_io_end_t *io_end = iocb->private; ext4_io_end_t *io_end = iocb->private;
struct workqueue_struct *wq; struct workqueue_struct *wq;
/* if not async direct IO or dio with 0 bytes write, just return */
if (!io_end || !size)
return;
ext_debug("ext4_end_io_dio(): io_end 0x%p" ext_debug("ext4_end_io_dio(): io_end 0x%p"
"for inode %lu, iocb 0x%p, offset %llu, size %llu\n", "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
iocb->private, io_end->inode->i_ino, iocb, offset, iocb->private, io_end->inode->i_ino, iocb, offset,
size); size);
/* if not async direct IO or dio with 0 bytes write, just return */
if (!io_end || !size)
return;
/* if not aio dio with unwritten extents, just free io and return */ /* if not aio dio with unwritten extents, just free io and return */
if (io_end->flag != DIO_AIO_UNWRITTEN){ if (io_end->flag != DIO_AIO_UNWRITTEN){
...@@ -3771,13 +3771,19 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, ...@@ -3771,13 +3771,19 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) { if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) {
ext4_free_io_end(iocb->private); ext4_free_io_end(iocb->private);
iocb->private = NULL; iocb->private = NULL;
} else if (ret > 0) } else if (ret > 0 && (EXT4_I(inode)->i_state &
EXT4_STATE_DIO_UNWRITTEN)) {
int err;
/* /*
* for non AIO case, since the IO is already * for non AIO case, since the IO is already
* completed, we could do the convertion right here * completed, we could do the convertion right here
*/ */
ret = ext4_convert_unwritten_extents(inode, err = ext4_convert_unwritten_extents(inode,
offset, ret); offset, ret);
if (err < 0)
ret = err;
EXT4_I(inode)->i_state &= ~EXT4_STATE_DIO_UNWRITTEN;
}
return ret; return ret;
} }
......
...@@ -1518,12 +1518,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, ...@@ -1518,12 +1518,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
return retval; return retval;
if (blocks == 1 && !dx_fallback && if (blocks == 1 && !dx_fallback &&
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
retval = make_indexed_dir(handle, dentry, inode, bh); return make_indexed_dir(handle, dentry, inode, bh);
if (retval == -ENOSPC)
brelse(bh);
return retval;
}
brelse(bh); brelse(bh);
} }
bh = ext4_append(handle, dir, &block, &retval); bh = ext4_append(handle, dir, &block, &retval);
...@@ -1532,10 +1528,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, ...@@ -1532,10 +1528,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
de = (struct ext4_dir_entry_2 *) bh->b_data; de = (struct ext4_dir_entry_2 *) bh->b_data;
de->inode = 0; de->inode = 0;
de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
retval = add_dirent_to_buf(handle, dentry, inode, de, bh); return add_dirent_to_buf(handle, dentry, inode, de, bh);
if (retval == -ENOSPC)
brelse(bh);
return retval;
} }
/* /*
...@@ -1664,7 +1657,6 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, ...@@ -1664,7 +1657,6 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
if (!de) if (!de)
goto cleanup; goto cleanup;
err = add_dirent_to_buf(handle, dentry, inode, de, bh); err = add_dirent_to_buf(handle, dentry, inode, de, bh);
if (err != -ENOSPC)
bh = NULL; bh = NULL;
goto cleanup; goto cleanup;
......
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