Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Oct 2009 20:29:42 +0000 (13:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Oct 2009 20:29:42 +0000 (13:29 -0700)
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
  xfs: stop calling filemap_fdatawait inside ->fsync
  fix readahead calculations in xfs_dir2_leaf_getdents()
  xfs: make sure xfs_sync_fsdata covers the log
  xfs: mark inodes dirty before issuing I/O
  xfs: cleanup ->sync_fs
  xfs: fix xfs_quiesce_data
  xfs: implement ->dirty_inode to fix timestamp handling

1  2 
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_super.c

@@@ -186,19 -186,37 +186,37 @@@ xfs_destroy_ioend
  }
  
  /*
+  * If the end of the current ioend is beyond the current EOF,
+  * return the new EOF value, otherwise zero.
+  */
+ STATIC xfs_fsize_t
+ xfs_ioend_new_eof(
+       xfs_ioend_t             *ioend)
+ {
+       xfs_inode_t             *ip = XFS_I(ioend->io_inode);
+       xfs_fsize_t             isize;
+       xfs_fsize_t             bsize;
+       bsize = ioend->io_offset + ioend->io_size;
+       isize = MAX(ip->i_size, ip->i_new_size);
+       isize = MIN(isize, bsize);
+       return isize > ip->i_d.di_size ? isize : 0;
+ }
+ /*
   * 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_fsize_t             bsize;
  
        ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
        ASSERT(ioend->io_type != IOMAP_READ);
        if (unlikely(ioend->io_error))
                return;
  
-       bsize = ioend->io_offset + ioend->io_size;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       isize = MAX(ip->i_size, ip->i_new_size);
-       isize = MIN(isize, bsize);
-       if (ip->i_d.di_size < isize) {
+       isize = xfs_ioend_new_eof(ioend);
+       if (isize) {
                ip->i_d.di_size = isize;
-               ip->i_update_core = 1;
                xfs_mark_inode_dirty_sync(ip);
        }
  
@@@ -404,10 -416,16 +416,16 @@@ xfs_submit_ioend_bio
        struct bio      *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_sync(XFS_I(ioend->io_inode));
        submit_bio(WRITE, bio);
        ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
        bio_put(bio);
@@@ -1635,5 -1653,4 +1653,5 @@@ const struct address_space_operations x
        .direct_IO              = xfs_vm_direct_IO,
        .migratepage            = buffer_migrate_page,
        .is_partially_uptodate  = block_is_partially_uptodate,
 +      .error_remove_page      = generic_error_remove_page,
  };
@@@ -42,7 -42,7 +42,7 @@@
  
  #include <linux/dcache.h>
  
 -static struct vm_operations_struct xfs_file_vm_ops;
 +static const struct vm_operations_struct xfs_file_vm_ops;
  
  STATIC ssize_t
  xfs_file_aio_read(
@@@ -176,14 -176,7 +176,7 @@@ xfs_file_fsync
        struct dentry           *dentry,
        int                     datasync)
  {
-       struct inode            *inode = dentry->d_inode;
-       struct xfs_inode        *ip = XFS_I(inode);
-       int                     error;
-       /* capture size updates in I/O completion before writing the inode. */
-       error = filemap_fdatawait(inode->i_mapping);
-       if (error)
-               return error;
+       struct xfs_inode        *ip = XFS_I(dentry->d_inode);
  
        xfs_iflags_clear(ip, XFS_ITRUNCATED);
        return -xfs_fsync(ip);
