Commit 66d834ea authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Alex Elder
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <david@fromorbit.com>
Signed-off-by: default avatarAlex Elder <aelder@sgi.com>
parent fd3200be
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -187,7 +187,7 @@ xfs_setfilesize(
	isize = xfs_ioend_new_eof(ioend);
	if (isize) {
		ip->i_d.di_size = isize;
		xfs_mark_inode_dirty_sync(ip);
		xfs_mark_inode_dirty(ip);
	}

	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.
	 */
	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 ?
		   WRITE_SYNC_PLUG : WRITE, bio);
+12 −11
Original line number Diff line number Diff line
@@ -97,16 +97,6 @@ xfs_iozero(
	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
xfs_file_fsync(
	struct file		*file,
@@ -139,7 +129,18 @@ xfs_file_fsync(
	 */
	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
		 * updates.  The sync transaction will also force the log.
+10 −0
Original line number Diff line number Diff line
@@ -91,6 +91,16 @@ xfs_mark_inode_dirty_sync(
		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.
 * We don't lock across timestamp updates, and we don't log them but
+1 −0
Original line number Diff line number Diff line
@@ -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_synchronize_times(xfs_inode_t *);
void		xfs_mark_inode_dirty(xfs_inode_t *);
void		xfs_mark_inode_dirty_sync(xfs_inode_t *);

#define IHOLD(ip) \