xfs
[Top] [All Lists]

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

To: xfs@xxxxxxxxxxx
Subject: [PATCH 2/4] xfs: always log file size updates
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Wed, 22 Jun 2011 16:01:31 -0400
References: <20110622200129.218994186@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.48-1
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);

<Prev in Thread] Current Thread [Next in Thread>