@@@ -280,7 -273,7 +273,7 @@@ const struct file_operations xfs_dir_fi
        .fsync          = xfs_file_fsync,
  };
  
 -static struct vm_operations_struct xfs_file_vm_ops = {
 +static const struct vm_operations_struct xfs_file_vm_ops = {
        .fault          = filemap_fault,
        .page_mkwrite   = xfs_vm_page_mkwrite,
  };
@@@ -67,7 -67,7 +67,7 @@@
  #include <linux/freezer.h>
  #include <linux/parser.h>
  
 -static struct super_operations xfs_super_operations;
 +static const struct super_operations xfs_super_operations;
  static kmem_zone_t *xfs_ioend_zone;
  mempool_t *xfs_ioend_pool;
  
@@@ -977,6 -977,28 +977,28 @@@ xfs_fs_inode_init_once
  }
  
  /*
+  * Dirty the XFS inode when mark_inode_dirty_sync() is called so that
+  * we catch unlogged VFS level updates to the inode. Care must be taken
+  * here - the transaction code calls mark_inode_dirty_sync() to mark the
+  * VFS inode dirty in a transaction and clears the i_update_core field;
+  * it must clear the field after calling mark_inode_dirty_sync() to
+  * correctly indicate that the dirty state has been propagated into the
+  * inode log item.
+  *
+  * We need the barrier() to maintain correct ordering between unlogged
+  * updates and the transaction commit code that clears the i_update_core
+  * field. This requires all updates to be completed before marking the
+  * inode dirty.
+  */
+ STATIC void
+ xfs_fs_dirty_inode(
+       struct inode    *inode)
+ {
+       barrier();
+       XFS_I(inode)->i_update_core = 1;
+ }
+ /*
   * Attempt to flush the inode, this will actually fail
   * if the inode is pinned, but we dirty the inode again
   * at the point when it is unpinned after a log write,
@@@ -1126,7 -1148,7 +1148,7 @@@ xfs_fs_put_super
  }
  
  STATIC int
- xfs_fs_sync_super(
+ xfs_fs_sync_fs(
        struct super_block      *sb,
        int                     wait)
  {
        int                     error;
  
        /*
-        * Treat a sync operation like a freeze.  This is to work
-        * around a race in sync_inodes() which works in two phases
-        * - an asynchronous flush, which can write out an inode
-        * without waiting for file size updates to complete, and a
-        * synchronous flush, which wont do anything because the
-        * async flush removed the inode's dirty flag.  Also
-        * sync_inodes() will not see any files that just have
-        * outstanding transactions to be flushed because we don't
-        * dirty the Linux inode until after the transaction I/O
-        * completes.
+        * Not much we can do for the first async pass.  Writing out the
+        * superblock would be counter-productive as we are going to redirty
+        * when writing out other data and metadata (and writing out a single
+        * block is quite fast anyway).
+        *
+        * Try to asynchronously kick off quota syncing at least.
         */
-       if (wait || unlikely(sb->s_frozen == SB_FREEZE_WRITE))
-               error = xfs_quiesce_data(mp);
-       else
-               error = xfs_sync_fsdata(mp, 0);
+       if (!wait) {
+               xfs_qm_sync(mp, SYNC_TRYLOCK);
+               return 0;
+       }
+       error = xfs_quiesce_data(mp);
+       if (error)
+               return -error;
  
-       if (unlikely(laptop_mode)) {
+       if (laptop_mode) {
                int     prev_sync_seq = mp->m_sync_seq;
  
                /*
                                mp->m_sync_seq != prev_sync_seq);
        }
  
-       return -error;
+       return 0;
  }
  
  STATIC int
@@@ -1536,13 -1558,14 +1558,14 @@@ xfs_fs_get_sb
                           mnt);
  }
  
 -static struct super_operations xfs_super_operations = {
 +static const struct super_operations xfs_super_operations = {
        .alloc_inode            = xfs_fs_alloc_inode,
        .destroy_inode          = xfs_fs_destroy_inode,
+       .dirty_inode            = xfs_fs_dirty_inode,
        .write_inode            = xfs_fs_write_inode,
        .clear_inode            = xfs_fs_clear_inode,
        .put_super              = xfs_fs_put_super,
-       .sync_fs                = xfs_fs_sync_super,
+       .sync_fs                = xfs_fs_sync_fs,
        .freeze_fs              = xfs_fs_freeze,
        .statfs                 = xfs_fs_statfs,
        .remount_fs             = xfs_fs_remount,