ext3: Fix waiting on transaction during fsync
log_start_commit() returns 1 only when it started a transaction commit. Thus in case transaction commit is already running, we fail to wait for the commit to finish. Fix the issue by always waiting for the commit regardless of the log_start_commit return value. Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
03f4d804a1
commit
5277970878
|
@ -48,7 +48,7 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
struct ext3_inode_info *ei = EXT3_I(inode);
|
struct ext3_inode_info *ei = EXT3_I(inode);
|
||||||
journal_t *journal = EXT3_SB(inode->i_sb)->s_journal;
|
journal_t *journal = EXT3_SB(inode->i_sb)->s_journal;
|
||||||
int ret = 0;
|
int ret, needs_barrier = 0;
|
||||||
tid_t commit_tid;
|
tid_t commit_tid;
|
||||||
|
|
||||||
if (inode->i_sb->s_flags & MS_RDONLY)
|
if (inode->i_sb->s_flags & MS_RDONLY)
|
||||||
|
@ -70,28 +70,26 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||||
* (they were dirtied by commit). But that's OK - the blocks are
|
* (they were dirtied by commit). But that's OK - the blocks are
|
||||||
* safe in-journal, which is all fsync() needs to ensure.
|
* safe in-journal, which is all fsync() needs to ensure.
|
||||||
*/
|
*/
|
||||||
if (ext3_should_journal_data(inode)) {
|
if (ext3_should_journal_data(inode))
|
||||||
ret = ext3_force_commit(inode->i_sb);
|
return ext3_force_commit(inode->i_sb);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (datasync)
|
if (datasync)
|
||||||
commit_tid = atomic_read(&ei->i_datasync_tid);
|
commit_tid = atomic_read(&ei->i_datasync_tid);
|
||||||
else
|
else
|
||||||
commit_tid = atomic_read(&ei->i_sync_tid);
|
commit_tid = atomic_read(&ei->i_sync_tid);
|
||||||
|
|
||||||
if (log_start_commit(journal, commit_tid)) {
|
if (test_opt(inode->i_sb, BARRIER) &&
|
||||||
log_wait_commit(journal, commit_tid);
|
!journal_trans_will_send_data_barrier(journal, commit_tid))
|
||||||
goto out;
|
needs_barrier = 1;
|
||||||
}
|
log_start_commit(journal, commit_tid);
|
||||||
|
ret = log_wait_commit(journal, commit_tid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case we didn't commit a transaction, we have to flush
|
* In case we didn't commit a transaction, we have to flush
|
||||||
* disk caches manually so that data really is on persistent
|
* disk caches manually so that data really is on persistent
|
||||||
* storage
|
* storage
|
||||||
*/
|
*/
|
||||||
if (test_opt(inode->i_sb, BARRIER))
|
if (needs_barrier)
|
||||||
blkdev_issue_flush(inode->i_sb->s_bdev, NULL);
|
blkdev_issue_flush(inode->i_sb->s_bdev, NULL);
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,7 +594,7 @@ out:
|
||||||
spin_unlock(&journal->j_state_lock);
|
spin_unlock(&journal->j_state_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(journal_commit_will_send_barrier);
|
EXPORT_SYMBOL(journal_trans_will_send_data_barrier);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log buffer allocation routines:
|
* Log buffer allocation routines:
|
||||||
|
|
Loading…
Reference in a new issue