diff options
| -rw-r--r-- | fs/ext4/ext4.h | 7 | ||||
| -rw-r--r-- | fs/ext4/ext4_jbd2.h | 13 | ||||
| -rw-r--r-- | fs/ext4/extents.c | 14 | ||||
| -rw-r--r-- | fs/ext4/fsync.c | 46 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 29 | ||||
| -rw-r--r-- | fs/ext4/super.c | 2 |
6 files changed, 80 insertions, 31 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4cfc2f0edb3f..ab31e65d46d0 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -709,6 +709,13 @@ struct ext4_inode_info { | |||
| 709 | struct list_head i_aio_dio_complete_list; | 709 | struct list_head i_aio_dio_complete_list; |
| 710 | /* current io_end structure for async DIO write*/ | 710 | /* current io_end structure for async DIO write*/ |
| 711 | ext4_io_end_t *cur_aio_dio; | 711 | ext4_io_end_t *cur_aio_dio; |
| 712 | |||
| 713 | /* | ||
| 714 | * Transactions that contain inode's metadata needed to complete | ||
| 715 | * fsync and fdatasync, respectively. | ||
| 716 | */ | ||
| 717 | tid_t i_sync_tid; | ||
| 718 | tid_t i_datasync_tid; | ||
| 712 | }; | 719 | }; |
| 713 | 720 | ||
| 714 | /* | 721 | /* |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index 2c2b262bd31b..05eca817d704 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
| @@ -249,6 +249,19 @@ static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode) | |||
| 249 | return 0; | 249 | return 0; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | static inline void ext4_update_inode_fsync_trans(handle_t *handle, | ||
| 253 | struct inode *inode, | ||
| 254 | int datasync) | ||
| 255 | { | ||
| 256 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
| 257 | |||
| 258 | if (ext4_handle_valid(handle)) { | ||
| 259 | ei->i_sync_tid = handle->h_transaction->t_tid; | ||
| 260 | if (datasync) | ||
| 261 | ei->i_datasync_tid = handle->h_transaction->t_tid; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 252 | /* super.c */ | 265 | /* super.c */ |
| 253 | int ext4_force_commit(struct super_block *sb); | 266 | int ext4_force_commit(struct super_block *sb); |
| 254 | 267 | ||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 5967f18fd7e7..700206e525da 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -3058,6 +3058,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
| 3058 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { | 3058 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { |
| 3059 | ret = ext4_convert_unwritten_extents_dio(handle, inode, | 3059 | ret = ext4_convert_unwritten_extents_dio(handle, inode, |
| 3060 | path); | 3060 | path); |
| 3061 | if (ret >= 0) | ||
| 3062 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
| 3061 | goto out2; | 3063 | goto out2; |
| 3062 | } | 3064 | } |
| 3063 | /* buffered IO case */ | 3065 | /* buffered IO case */ |
| @@ -3085,6 +3087,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
| 3085 | ret = ext4_ext_convert_to_initialized(handle, inode, | 3087 | ret = ext4_ext_convert_to_initialized(handle, inode, |
| 3086 | path, iblock, | 3088 | path, iblock, |
| 3087 | max_blocks); | 3089 | max_blocks); |
| 3090 | if (ret >= 0) | ||
| 3091 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
| 3088 | out: | 3092 | out: |
| 3089 | if (ret <= 0) { | 3093 | if (ret <= 0) { |
| 3090 | err = ret; | 3094 | err = ret; |
| @@ -3323,10 +3327,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 3323 | allocated = ext4_ext_get_actual_len(&newex); | 3327 | allocated = ext4_ext_get_actual_len(&newex); |
| 3324 | set_buffer_new(bh_result); | 3328 | set_buffer_new(bh_result); |
| 3325 | 3329 | ||
| 3326 | /* Cache only when it is _not_ an uninitialized extent */ | 3330 | /* |
| 3327 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) | 3331 | * Cache the extent and update transaction to commit on fdatasync only |
| 3332 | * when it is _not_ an uninitialized extent. | ||
| 3333 | */ | ||
| 3334 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { | ||
| 3328 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, | 3335 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, |
| 3329 | EXT4_EXT_CACHE_EXTENT); | 3336 | EXT4_EXT_CACHE_EXTENT); |
| 3337 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
| 3338 | } else | ||
| 3339 | ext4_update_inode_fsync_trans(handle, inode, 0); | ||
| 3330 | out: | 3340 | out: |
| 3331 | if (allocated > max_blocks) | 3341 | if (allocated > max_blocks) |
| 3332 | allocated = max_blocks; | 3342 | allocated = max_blocks; |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index a3c25076aef1..0b22497d92e1 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -51,25 +51,30 @@ | |||
| 51 | int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | 51 | int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) |
| 52 | { | 52 | { |
| 53 | struct inode *inode = dentry->d_inode; | 53 | struct inode *inode = dentry->d_inode; |
| 54 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
| 54 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; | 55 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; |
| 55 | int err, ret = 0; | 56 | int ret; |
| 57 | tid_t commit_tid; | ||
| 56 | 58 | ||
| 57 | J_ASSERT(ext4_journal_current_handle() == NULL); | 59 | J_ASSERT(ext4_journal_current_handle() == NULL); |
| 58 | 60 | ||
| 59 | trace_ext4_sync_file(file, dentry, datasync); | 61 | trace_ext4_sync_file(file, dentry, datasync); |
| 60 | 62 | ||
| 63 | if (inode->i_sb->s_flags & MS_RDONLY) | ||
| 64 | return 0; | ||
| 65 | |||
| 61 | ret = flush_aio_dio_completed_IO(inode); | 66 | ret = flush_aio_dio_completed_IO(inode); |
| 62 | if (ret < 0) | 67 | if (ret < 0) |
| 63 | return ret; | 68 | return ret; |
| 69 | |||
| 70 | if (!journal) | ||
| 71 | return simple_fsync(file, dentry, datasync); | ||
| 72 | |||
| 64 | /* | 73 | /* |
| 65 | * data=writeback: | 74 | * data=writeback,ordered: |
| 66 | * The caller's filemap_fdatawrite()/wait will sync the data. | 75 | * The caller's filemap_fdatawrite()/wait will sync the data. |
| 67 | * sync_inode() will sync the metadata | 76 | * Metadata is in the journal, we wait for proper transaction to |
| 68 | * | 77 | * commit here. |
| 69 | * data=ordered: | ||
| 70 | * The caller's filemap_fdatawrite() will write the data and | ||
| 71 | * sync_inode() will write the inode if it is dirty. Then the caller's | ||
| 72 | * filemap_fdatawait() will wait on the pages. | ||
| 73 | * | 78 | * |
| 74 | * data=journal: | 79 | * data=journal: |
| 75 | * filemap_fdatawrite won't do anything (the buffers are clean). | 80 | * filemap_fdatawrite won't do anything (the buffers are clean). |
| @@ -82,27 +87,10 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 82 | if (ext4_should_journal_data(inode)) | 87 | if (ext4_should_journal_data(inode)) |
| 83 | return ext4_force_commit(inode->i_sb); | 88 | return ext4_force_commit(inode->i_sb); |
| 84 | 89 | ||
| 85 | if (!journal) | 90 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; |
| 86 | ret = sync_mapping_buffers(inode->i_mapping); | 91 | if (jbd2_log_start_commit(journal, commit_tid)) |
| 87 | 92 | jbd2_log_wait_commit(journal, commit_tid); | |
| 88 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 93 | else if (journal->j_flags & JBD2_BARRIER) |
| 89 | goto out; | ||
| 90 | |||
| 91 | /* | ||
| 92 | * The VFS has written the file data. If the inode is unaltered | ||
| 93 | * then we need not start a commit. | ||
| 94 | */ | ||
| 95 | if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { | ||
| 96 | struct writeback_control wbc = { | ||
| 97 | .sync_mode = WB_SYNC_ALL, | ||
| 98 | .nr_to_write = 0, /* sys_fsync did this */ | ||
| 99 | }; | ||
| 100 | err = sync_inode(inode, &wbc); | ||
| 101 | if (ret == 0) | ||
| 102 | ret = err; | ||
| 103 | } | ||
| 104 | out: | ||
| 105 | if (journal && (journal->j_flags & JBD2_BARRIER)) | ||
| 106 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | 94 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); |
| 107 | return ret; | 95 | return ret; |
| 108 | } | 96 | } |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 958c3ff800e9..f1bc1e338828 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -983,6 +983,8 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
| 983 | goto cleanup; | 983 | goto cleanup; |
| 984 | 984 | ||
| 985 | set_buffer_new(bh_result); | 985 | set_buffer_new(bh_result); |
| 986 | |||
| 987 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
| 986 | got_it: | 988 | got_it: |
| 987 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); | 989 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); |
| 988 | if (count > blocks_to_boundary) | 990 | if (count > blocks_to_boundary) |
| @@ -4738,6 +4740,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 4738 | struct ext4_inode *raw_inode; | 4740 | struct ext4_inode *raw_inode; |
| 4739 | struct ext4_inode_info *ei; | 4741 | struct ext4_inode_info *ei; |
| 4740 | struct inode *inode; | 4742 | struct inode *inode; |
| 4743 | journal_t *journal = EXT4_SB(sb)->s_journal; | ||
| 4741 | long ret; | 4744 | long ret; |
| 4742 | int block; | 4745 | int block; |
| 4743 | 4746 | ||
| @@ -4802,6 +4805,31 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 4802 | ei->i_data[block] = raw_inode->i_block[block]; | 4805 | ei->i_data[block] = raw_inode->i_block[block]; |
| 4803 | INIT_LIST_HEAD(&ei->i_orphan); | 4806 | INIT_LIST_HEAD(&ei->i_orphan); |
| 4804 | 4807 | ||
| 4808 | /* | ||
| 4809 | * Set transaction id's of transactions that have to be committed | ||
| 4810 | * to finish f[data]sync. We set them to currently running transaction | ||
| 4811 | * as we cannot be sure that the inode or some of its metadata isn't | ||
| 4812 | * part of the transaction - the inode could have been reclaimed and | ||
| 4813 | * now it is reread from disk. | ||
| 4814 | */ | ||
| 4815 | if (journal) { | ||
| 4816 | transaction_t *transaction; | ||
| 4817 | tid_t tid; | ||
| 4818 | |||
| 4819 | spin_lock(&journal->j_state_lock); | ||
| 4820 | if (journal->j_running_transaction) | ||
| 4821 | transaction = journal->j_running_transaction; | ||
| 4822 | else | ||
| 4823 | transaction = journal->j_committing_transaction; | ||
| 4824 | if (transaction) | ||
| 4825 | tid = transaction->t_tid; | ||
| 4826 | else | ||
| 4827 | tid = journal->j_commit_sequence; | ||
| 4828 | spin_unlock(&journal->j_state_lock); | ||
| 4829 | ei->i_sync_tid = tid; | ||
| 4830 | ei->i_datasync_tid = tid; | ||
| 4831 | } | ||
| 4832 | |||
| 4805 | if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { | 4833 | if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { |
| 4806 | ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); | 4834 | ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); |
| 4807 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > | 4835 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > |
| @@ -5056,6 +5084,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
| 5056 | err = rc; | 5084 | err = rc; |
| 5057 | ei->i_state &= ~EXT4_STATE_NEW; | 5085 | ei->i_state &= ~EXT4_STATE_NEW; |
| 5058 | 5086 | ||
| 5087 | ext4_update_inode_fsync_trans(handle, inode, 0); | ||
| 5059 | out_brelse: | 5088 | out_brelse: |
| 5060 | brelse(bh); | 5089 | brelse(bh); |
| 5061 | ext4_std_error(inode->i_sb, err); | 5090 | ext4_std_error(inode->i_sb, err); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8ab0c9518473..2b13dcfcf775 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -706,6 +706,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
| 706 | spin_lock_init(&(ei->i_block_reservation_lock)); | 706 | spin_lock_init(&(ei->i_block_reservation_lock)); |
| 707 | INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); | 707 | INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); |
| 708 | ei->cur_aio_dio = NULL; | 708 | ei->cur_aio_dio = NULL; |
| 709 | ei->i_sync_tid = 0; | ||
| 710 | ei->i_datasync_tid = 0; | ||
| 709 | 711 | ||
| 710 | return &ei->vfs_inode; | 712 | return &ei->vfs_inode; |
| 711 | } | 713 | } |
