xfs: implement optimized fdatasync
Allow us to track the difference between timestamp and size updates by using mark_inode_dirty from the I/O completion code, and checking the VFS inode flags in xfs_file_fsync. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <david@fromorbit.com> Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
committed by
Alex Elder
parent
fd3200bef7
commit
66d834ea60
@@ -187,7 +187,7 @@ xfs_setfilesize(
|
|||||||
isize = xfs_ioend_new_eof(ioend);
|
isize = xfs_ioend_new_eof(ioend);
|
||||||
if (isize) {
|
if (isize) {
|
||||||
ip->i_d.di_size = isize;
|
ip->i_d.di_size = isize;
|
||||||
xfs_mark_inode_dirty_sync(ip);
|
xfs_mark_inode_dirty(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||||
@@ -341,7 +341,7 @@ xfs_submit_ioend_bio(
|
|||||||
* but don't update the inode size until I/O completion.
|
* but don't update the inode size until I/O completion.
|
||||||
*/
|
*/
|
||||||
if (xfs_ioend_new_eof(ioend))
|
if (xfs_ioend_new_eof(ioend))
|
||||||
xfs_mark_inode_dirty_sync(XFS_I(ioend->io_inode));
|
xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
|
||||||
|
|
||||||
submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
|
submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
|
||||||
WRITE_SYNC_PLUG : WRITE, bio);
|
WRITE_SYNC_PLUG : WRITE, bio);
|
||||||
|
@@ -97,16 +97,6 @@ xfs_iozero(
|
|||||||
return (-status);
|
return (-status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We ignore the datasync flag here because a datasync is effectively
|
|
||||||
* identical to an fsync. That is, datasync implies that we need to write
|
|
||||||
* only the metadata needed to be able to access the data that is written
|
|
||||||
* if we crash after the call completes. Hence if we are writing beyond
|
|
||||||
* EOF we have to log the inode size change as well, which makes it a
|
|
||||||
* full fsync. If we don't write beyond EOF, the inode core will be
|
|
||||||
* clean in memory and so we don't need to log the inode, just like
|
|
||||||
* fsync.
|
|
||||||
*/
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_file_fsync(
|
xfs_file_fsync(
|
||||||
struct file *file,
|
struct file *file,
|
||||||
@@ -139,7 +129,18 @@ xfs_file_fsync(
|
|||||||
*/
|
*/
|
||||||
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
||||||
|
|
||||||
if (ip->i_update_core) {
|
/*
|
||||||
|
* First check if the VFS inode is marked dirty. All the dirtying
|
||||||
|
* of non-transactional updates no goes through mark_inode_dirty*,
|
||||||
|
* which allows us to distinguish beteeen pure timestamp updates
|
||||||
|
* and i_size updates which need to be caught for fdatasync.
|
||||||
|
* After that also theck for the dirty state in the XFS inode, which
|
||||||
|
* might gets cleared when the inode gets written out via the AIL
|
||||||
|
* or xfs_iflush_cluster.
|
||||||
|
*/
|
||||||
|
if (((dentry->d_inode->i_state & I_DIRTY_DATASYNC) ||
|
||||||
|
((dentry->d_inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
|
||||||
|
ip->i_update_core) {
|
||||||
/*
|
/*
|
||||||
* Kick off a transaction to log the inode core to get the
|
* Kick off a transaction to log the inode core to get the
|
||||||
* updates. The sync transaction will also force the log.
|
* updates. The sync transaction will also force the log.
|
||||||
|
@@ -91,6 +91,16 @@ xfs_mark_inode_dirty_sync(
|
|||||||
mark_inode_dirty_sync(inode);
|
mark_inode_dirty_sync(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfs_mark_inode_dirty(
|
||||||
|
xfs_inode_t *ip)
|
||||||
|
{
|
||||||
|
struct inode *inode = VFS_I(ip);
|
||||||
|
|
||||||
|
if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR)))
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the requested timestamp in the given inode.
|
* Change the requested timestamp in the given inode.
|
||||||
* We don't lock across timestamp updates, and we don't log them but
|
* We don't lock across timestamp updates, and we don't log them but
|
||||||
|
@@ -480,6 +480,7 @@ void xfs_lock_inodes(xfs_inode_t **, int, uint);
|
|||||||
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
|
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
|
||||||
|
|
||||||
void xfs_synchronize_times(xfs_inode_t *);
|
void xfs_synchronize_times(xfs_inode_t *);
|
||||||
|
void xfs_mark_inode_dirty(xfs_inode_t *);
|
||||||
void xfs_mark_inode_dirty_sync(xfs_inode_t *);
|
void xfs_mark_inode_dirty_sync(xfs_inode_t *);
|
||||||
|
|
||||||
#define IHOLD(ip) \
|
#define IHOLD(ip) \
|
||||||
|
Reference in New Issue
Block a user