ext4: collapse handling of data=ordered and data=writeback codepaths
The only difference between how we handle data=ordered and data=writeback is a single call to ext4_jbd2_file_inode(). Eliminate code duplication by factoring out redundant the code paths. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Lukas Czerner <lczerner@redhat.com>
This commit is contained in:
@@ -1374,6 +1374,7 @@ enum {
|
|||||||
EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
|
EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
|
||||||
nolocking */
|
nolocking */
|
||||||
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
|
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
|
||||||
|
EXT4_STATE_ORDERED_MODE, /* data=ordered mode */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EXT4_INODE_BIT_FNS(name, field, offset) \
|
#define EXT4_INODE_BIT_FNS(name, field, offset) \
|
||||||
|
125
fs/ext4/inode.c
125
fs/ext4/inode.c
@@ -1145,77 +1145,36 @@ static int ext4_generic_write_end(struct file *file,
|
|||||||
* ext4 never places buffers on inode->i_mapping->private_list. metadata
|
* ext4 never places buffers on inode->i_mapping->private_list. metadata
|
||||||
* buffers are managed internally.
|
* buffers are managed internally.
|
||||||
*/
|
*/
|
||||||
static int ext4_ordered_write_end(struct file *file,
|
static int ext4_write_end(struct file *file,
|
||||||
struct address_space *mapping,
|
struct address_space *mapping,
|
||||||
loff_t pos, unsigned len, unsigned copied,
|
loff_t pos, unsigned len, unsigned copied,
|
||||||
struct page *page, void *fsdata)
|
struct page *page, void *fsdata)
|
||||||
{
|
{
|
||||||
handle_t *handle = ext4_journal_current_handle();
|
handle_t *handle = ext4_journal_current_handle();
|
||||||
struct inode *inode = mapping->host;
|
struct inode *inode = mapping->host;
|
||||||
int ret = 0, ret2;
|
int ret = 0, ret2;
|
||||||
|
|
||||||
trace_ext4_ordered_write_end(inode, pos, len, copied);
|
trace_ext4_write_end(inode, pos, len, copied);
|
||||||
ret = ext4_jbd2_file_inode(handle, inode);
|
if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
|
||||||
|
ret = ext4_jbd2_file_inode(handle, inode);
|
||||||
if (ret == 0) {
|
if (ret) {
|
||||||
ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
|
unlock_page(page);
|
||||||
page, fsdata);
|
page_cache_release(page);
|
||||||
copied = ret2;
|
goto errout;
|
||||||
if (pos + len > inode->i_size && ext4_can_truncate(inode))
|
}
|
||||||
/* if we have allocated more blocks and copied
|
|
||||||
* less. We will have blocks allocated outside
|
|
||||||
* inode->i_size. So truncate them
|
|
||||||
*/
|
|
||||||
ext4_orphan_add(handle, inode);
|
|
||||||
if (ret2 < 0)
|
|
||||||
ret = ret2;
|
|
||||||
} else {
|
|
||||||
unlock_page(page);
|
|
||||||
page_cache_release(page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret2 = ext4_journal_stop(handle);
|
copied = ext4_generic_write_end(file, mapping, pos, len, copied,
|
||||||
if (!ret)
|
page, fsdata);
|
||||||
ret = ret2;
|
if (copied < 0)
|
||||||
|
ret = copied;
|
||||||
if (pos + len > inode->i_size) {
|
|
||||||
ext4_truncate_failed_write(inode);
|
|
||||||
/*
|
|
||||||
* If truncate failed early the inode might still be
|
|
||||||
* on the orphan list; we need to make sure the inode
|
|
||||||
* is removed from the orphan list in that case.
|
|
||||||
*/
|
|
||||||
if (inode->i_nlink)
|
|
||||||
ext4_orphan_del(NULL, inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return ret ? ret : copied;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ext4_writeback_write_end(struct file *file,
|
|
||||||
struct address_space *mapping,
|
|
||||||
loff_t pos, unsigned len, unsigned copied,
|
|
||||||
struct page *page, void *fsdata)
|
|
||||||
{
|
|
||||||
handle_t *handle = ext4_journal_current_handle();
|
|
||||||
struct inode *inode = mapping->host;
|
|
||||||
int ret = 0, ret2;
|
|
||||||
|
|
||||||
trace_ext4_writeback_write_end(inode, pos, len, copied);
|
|
||||||
ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
|
|
||||||
page, fsdata);
|
|
||||||
copied = ret2;
|
|
||||||
if (pos + len > inode->i_size && ext4_can_truncate(inode))
|
if (pos + len > inode->i_size && ext4_can_truncate(inode))
|
||||||
/* if we have allocated more blocks and copied
|
/* if we have allocated more blocks and copied
|
||||||
* less. We will have blocks allocated outside
|
* less. We will have blocks allocated outside
|
||||||
* inode->i_size. So truncate them
|
* inode->i_size. So truncate them
|
||||||
*/
|
*/
|
||||||
ext4_orphan_add(handle, inode);
|
ext4_orphan_add(handle, inode);
|
||||||
|
errout:
|
||||||
if (ret2 < 0)
|
|
||||||
ret = ret2;
|
|
||||||
|
|
||||||
ret2 = ext4_journal_stop(handle);
|
ret2 = ext4_journal_stop(handle);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = ret2;
|
ret = ret2;
|
||||||
@@ -2818,18 +2777,9 @@ static int ext4_da_write_end(struct file *file,
|
|||||||
unsigned long start, end;
|
unsigned long start, end;
|
||||||
int write_mode = (int)(unsigned long)fsdata;
|
int write_mode = (int)(unsigned long)fsdata;
|
||||||
|
|
||||||
if (write_mode == FALL_BACK_TO_NONDELALLOC) {
|
if (write_mode == FALL_BACK_TO_NONDELALLOC)
|
||||||
switch (ext4_inode_journal_mode(inode)) {
|
return ext4_write_end(file, mapping, pos,
|
||||||
case EXT4_INODE_ORDERED_DATA_MODE:
|
len, copied, page, fsdata);
|
||||||
return ext4_ordered_write_end(file, mapping, pos,
|
|
||||||
len, copied, page, fsdata);
|
|
||||||
case EXT4_INODE_WRITEBACK_DATA_MODE:
|
|
||||||
return ext4_writeback_write_end(file, mapping, pos,
|
|
||||||
len, copied, page, fsdata);
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_ext4_da_write_end(inode, pos, len, copied);
|
trace_ext4_da_write_end(inode, pos, len, copied);
|
||||||
start = pos & (PAGE_CACHE_SIZE - 1);
|
start = pos & (PAGE_CACHE_SIZE - 1);
|
||||||
@@ -3334,27 +3284,12 @@ static int ext4_journalled_set_page_dirty(struct page *page)
|
|||||||
return __set_page_dirty_nobuffers(page);
|
return __set_page_dirty_nobuffers(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct address_space_operations ext4_ordered_aops = {
|
static const struct address_space_operations ext4_aops = {
|
||||||
.readpage = ext4_readpage,
|
.readpage = ext4_readpage,
|
||||||
.readpages = ext4_readpages,
|
.readpages = ext4_readpages,
|
||||||
.writepage = ext4_writepage,
|
.writepage = ext4_writepage,
|
||||||
.write_begin = ext4_write_begin,
|
.write_begin = ext4_write_begin,
|
||||||
.write_end = ext4_ordered_write_end,
|
.write_end = ext4_write_end,
|
||||||
.bmap = ext4_bmap,
|
|
||||||
.invalidatepage = ext4_invalidatepage,
|
|
||||||
.releasepage = ext4_releasepage,
|
|
||||||
.direct_IO = ext4_direct_IO,
|
|
||||||
.migratepage = buffer_migrate_page,
|
|
||||||
.is_partially_uptodate = block_is_partially_uptodate,
|
|
||||||
.error_remove_page = generic_error_remove_page,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct address_space_operations ext4_writeback_aops = {
|
|
||||||
.readpage = ext4_readpage,
|
|
||||||
.readpages = ext4_readpages,
|
|
||||||
.writepage = ext4_writepage,
|
|
||||||
.write_begin = ext4_write_begin,
|
|
||||||
.write_end = ext4_writeback_write_end,
|
|
||||||
.bmap = ext4_bmap,
|
.bmap = ext4_bmap,
|
||||||
.invalidatepage = ext4_invalidatepage,
|
.invalidatepage = ext4_invalidatepage,
|
||||||
.releasepage = ext4_releasepage,
|
.releasepage = ext4_releasepage,
|
||||||
@@ -3399,23 +3334,21 @@ void ext4_set_aops(struct inode *inode)
|
|||||||
{
|
{
|
||||||
switch (ext4_inode_journal_mode(inode)) {
|
switch (ext4_inode_journal_mode(inode)) {
|
||||||
case EXT4_INODE_ORDERED_DATA_MODE:
|
case EXT4_INODE_ORDERED_DATA_MODE:
|
||||||
if (test_opt(inode->i_sb, DELALLOC))
|
ext4_set_inode_state(inode, EXT4_STATE_ORDERED_MODE);
|
||||||
inode->i_mapping->a_ops = &ext4_da_aops;
|
|
||||||
else
|
|
||||||
inode->i_mapping->a_ops = &ext4_ordered_aops;
|
|
||||||
break;
|
break;
|
||||||
case EXT4_INODE_WRITEBACK_DATA_MODE:
|
case EXT4_INODE_WRITEBACK_DATA_MODE:
|
||||||
if (test_opt(inode->i_sb, DELALLOC))
|
ext4_clear_inode_state(inode, EXT4_STATE_ORDERED_MODE);
|
||||||
inode->i_mapping->a_ops = &ext4_da_aops;
|
|
||||||
else
|
|
||||||
inode->i_mapping->a_ops = &ext4_writeback_aops;
|
|
||||||
break;
|
break;
|
||||||
case EXT4_INODE_JOURNAL_DATA_MODE:
|
case EXT4_INODE_JOURNAL_DATA_MODE:
|
||||||
inode->i_mapping->a_ops = &ext4_journalled_aops;
|
inode->i_mapping->a_ops = &ext4_journalled_aops;
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
if (test_opt(inode->i_sb, DELALLOC))
|
||||||
|
inode->i_mapping->a_ops = &ext4_da_aops;
|
||||||
|
else
|
||||||
|
inode->i_mapping->a_ops = &ext4_aops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -257,15 +257,7 @@ DECLARE_EVENT_CLASS(ext4__write_end,
|
|||||||
__entry->pos, __entry->len, __entry->copied)
|
__entry->pos, __entry->len, __entry->copied)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end,
|
DEFINE_EVENT(ext4__write_end, ext4_write_end,
|
||||||
|
|
||||||
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
|
|
||||||
unsigned int copied),
|
|
||||||
|
|
||||||
TP_ARGS(inode, pos, len, copied)
|
|
||||||
);
|
|
||||||
|
|
||||||
DEFINE_EVENT(ext4__write_end, ext4_writeback_write_end,
|
|
||||||
|
|
||||||
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
|
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
|
||||||
unsigned int copied),
|
unsigned int copied),
|
||||||
|
Reference in New Issue
Block a user