xfs: avoid synchronous transaction in xfs_fs_write_inode
PATCH 1/1 xfs: avoid synchronous transaction in xfs_fs_write_inode
We already rely on the fact that the sync code will cause a synchronous log force later on (currently via xfs_fs_sync_fs -> xfs_quiesce_data -> xfs_sync_data), so no need to do this here. This allows us to avoid a lot of synchronous log forces during sync, which pays of especially
with delayed logging enabled. Some compilebench numbers that show
this:
xfs (delayed logging, 256k logbufs)
===================================
intial create 25.94 MB/s 25.75 MB/s 25.64 MB/s
create 8.54 MB/s 9.12 MB/s 9.15 MB/s
patch 2.47 MB/s 2.47 MB/s 3.17 MB/s
compile 29.65 MB/s 30.51 MB/s 27.33 MB/s
clean 90.92 MB/s 98.83 MB/s 128.87 MB/s
read tree 11.90 MB/s 11.84 MB/s 8.56 MB/s
read compiled 28.75 MB/s 29.96 MB/s 24.25 MB/s
delete tree 8.39 seconds 8.12 seconds 8.46 seconds
delete compiled 8.35 seconds 8.44 seconds 5.11 seconds
stat tree 6.03 seconds 5.59 seconds 5.19 seconds
stat compiled tree 9.00 seconds 9.52 seconds 8.49 seconds
xfs + write_inode log_force removal
===================================
intial create 25.87 MB/s 25.76 MB/s 25.87 MB/s
create 15.18 MB/s 14.80 MB/s 14.94 MB/s patch 3.13 MB/s 3.14 MB/s 3.11 MB/s
compile 36.74 MB/s 37.17 MB/s 36.84 MB/s
clean 226.02 MB/s 222.58 MB/s 217.94 MB/s
read tree 15.14 MB/s 15.02 MB/s 15.14 MB/s
read compiled tree 29.30 MB/s 29.31 MB/s 29.32 MB/s
delete tree 6.22 seconds 6.14 seconds 6.15 seconds
delete compiled tree 5.75 seconds 5.92 seconds 5.81 seconds
stat tree 4.60 seconds 4.51 seconds 4.56 seconds
stat compiled tree 4.07 seconds 3.87 seconds 3.96 seconds
fs/xfs/linux-2.6/xfs_super.c +6 -1
@@ -1025,7 +1025,6 @@ xfs_log_inode(*/ 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 );xfs_ilock_demote (ip,XFS_ILOCK_EXCL );
@@ -1052,6 +1051,12 @@ xfs_fs_write_inode(* log and the fsync transactions we reduce the IOs we have * to do here from two (log and inode) to just the log. * +* We do not even have to use a log force / synchronous +* transaction here as the sync code will cause do +* synchronous log force later durinc the sync process. +* With delayed logging that means we reduce the amount +* of required I/O requests dramatically. +* * Note: We still need to do a delwri write of the inode after * this to flush it to the backing buffer so that bulkstat * works properly if this is the first time the inode has been
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 38 lines · Christoph Hellwig
We already rely on the fact that the sync code will cause a synchronous log force later on (currently via
xfs_fs_sync_fs->xfs_quiesce_data->xfs_sync_data), so no need to do this here. This allows us to avoid a lot of synchronous log forces during sync, which pays of especially
with delayed logging enabled. Some compilebench numbers that show
this:xfs (delayed logging, 256k logbufs)
===================================intial create 25.94 MB/s 25.75 MB/s 25.64 MB/s
create 8.54 MB/s 9.12 MB/s 9.15 MB/s
patch 2.47 MB/s 2.47 MB/s 3.17 MB/s
compile 29.65 MB/s 30.51 MB/s 27.33 MB/s
clean 90.92 MB/s 98.83 MB/s 128.87 MB/s
read tree 11.90 MB/s 11.84 MB/s 8.56 MB/s
read compiled 28.75 MB/s 29.96 MB/s 24.25 MB/s
delete tree 8.39 seconds 8.12 seconds 8.46 seconds
delete compiled 8.35 seconds 8.44 seconds 5.11 seconds
stat tree 6.03 seconds 5.59 seconds 5.19 seconds
stat compiled tree 9.00 seconds 9.52 seconds 8.49 secondsxfs +
write_inodelog_forceremoval
===================================
intial create 25.87 MB/s 25.76 MB/s 25.87 MB/screate 15.18 MB/s 14.80 MB/s 14.94 MB/s patch 3.13 MB/s 3.14 MB/s 3.11 MB/scompile 36.74 MB/s 37.17 MB/s 36.84 MB/s
clean 226.02 MB/s 222.58 MB/s 217.94 MB/s
read tree 15.14 MB/s 15.02 MB/s 15.14 MB/s
read compiled tree 29.30 MB/s 29.31 MB/s 29.32 MB/s
delete tree 6.22 seconds 6.14 seconds 6.15 seconds
delete compiled tree 5.75 seconds 5.92 seconds 5.81 seconds
stat tree 4.60 seconds 4.51 seconds 4.56 seconds
stat compiled tree 4.07 seconds 3.87 seconds 3.96 seconds
Quoted 1 line
Signed-off-by Christoph Hellwig <[email protected]>
All great - I attempted this myself - but it breaks bulkstat. See xfstest 183:
183 2s ... - output mismatch (see 183.out.bad)
183.out.bad 2010-06-09 17:10:23.000000000 +1000 renamed from 183.out 2010-04-28 15:00:22.000000000 +1000 +1 -1
@@ -1,4 +1,4 @@ QA output created by 183 Start original bulkstat_unlink_test with -r switch Runing extended checks. -Iteration 0 ... (100 files)passed +Iteration 0 ... (100 files)ERROR, count(2) != scount(1).
Ran: 183
Failures: 183
Failed 1 of 1 tests
Test 183 fails with this patch because it leaves the inode pinned in the WB_SYNC_ALL case after calling xfs_log_inode(), and so the inode can't be flushed to the backing buffer. Hence bulkstat may not see changes to an inode after a sync becuase they weren't flushed during the sync.
I think that we need to revisit bulkstat's use of the backing buffers for performance reasons now we have a much more scalable inode cache. Having to keep the backing buffers coherent is only going to be more problematic in future as things get even more asynchronous....
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 2 lines · Dave Chinner
All great - I attempted this myself - but it breaks bulkstat. See xfstest 183:
I can't reproduce the failure. And then I don't think we should prioritize bulkstate over metadata performance. The only major users of bulkstat on XFS in the mainline kernel is xfsdump, and metadata performance during normal loads is a lot more important. And the difference when using LVM/MD will be even larger with this as barriers are a lot more expensive there.
What do you think about adding something like the patch below which always makes bulkstat always use the iget version which doesn't show this sort of problems.
---
From: Christoph Hellwig <[email protected]>
Subject: xfs: always use iget in bulkstat
The non-coherent bulkstat versionsthat look directly at the inode buffers causes various problems with performance optimizations that make increased use of just logging inodes. This patch makes bulkstat always use iget, which should be fast enough for normal use with the radix-tree based inode cache introduced a while ago.
---
linux-2.6/xfs_ioctl.c | 7 - linux-2.6/xfs_ioctl32.c | 12 -- quota/xfs_qm.c | 11 - quota/xfs_qm_syscalls.c | 16 +- xfs_itable.c | 281 ++++++------------------------------------------ xfs_itable.h | 14 -- 6 files changed, 59 insertions(+), 282 deletions(-)
fs/xfs/linux-2.6/xfs_ioctl.c +3 -4
@@ -670,10 +670,9 @@ xfs_ioc_bulkstat( error =xfs_bulkstat_single (mp, &inlast, bulkreq.ubuffer, &done); else /* XFS_IOC_FSBULKSTAT */ - error =xfs_bulkstat (mp, &inlast, &count, - (bulkstat_one_pf )xfs_bulkstat_one,NULL , -sizeof (xfs_bstat_t), bulkreq.ubuffer, -BULKSTAT_FG_QUICK , &done); + error =xfs_bulkstat (mp, &inlast, &count, xfs_bulkstat_one, +sizeof (xfs_bstat_t), bulkreq.ubuffer, + &done);if (error)return -error;
fs/xfs/linux-2.6/xfs_ioctl32.c +4 -8
@@ -233,15 +233,13 @@ xfs_bulkstat_one_compat(xfs_ino_t ino,/* inode number to get data for */ void __user *buffer, /* buffer to place output in */ int ubsize, /* size of buffer */ - void *private_data, /* my private data */ xfs_daddr_t bno, /* starting bno of inode cluster */ int *ubused, /* bytes used by me */ - void *dibuff, /* on-disk inode buffer */ int *stat) /* BULKSTAT_RV_... */ { return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,xfs_bulkstat_one_fmt_compat ,bno , -ubused ,dibuff ,stat ); +ubused ,stat ); }/* copied from xfs_ioctl.c */
@@ -294,13 +292,11 @@ xfs_compat_ioc_bulkstat(int res; error =xfs_bulkstat_one_compat (mp, inlast, bulkreq.ubuffer, -sizeof (compat_xfs_bstat_t), -NULL ,0 ,NULL ,NULL , &res); +sizeof (compat_xfs_bstat_t),0 ,NULL , &res); }else if (cmd ==XFS_IOC_FSBULKSTAT_32 ) { error =xfs_bulkstat (mp, &inlast, &count, - xfs_bulkstat_one_compat,NULL , -sizeof (compat_xfs_bstat_t), bulkreq.ubuffer, -BULKSTAT_FG_QUICK , &done); + xfs_bulkstat_one_compat,sizeof (compat_xfs_bstat_t), + bulkreq.ubuffer, &done); }else error =XFS_ERROR (EINVAL );if (error)
fs/xfs/quota/xfs_qm.c +5 -6
@@ -1625,10 +1625,8 @@ xfs_qm_dqusage_adjust(xfs_ino_t ino,/* inode number to get data for */ void __user *buffer, /* not used */ int ubsize, /* not used */ - void *private_data, /* not used */ xfs_daddr_t bno, /* starting block of inode cluster */ int *ubused, /* not used */ - void *dip, /* on-disk inode pointer (not used) */ int *res) /* result code value */ { xfs_inode_t *ip;
@@ -1789,12 +1787,13 @@ xfs_qm_quotacheck(* Iterate thru all the inodes in the file system, * adjusting the corresponding dquot counters in core. */ -if ((error =xfs_bulkstat (mp, &lastino, &count, - xfs_qm_dqusage_adjust,NULL , - structsz,NULL ,BULKSTAT_FG_IGET , &done))) + error =xfs_bulkstat (mp, &lastino, &count, + xfs_qm_dqusage_adjust, + structsz,NULL , &done); +if (error)break ; - }while (! done); + }while (!done);/* * We've made all the changes that we need to make incore.
fs/xfs/quota/xfs_qm_syscalls.c +7 -9
@@ -1095,10 +1095,8 @@ xfs_qm_internalqcheck_adjust(xfs_ino_t ino,/* inode number to get data for */ void __user *buffer, /* not used */ int ubsize, /* not used */ - void *private_data, /* not used */ xfs_daddr_t bno, /* starting block of inode cluster */ int *ubused, /* not used */ - void *dip, /* not used */ int *res) /* bulkstat result code */ { xfs_inode_t *ip;
@@ -1191,15 +1189,15 @@ xfs_qm_internalqcheck(* Iterate thru all the inodes in the file system, * adjusting the corresponding dquot counters */ -if ((error =xfs_bulkstat (mp, &lastino, &count, - xfs_qm_internalqcheck_adjust,NULL , -0 ,NULL ,BULKSTAT_FG_IGET , &done))) { + error =xfs_bulkstat (mp, &lastino, &count, + xfs_qm_internalqcheck_adjust, +0 ,NULL , &done); +if (error) { +cmn_err (CE_DEBUG ,"Bulkstat returned error 0x%x" , error);break ; } - }while (! done); -if (error) { -cmn_err (CE_DEBUG ,"Bulkstat returned error 0x%x" , error); - } + }while (!done); +cmn_err (CE_DEBUG ,"Checking results against system dquots" );for (i =0 ; i < qmtest_hashmask; i++) {xfs_dqtest_t *d, *n;
fs/xfs/xfs_itable.c +40 -241
370 lines not on this page · raw message
fs/xfs/xfs_itable.h +0 -14
@@ -27,10 +27,8 @@ typedef int (*bulkstat_one_pf)(struct xfxfs_ino_t ino, void __user *buffer, int ubsize, - void *private_data, xfs_daddr_t bno, int *ubused, - void *dip, int *stat);/*
@@ -41,13 +39,6 @@ typedef int (*bulkstat_one_pf)(struct xf#define BULKSTAT_RV_GIVEUP 2/* -* Values for bulkstat flag argument. -*/ -#define BULKSTAT_FG_IGET 0x1/* Go through the buffer cache */ -#define BULKSTAT_FG_QUICK 0x2/* No iget, walk the dinode cluster */ -#define BULKSTAT_FG_INLINE 0x4/* No iget if inline attrs */ - -/* * Return stat information in bulk (by-inode) for the filesystem. */ int /* error status */
@@ -56,10 +47,8 @@ xfs_bulkstat( xfs_ino_t *lastino,/* last inode returned */ int *count,/* size of buffer/count returned */ bulkstat_one_pf formatter, /* func that'd fill a single buf */ - void *private_data,/* private data for formatter */ size_t statstruct_size,/* sizeof struct that we're filling */ char__user *ubuffer,/* buffer with inode stats */ - int flags, /* flag to control access method */ int *done); /* 1 if there are more stats to get */int
@@ -84,7 +73,6 @@ xfs_bulkstat_one_int(bulkstat_one_fmt_pf formatter, xfs_daddr_t bno, int *ubused, - void *dibuff, int *stat);int
@@ -93,10 +81,8 @@ xfs_bulkstat_one(xfs_ino_t ino, void __user *buffer, int ubsize, - void *private_data, xfs_daddr_t bno, int *ubused, - void *dibuff, int *stat); typedef int (*inumbers_fmt_pf)(
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 11 lines · Christoph Hellwig
Quoted 2 lines · Dave Chinner
All great - I attempted this myself - but it breaks bulkstat. See xfstest 183:
I can't reproduce the failure. And then I don't think we should prioritize bulkstate over metadata performance. The only major users of bulkstat on XFS in the mainline kernel is xfsdump, and metadata performance during normal loads is a lot more important. And the difference when using LVM/MD will be even larger with this as barriers are a lot more expensive there.
Quoted 3 lines
What do you think about adding something like the patch below which always makes bulkstat always use the iget version which doesn't show this sort of problems.
<snip patch>
The big advantage of the non-coherent bulkstat (apart from the order of magnitude performance increase it afforded) is that it doesn't cause the inode cache to grow and cause memory pressure.
I was thinking that what I'd like a coherent bulkstat to do is if it causes a cache miss immediately mark the inode as reclaimable so that it gets turfed back out of the cache within a few seconds of bulkstat using it. This will keep the cache growth under control, and keep the speed of cache lookups fairly consistent. It also means we don't need to set up the VFS side of the inode, as this will be done anyway if we get a cache hit on a normal lookup of a reclaimable inode. If we convert back to coherent bulkstat, at minimum I'd like to make this change during the conversion to keep the per-inode CPU overhead at a minimum.
The other thing I was thinking is a "bulk inode read" where we insert the entire cluster of inodes into the cache in a single operation. that way we don't have to keep calling the inode read code on every cache miss. With the above "insert as reclaimable inodes" it would significantly reduce the CPU overhead of populating the cache just for bulkstat. With this being done by a prefetch thread or two, we can leave the ioctl thread simply doing cache lookups and formatting....
The big question is what the SGI guys think of this - removing the non-cohenerent modes that are there for optimising specific DMF operations that are otherwise rather costly (i.e. BULKSTAT_FG_INLINE replaces bulkstat/open-by-handle/read xattr/close) and cause cache pollution. Are there ways to do this with coherent bulkstats?
However, this raises the same issue with the removal of the remaining DMAPI hooks (that Alex wants more discussion on), so to me the big question is now this: how much of the XFS code that is there specifically for supporting SGI's proprietry applications should be maintained in mainline given that SGI already supports and maintains a separate XFS tree with the significant additional functionality necessary for those applications that is not in mainline....
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 20 lines · Christoph Hellwig
Quoted 2 lines · Dave Chinner
All great - I attempted this myself - but it breaks bulkstat. See xfstest 183:
I can't reproduce the failure. And then I don't think we should prioritize bulkstate over metadata performance. The only major users of bulkstat on XFS in the mainline kernel is xfsdump, and metadata performance during normal loads is a lot more important. And the difference when using LVM/MD will be even larger with this as barriers are a lot more expensive there.
What do you think about adding something like the patch below which always makes bulkstat always use the iget version which doesn't show this sort of problems.
---
From: Christoph Hellwig <[email protected]>
Subject: xfs: always use iget in bulkstat
Quoted 7 lines
The non-coherent bulkstat versionsthat look directly at the inode buffers causes various problems with performance optimizations that make increased use of just logging inodes. This patch makes bulkstat always use iget, which should be fast enough for normal use with the radix-tree based inode cache introduced a while ago.
Signed-off-by Christoph Hellwig <[email protected]>
An important note: I think this patch is necessary to avoid bulkstat returning unlinked inodes when cache thrashing is occurring. The current non-coherent lookup will incorrectly return unlinked inodes if the inode cluster is marked stale, reclaimed and turfed from memory due to an unlink and memory pressure between the ialloc btree lookup and the cluster buffer read.
The only way to avoid this is to ensure that the ialloc btree lookup and the formatting of the inode into the user buffer is atomic, which means we have to do a coherent lookup that returns a locked into....
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs