xfs
[Top] [All Lists]

[PATCH 3/4] xfs: always log timestamp updates

To: xfs@xxxxxxxxxxx
Subject: [PATCH 3/4] xfs: always log timestamp updates
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Wed, 22 Jun 2011 16:01:32 -0400
References: <20110622200129.218994186@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.48-1
Switch read/write path timestamp updates to use normal logging instead
of going through the VFS dirty tracking machinery.  This is implemented
by logging the inode core in ->dirty_inode.  Compared to the old code
this may cause additional transactions to be started when we do a lot
of small writes to a file, but with the delayed logging code those
do not have major overhead.

After this patch all inode updates are logged directly, and we do not
have to implement a write_inode method anymore.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>

Index: xfs/fs/xfs/linux-2.6/xfs_file.c
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_file.c        2011-06-22 11:16:25.057740552 
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_file.c     2011-06-22 11:33:21.497689090 +0200
@@ -132,7 +132,6 @@ xfs_file_fsync(
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
 
@@ -160,76 +159,17 @@ xfs_file_fsync(
        }
 
        /*
-        * We always need to make sure that the required inode state is safe on
-        * disk.  The inode might be clean but we still might need to force the
-        * log because of committed transactions that haven't hit the disk yet.
-        * Likewise, there could be unflushed non-transactional changes to the
-        * inode core that have to go to disk and this requires us to issue
-        * a synchronous transaction to capture these changes correctly.
-        *
-        * This code relies on the assumption that if the i_update_core field
-        * of the inode is clear and the inode is unpinned then it is clean
-        * and no action is required.
+        * All updates to the inode are logged, so in addition to the write
+        * cache flushing we really just have to force out the log up to
+        * the LSN that last modified this inode.
         */
        xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-       /*
-        * 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 (((inode->i_state & I_DIRTY_DATASYNC) ||
-           ((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.
-                */
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
-               tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-               error = xfs_trans_reserve(tp, 0,
-                               XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       return -error;
-               }
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-               /*
-                * Note - it's possible that we might have pushed ourselves out
-                * of the way during trans_reserve which would flush the inode.
-                * But there's no guarantee that the inode buffer has actually
-                * gone out yet (it's delwri).  Plus the buffer could be pinned
-                * anyway if it's part of an inode in another recent
-                * transaction.  So we play it safe and fire off the
-                * transaction anyway.
-                */
-               xfs_trans_ijoin(tp, ip);
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-               xfs_trans_set_sync(tp);
-               error = _xfs_trans_commit(tp, 0, &log_flushed);
-
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       } else {
-               /*
-                * Timestamps/size haven't changed since last inode flush or
-                * inode transaction commit.  That means either nothing got
-                * written or a transaction committed which caught the updates.
-                * If the latter happened and the transaction hasn't hit the
-                * disk yet, the inode will be still be pinned.  If it is,
-                * force the log.
-                */
-               if (xfs_ipincount(ip)) {
-                       error = _xfs_log_force_lsn(mp,
-                                       ip->i_itemp->ili_last_lsn,
-                                       XFS_LOG_SYNC, &log_flushed);
-               }
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       if (xfs_ipincount(ip)) {
+               error = _xfs_log_force_lsn(ip->i_mount,
+                               ip->i_itemp->ili_last_lsn,
+                               XFS_LOG_SYNC, &log_flushed);
        }
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        /*
         * If we only have a single device, and the log force about was
@@ -669,9 +609,6 @@ xfs_file_aio_write_checks(
        if (new_size > ip->i_size)
                ip->i_new_size = new_size;
 
-       if (likely(!(file->f_mode & FMODE_NOCMTIME)))
-               file_update_time(file);
-
        /*
         * If the offset is beyond the size of the file, we need to zero any
         * blocks that fall between the existing EOF and the start of this
@@ -684,6 +621,9 @@ xfs_file_aio_write_checks(
        if (error)
                return error;
 
+       if (likely(!(file->f_mode & FMODE_NOCMTIME)))
+               file_update_time(file);
+
        /*
         * If we're writing the file then make sure to clear the setuid and
         * setgid bits if the process is not being run by root.  This keeps
Index: xfs/fs/xfs/linux-2.6/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_super.c       2011-06-22 11:16:25.071073884 
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_super.c    2011-06-22 20:46:46.996007785 +0200
@@ -895,129 +895,54 @@ xfs_fs_inode_init_once(
                     "xfsino", ip->i_ino);
 }
 
-/*
- * Dirty the XFS inode when mark_inode_dirty_sync() is called so that
- * we catch unlogged VFS level updates to the inode.
- *
- * 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,
-       int             flags)
-{
-       barrier();
-       XFS_I(inode)->i_update_core = 1;
-}
-
-STATIC int
-xfs_log_inode(
-       struct xfs_inode        *ip)
+       struct inode            *inode,
+       int                     flags)
 {
+       struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error;
 
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       /*
+        * We only want to log the inode if the flags are exactly
+        * I_DIRTY_SYNC, as that is what the VFS uses for logging
+        * timestamp updates.  In theory there shouldn't be other calls
+        * from generic code anyway, but the generic_write_end() keeps
+        * dirtying the inode after updating i_size in the Linux inode.
+        */
+       if (flags != I_DIRTY_SYNC)
+               return;
+
+       trace_xfs_dirty_inode(ip);
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
        error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-
        if (error) {
                xfs_trans_cancel(tp, 0);
-               /* we need to return with the lock hold shared */
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-               return error;
+               return;
        }
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
        /*
-        * Note - it's possible that we might have pushed ourselves out of the
-        * way during trans_reserve which would flush the inode.  But there's
-        * no guarantee that the inode buffer has actually gone out yet (it's
-        * delwri).  Plus the buffer could be pinned anyway if it's part of
-        * an inode in another recent transaction.  So we play it safe and
-        * fire off the transaction anyway.
+        * Make sure to get the latest timestamps from the Linux inode.
         */
+       ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
+       ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
+       ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
+       ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
+       ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
+       ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
+
        xfs_trans_ijoin(tp, ip);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        error = xfs_trans_commit(tp, 0);
-       xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
-
-       return error;
-}
-
-STATIC int
-xfs_fs_write_inode(
-       struct inode            *inode,
-       struct writeback_control *wbc)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       int                     error = EAGAIN;
-
-       trace_xfs_write_inode(ip);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       if (wbc->sync_mode == WB_SYNC_ALL) {
-               /*
-                * Make sure the inode has made it it into the log.  Instead
-                * of forcing it all the way to stable storage using a
-                * synchronous transaction we let the log force inside the
-                * ->sync_fs call do that for thus, which reduces the number
-                * of synchronous log foces dramatically.
-                */
-               xfs_ioend_wait(ip);
-               xfs_ilock(ip, XFS_ILOCK_SHARED);
-               if (ip->i_update_core) {
-                       error = xfs_log_inode(ip);
-                       if (error)
-                               goto out_unlock;
-               }
-       } else {
-               /*
-                * We make this non-blocking if the inode is contended, return
-                * EAGAIN to indicate to the caller that they did not succeed.
-                * This prevents the flush path from blocking on inodes inside
-                * another operation right now, they get caught later by
-                * xfs_sync.
-                */
-               if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
-                       goto out;
-
-               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
-                       goto out_unlock;
-
-               /*
-                * Now we have the flush lock and the inode is not pinned, we
-                * can check if the inode is really clean as we know that
-                * there are no pending transaction completions, it is not
-                * waiting on the delayed write queue and there is no IO in
-                * progress.
-                */
-               if (xfs_inode_clean(ip)) {
-                       xfs_ifunlock(ip);
-                       error = 0;
-                       goto out_unlock;
-               }
-               error = xfs_iflush(ip, SYNC_TRYLOCK);
+       if (error) {
+               /* print error */
        }
-
- out_unlock:
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
- out:
-       /*
-        * if we failed to write out the inode then mark
-        * it dirty again so we'll try again later.
-        */
-       if (error)
-               xfs_mark_inode_dirty_sync(ip);
-       return -error;
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 }
 
 STATIC void
@@ -1545,7 +1470,6 @@ static const struct super_operations xfs
        .alloc_inode            = xfs_fs_alloc_inode,
        .destroy_inode          = xfs_fs_destroy_inode,
        .dirty_inode            = xfs_fs_dirty_inode,
-       .write_inode            = xfs_fs_write_inode,
        .evict_inode            = xfs_fs_evict_inode,
        .put_super              = xfs_fs_put_super,
        .sync_fs                = xfs_fs_sync_fs,
Index: xfs/fs/xfs/xfs_iget.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iget.c  2011-06-22 11:16:25.111073882 +0200
+++ xfs/fs/xfs/xfs_iget.c       2011-06-22 11:33:21.501022423 +0200
@@ -93,7 +93,6 @@ xfs_inode_alloc(
        ip->i_afp = NULL;
        memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
        ip->i_flags = 0;
-       ip->i_update_core = 0;
        ip->i_delayed_blks = 0;
        memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
        ip->i_size = 0;
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-06-22 11:17:51.944402819 +0200
+++ xfs/fs/xfs/xfs_inode.c      2011-06-22 11:33:21.501022423 +0200
@@ -1906,7 +1906,6 @@ retry:
                        iip = ip->i_itemp;
                        if (!iip || xfs_inode_clean(ip)) {
                                ASSERT(ip != free_ip);
-                               ip->i_update_core = 0;
                                xfs_ifunlock(ip);
                                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                                continue;
@@ -2688,7 +2687,6 @@ xfs_iflush(
         * to disk, because the log record didn't make it to disk!
         */
        if (XFS_FORCED_SHUTDOWN(mp)) {
-               ip->i_update_core = 0;
                if (iip)
                        iip->ili_format.ilf_fields = 0;
                xfs_ifunlock(ip);
@@ -2768,26 +2766,6 @@ xfs_iflush_int(
        /* set *dip = inode's place in the buffer */
        dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
-       /*
-        * Clear i_update_core before copying out the data.
-        * This is for coordination with our timestamp updates
-        * that don't hold the inode lock. They will always
-        * update the timestamps BEFORE setting i_update_core,
-        * so if we clear i_update_core after they set it we
-        * are guaranteed to see their updates to the timestamps.
-        * I believe that this depends on strongly ordered memory
-        * semantics, but we have that.  We use the SYNCHRONIZE
-        * macro to make sure that the compiler does not reorder
-        * the i_update_core access below the data copy below.
-        */
-       ip->i_update_core = 0;
-       SYNCHRONIZE();
-
-       /*
-        * Make sure to get the latest timestamps from the Linux inode.
-        */
-       xfs_synchronize_times(ip);
-
        if (XFS_TEST_ERROR(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC,
                               mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
                xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
@@ -2946,8 +2924,7 @@ xfs_iflush_int(
        } else {
                /*
                 * We're flushing an inode which is not in the AIL and has
-                * not been logged but has i_update_core set.  For this
-                * case we can use a B_DELWRI flush and immediately drop
+                * not been logged.  For this case we can immediately drop
                 * the inode flush lock because we can avoid the whole
                 * AIL state thing.  It's OK to drop the flush lock now,
                 * because we've already locked the buffer and to do anything
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-06-22 11:16:25.141073882 +0200
+++ xfs/fs/xfs/xfs_inode.h      2011-06-22 11:33:21.501022423 +0200
@@ -250,7 +250,6 @@ typedef struct xfs_inode {
        spinlock_t              i_flags_lock;   /* inode i_flags lock */
        /* Miscellaneous state. */
        unsigned short          i_flags;        /* see defined flags below */
-       unsigned char           i_update_core;  /* timestamps/size is dirty */
        unsigned int            i_delayed_blks; /* count of delay alloc blks */
 
        xfs_icdinode_t          i_d;            /* most of ondisk inode */
@@ -491,10 +490,6 @@ int                xfs_iflush(xfs_inode_t *, uint);
 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) \
 do { \
        ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c    2011-06-22 11:16:25.151073881 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-06-22 11:33:21.504355756 +0200
@@ -256,42 +256,6 @@ xfs_inode_item_format(
        vecp++;
        nvecs        = 1;
 
-       /*
-        * Clear i_update_core if the timestamps (or any other
-        * non-transactional modification) need flushing/logging
-        * and we're about to log them with the rest of the core.
-        *
-        * This is the same logic as xfs_iflush() but this code can't
-        * run at the same time as xfs_iflush because we're in commit
-        * processing here and so we have the inode lock held in
-        * exclusive mode.  Although it doesn't really matter
-        * for the timestamps if both routines were to grab the
-        * timestamps or not.  That would be ok.
-        *
-        * We clear i_update_core before copying out the data.
-        * This is for coordination with our timestamp updates
-        * that don't hold the inode lock. They will always
-        * update the timestamps BEFORE setting i_update_core,
-        * so if we clear i_update_core after they set it we
-        * are guaranteed to see their updates to the timestamps
-        * either here.  Likewise, if they set it after we clear it
-        * here, we'll see it either on the next commit of this
-        * inode or the next time the inode gets flushed via
-        * xfs_iflush().  This depends on strongly ordered memory
-        * semantics, but we have that.  We use the SYNCHRONIZE
-        * macro to make sure that the compiler does not reorder
-        * the i_update_core access below the data copy below.
-        */
-       if (ip->i_update_core)  {
-               ip->i_update_core = 0;
-               SYNCHRONIZE();
-       }
-
-       /*
-        * Make sure to get the latest timestamps from the Linux inode.
-        */
-       xfs_synchronize_times(ip);
-
        vecp->i_addr = &ip->i_d;
        vecp->i_len  = sizeof(struct xfs_icdinode);
        vecp->i_type = XLOG_REG_TYPE_ICORE;
Index: xfs/fs/xfs/xfs_inode_item.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.h    2011-06-22 11:16:25.234407209 +0200
+++ xfs/fs/xfs/xfs_inode_item.h 2011-06-22 11:33:21.507689089 +0200
@@ -148,9 +148,8 @@ typedef struct xfs_inode_log_item {
 
 static inline int xfs_inode_clean(xfs_inode_t *ip)
 {
-       return (!ip->i_itemp ||
-               !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
-              !ip->i_update_core;
+       return !ip->i_itemp ||
+               !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL);
 }
 
 extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
Index: xfs/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_iops.c        2011-06-22 11:16:25.084407216 
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_iops.c     2011-06-22 11:33:21.507689089 +0200
@@ -51,50 +51,6 @@
 #include <linux/slab.h>
 
 /*
- * Bring the timestamps in the XFS inode uptodate.
- *
- * Used before writing the inode to disk.
- */
-void
-xfs_synchronize_times(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
-       ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
-       ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
-       ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
-       ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
-       ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
-}
-
-/*
- * If the linux inode is valid, mark it dirty.
- * Used when committing a dirty inode into a transaction so that
- * the inode will get written back by the linux code
- */
-void
-xfs_mark_inode_dirty_sync(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
-               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)))
-               mark_inode_dirty(inode);
-}
-
-/*
  * Hook in SELinux.  This is not quite correct yet, what we really need
  * here (as we do for default ACLs) is a mechanism by which creation of
  * these attrs can be journalled at inode creation time (along with the
@@ -669,19 +625,16 @@ xfs_setattr_nonsize(
                inode->i_atime = iattr->ia_atime;
                ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
                ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_CTIME) {
                inode->i_ctime = iattr->ia_ctime;
                ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
                ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_MTIME) {
                inode->i_mtime = iattr->ia_mtime;
                ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
                ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-               ip->i_update_core = 1;
        }
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -906,13 +859,11 @@ xfs_setattr_size(
                inode->i_ctime = iattr->ia_ctime;
                ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
                ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_MTIME) {
                inode->i_mtime = iattr->ia_mtime;
                ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
                ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-               ip->i_update_core = 1;
        }
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
Index: xfs/fs/xfs/linux-2.6/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/linux-2.6/xfs_trace.h       2011-06-22 11:16:25.097740550 
+0200
+++ xfs/fs/xfs/linux-2.6/xfs_trace.h    2011-06-22 11:33:21.511022422 +0200
@@ -579,7 +579,7 @@ DEFINE_INODE_EVENT(xfs_file_compat_ioctl
 DEFINE_INODE_EVENT(xfs_ioctl_setattr);
 DEFINE_INODE_EVENT(xfs_file_fsync);
 DEFINE_INODE_EVENT(xfs_destroy_inode);
-DEFINE_INODE_EVENT(xfs_write_inode);
+DEFINE_INODE_EVENT(xfs_dirty_inode);
 DEFINE_INODE_EVENT(xfs_evict_inode);
 
 DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
Index: xfs/fs/xfs/xfs_trans_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_inode.c   2011-06-22 13:53:13.157264222 +0200
+++ xfs/fs/xfs/xfs_trans_inode.c        2011-06-22 13:55:01.213925417 +0200
@@ -110,10 +110,14 @@ xfs_trans_ichgtime(
        if ((flags & XFS_ICHGTIME_MOD) &&
            !timespec_equal(&inode->i_mtime, &tv)) {
                inode->i_mtime = tv;
+               ip->i_d.di_mtime.t_sec = tv.tv_sec;
+               ip->i_d.di_mtime.t_nsec = tv.tv_nsec;
        }
        if ((flags & XFS_ICHGTIME_CHG) &&
            !timespec_equal(&inode->i_ctime, &tv)) {
                inode->i_ctime = tv;
+               ip->i_d.di_ctime.t_sec = tv.tv_sec;
+               ip->i_d.di_ctime.t_nsec = tv.tv_nsec;
        }
 }
 
Index: xfs/fs/xfs/xfs_itable.c
===================================================================
--- xfs.orig/fs/xfs/xfs_itable.c        2011-06-22 13:56:49.090586622 +0200
+++ xfs/fs/xfs/xfs_itable.c     2011-06-22 13:59:00.593913297 +0200
@@ -62,7 +62,6 @@ xfs_bulkstat_one_int(
 {
        struct xfs_icdinode     *dic;           /* dinode core info pointer */
        struct xfs_inode        *ip;            /* incore inode pointer */
-       struct inode            *inode;
        struct xfs_bstat        *buf;           /* return buffer */
        int                     error = 0;      /* error value */
 
@@ -86,7 +85,6 @@ xfs_bulkstat_one_int(
        ASSERT(ip->i_imap.im_blkno != 0);
 
        dic = &ip->i_d;
-       inode = VFS_I(ip);
 
        /* xfs_iget returns the following without needing
         * further change.
@@ -99,19 +97,12 @@ xfs_bulkstat_one_int(
        buf->bs_uid = dic->di_uid;
        buf->bs_gid = dic->di_gid;
        buf->bs_size = dic->di_size;
-
-       /*
-        * We need to read the timestamps from the Linux inode because
-        * the VFS keeps writing directly into the inode structure instead
-        * of telling us about the updates.
-        */
-       buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
-       buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
-       buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
-       buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
-       buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
-       buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
-
+       buf->bs_atime.tv_sec = dic->di_atime.t_sec;
+       buf->bs_atime.tv_nsec = dic->di_atime.t_nsec;
+       buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
+       buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
+       buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
+       buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
        buf->bs_xflags = xfs_ip2xflags(ip);
        buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
        buf->bs_extents = dic->di_nextents;

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