Instead of updating the inode size through the VFS dirty mechanism and
->write_inode just log it directly. This may cause a few additional
transactions for inode core updates, but with the delaylog code those
are cheap enough to not bother.
Signed-off-by: Christoph Hellwig <hch@xxxxxx>
Index: xfs/fs/xfs/linux-2.6/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_aops.c 2011-06-22 10:58:30.344461631
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_aops.c 2011-06-22 10:58:55.877793671 +0200
@@ -156,29 +156,6 @@ xfs_ioend_new_eof(
}
/*
- * Update on-disk file size now that data has been written to disk. The
- * current in-memory file size is i_size. If a write is beyond eof i_new_size
- * will be the intended file size until i_size is updated. If this write does
- * not extend all the way to the valid file size then restrict this update to
- * the end of the write.
- */
-STATIC void
-xfs_setfilesize(
- xfs_ioend_t *ioend)
-{
- xfs_inode_t *ip = XFS_I(ioend->io_inode);
- xfs_fsize_t isize;
-
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- isize = xfs_ioend_new_eof(ioend);
- if (isize) {
- ip->i_d.di_size = isize;
- xfs_mark_inode_dirty(ip);
- }
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
-}
-
-/*
* Schedule IO completion handling on the final put of an ioend.
*/
STATIC void
@@ -223,10 +200,25 @@ xfs_end_io(
}
/*
- * We might have to update the on-disk file size after extending
- * writes.
+ * Update on-disk file size now that data has been written to disk.
+ *
+ * The current in-memory file size is i_size. If a write is beyond
+ * eof i_new_size will be the intended file size until i_size is
+ * updated. If this write does not extend all the way to the valid
+ * file size then restrict this update to the end of the write.
*/
- xfs_setfilesize(ioend);
+ if (likely(!ioend->io_error && !XFS_FORCED_SHUTDOWN(ip->i_mount))) {
+ xfs_fsize_t isize;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ isize = xfs_ioend_new_eof(ioend);
+ if (isize)
+ error = xfs_setfilesize(ip, isize);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+ if (error)
+ ioend->io_error = error;
+ }
if (ioend->io_iocb)
aio_complete(ioend->io_iocb, ioend->io_result, 0);
@@ -386,14 +378,6 @@ xfs_submit_ioend_bio(
atomic_inc(&ioend->io_remaining);
bio->bi_private = ioend;
bio->bi_end_io = xfs_end_bio;
-
- /*
- * If the I/O is beyond EOF we mark the inode dirty immediately
- * but don't update the inode size until I/O completion.
- */
- if (xfs_ioend_new_eof(ioend))
- xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
-
submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
}
Index: xfs/fs/xfs/linux-2.6/xfs_file.c
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_file.c 2011-06-22 10:58:30.361128296
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_file.c 2011-06-22 11:16:25.057740552 +0200
@@ -405,7 +405,7 @@ xfs_aio_write_newsize_update(
xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
ip->i_new_size = 0;
if (ip->i_d.di_size > ip->i_size)
- ip->i_d.di_size = ip->i_size;
+ xfs_setfilesize(ip, ip->i_size);
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
}
}
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-06-22 10:58:30.371128295 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-06-22 11:17:51.944402819 +0200
@@ -1515,6 +1515,34 @@ xfs_itruncate_finish(
}
/*
+ * Update the inode size during I/O completions or error handling.
+ */
+int
+xfs_setfilesize(
+ struct xfs_inode *ip,
+ xfs_fsize_t isize)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_trans *tp;
+ int error = 0;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+ tp = _xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS, KM_NOFS, true);
+ error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+ return error;
+ }
+
+ ip->i_d.di_size = isize;
+ xfs_trans_ijoin(tp, ip);
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ return xfs_trans_commit(tp, 0);
+}
+
+/*
* This is called when the inode's link count goes to 0.
* We place the on-disk inode on a list in the AGI. It
* will be pulled from this list when the inode is freed.
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-06-22 10:58:30.387794963 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-06-22 11:16:25.141073882 +0200
@@ -482,6 +482,7 @@ int xfs_ifree(struct xfs_trans *, xfs_i
struct xfs_bmap_free *);
int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
xfs_fsize_t, int, int);
+int xfs_setfilesize(struct xfs_inode *, xfs_fsize_t);
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int);
|