[PATCH 2/4] xfs: always log file size updates

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs


[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux