|
@@ -863,91 +863,58 @@ 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.
|
|
|
+ * This is called by the VFS when dirtying inode metadata. This can happen
|
|
|
+ * for a few reasons, but we only care about timestamp updates, given that
|
|
|
+ * we handled the rest ourselves. In theory no other calls should happen,
|
|
|
+ * but for example generic_write_end() keeps dirtying the inode after
|
|
|
+ * updating i_size. Thus we check that the flags are exactly I_DIRTY_SYNC,
|
|
|
+ * and skip this call otherwise.
|
|
|
*
|
|
|
- * 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.
|
|
|
+ * We'll hopefull get a different method just for updating timestamps soon,
|
|
|
+ * at which point this hack can go away, and maybe we'll also get real
|
|
|
+ * error handling here.
|
|
|
*/
|
|
|
STATIC void
|
|
|
xfs_fs_dirty_inode(
|
|
|
- struct inode *inode,
|
|
|
- int flags)
|
|
|
-{
|
|
|
- barrier();
|
|
|
- XFS_I(inode)->i_update_core = 1;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-xfs_fs_write_inode(
|
|
|
struct inode *inode,
|
|
|
- struct writeback_control *wbc)
|
|
|
+ int flags)
|
|
|
{
|
|
|
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 || wbc->for_kupdate) {
|
|
|
- /*
|
|
|
- * 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 forces dramatically.
|
|
|
- */
|
|
|
- error = xfs_log_dirty_inode(ip, NULL, 0);
|
|
|
- if (error)
|
|
|
- goto out;
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- if (!ip->i_update_core)
|
|
|
- return 0;
|
|
|
+ struct xfs_trans *tp;
|
|
|
+ int error;
|
|
|
|
|
|
- /*
|
|
|
- * 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 (flags != I_DIRTY_SYNC)
|
|
|
+ return;
|
|
|
|
|
|
- if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
|
|
|
- goto out_unlock;
|
|
|
+ trace_xfs_dirty_inode(ip);
|
|
|
|
|
|
- /*
|
|
|
- * 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);
|
|
|
+ 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);
|
|
|
+ goto trouble;
|
|
|
}
|
|
|
-
|
|
|
- out_unlock:
|
|
|
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
|
- out:
|
|
|
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
/*
|
|
|
- * if we failed to write out the inode then mark
|
|
|
- * it dirty again so we'll try again later.
|
|
|
+ * Grab all 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_ILOCK_EXCL);
|
|
|
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
+ error = xfs_trans_commit(tp, 0);
|
|
|
if (error)
|
|
|
- xfs_mark_inode_dirty_sync(ip);
|
|
|
- return -error;
|
|
|
+ goto trouble;
|
|
|
+ return;
|
|
|
+
|
|
|
+trouble:
|
|
|
+ xfs_warn(mp, "failed to update timestamps for inode 0x%llx", ip->i_ino);
|
|
|
}
|
|
|
|
|
|
STATIC void
|
|
@@ -1466,7 +1433,6 @@ 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,
|
|
|
.evict_inode = xfs_fs_evict_inode,
|
|
|
.put_super = xfs_fs_put_super,
|
|
|
.sync_fs = xfs_fs_sync_fs,
|