iomap: Use FUA for pure data O_DSYNC DIO writes
Subsystems (3)
RFC PATCH 1/1 iomap: Use FUA for pure data O_DSYNC DIO writes
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
We know from teh IOMAP_F_DIRTY flag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.
Hence if we have been returned a mapped extent that is not new and the IO mapping is not dirty, then we can use a FUA write to provide datasync semantics. This allows us to short-cut the generic_write_sync() call in IO completion and hence avoid unnecessary operations. This makes pure direct IO data write behaviour identical to the way block devices use REQ_FUA to provide datasync semantics.
Now that iomap_dio_rw() is determining if REQ_FUA can be used, we have to stop issuing generic_write_sync() calls from the XFS code when REQ_FUA is issued, otherwise it will still throw a cache flush to the device via xfs_file_fsync(). To do this, we need to make iomap_dio_rw() always responsible for issuing generic_write_sync() when necessary, not just for AIO calls. This means the filesystem doesn't have to guess when cache flushes are necessary now.
On a FUA enabled device, a synchronous direct IO write workload (sequential 4k overwrites in 32MB file) had the following results:
# xfs_io -fd -c "pwrite -V 1 -D 0 32m" /mnt/scratch/boo
kernel time write()s write iops Write b/w
------ ---- -------- ---------- ---------
(no dsync) 4s 2173/s 2173 8.5MB/s
vanilla 22s 370/s 750 1.4MB/s
patched 19s 420/s 420 1.6MB/s
The patched code clearly doesn't send cache flushes anymore, but instead uses FUA (confirmed via blktrace), and performance improves a bit as a result. However, the benefits will be higher on workloads that mix O_DSYNC overwrites with other write IO as we won't be flushing the entire device cache on every DSYNC overwrite IO anymore.
--- fs/iomap.c | 38 +++++++++++++++++++++++++++++++++----- fs/xfs/xfs_file.c | 5 +++++ 2 files changed, 38 insertions(+), 5 deletions(-)
fs/iomap.c +33 -5
@@ -685,6 +685,7 @@ EXPORT_SYMBOL_GPL(iomap_seek_data);* Private flags for iomap_dio, must not overlap with the public ones in * iomap.h: */ +#define IOMAP_DIO_WRITE_FUA (1 << 29)#define IOMAP_DIO_WRITE (1 << 30)#define IOMAP_DIO_DIRTY (1 << 31)
@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio); +/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);return ret; }
@@ -769,12 +781,9 @@ static void iomap_dio_complete_work(struct work_struct *work) { struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);struct kiocb *iocb = dio->iocb; -bool is_write = (dio->flags &IOMAP_DIO_WRITE );ssize_t ret; ret =iomap_dio_complete (dio); -if (is_write && ret >0 ) - ret =generic_write_sync (iocb, ret); iocb->ki_complete (iocb, ret,0 ); }
@@ -883,6 +892,15 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, dio->flags |=IOMAP_DIO_COW ;if (iomap->flags &IOMAP_F_NEW ) need_zeroout = true; +/* +* Use a FUA write if we need datasync semantics and this is a +* pure data IO that doesn't require any metadata updates. This +* allows us to avoid cache flushes on IO completion. +*/ +else if (!(iomap->flags & (IOMAP_F_SHARED |IOMAP_F_DIRTY )) && + (dio->flags &IOMAP_DIO_WRITE ) && + (dio->iocb->ki_flags &IOCB_DSYNC )) + dio->flags |=IOMAP_DIO_WRITE_FUA ;break ;default :WARN_ON_ONCE (1 );
@@ -930,7 +948,11 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, n = bio->bi_iter.bi_size;if (dio->flags &IOMAP_DIO_WRITE ) { -bio_set_op_attrs (bio,REQ_OP_WRITE ,REQ_SYNC |REQ_IDLE ); +int op_flags =REQ_SYNC |REQ_IDLE ; + +if (dio->flags &IOMAP_DIO_WRITE_FUA ) + op_flags |=REQ_FUA ; +bio_set_op_attrs (bio,REQ_OP_WRITE , op_flags);task_io_account_write (n); }else {bio_set_op_attrs (bio,REQ_OP_READ ,0 );
@@ -961,6 +983,12 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,return copied; } +/* +* iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO +* is being issued as AIO or not. This allows us to optimise pure data writes to +* use REQ_FUA rather than requiring generic_write_sync() to issue a REQ_FLUSH +* post write. +*/ ssize_t iomap_dio_rw (struct kiocb *iocb,struct iov_iter *iter,const struct iomap_ops *ops,iomap_dio_end_io_t end_io)
fs/xfs/xfs_file.c +5 -0
@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);
Signature · 1 line
2.16.1
Quoted 11 lines · Dave Chinner
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
We know from teh
IOMAP_F_DIRTYflag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct
^^^^ modification
Quoted 56 lines
IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.
Hence if we have been returned a mapped extent that is not new and the IO mapping is not dirty, then we can use a FUA write to provide datasync semantics. This allows us to short-cut the
generic_write_sync()call in IO completion and hence avoid unnecessary operations. This makes pure direct IO data write behaviour identical to the way block devices useREQ_FUAto provide datasync semantics.Now that
iomap_dio_rw()is determining ifREQ_FUAcan be used, we have to stop issuinggeneric_write_sync()calls from the XFS code whenREQ_FUAis issued, otherwise it will still throw a cache flush to the device viaxfs_file_fsync(). To do this, we need to makeiomap_dio_rw()always responsible for issuinggeneric_write_sync()when necessary, not just for AIO calls. This means the filesystem doesn't have to guess when cache flushes are necessary now.On a FUA enabled device, a synchronous direct IO write workload (sequential 4k overwrites in 32MB file) had the following results:
# xfs_io -fd -c "pwrite -V 1 -D 0 32m" /mnt/scratch/bookernel time write()s write iops Write b/w
------ ---- -------- ---------- ---------
(no dsync) 4s 2173/s 2173 8.5MB/s
vanilla 22s 370/s 750 1.4MB/s
patched 19s 420/s 420 1.6MB/sThe patched code clearly doesn't send cache flushes anymore, but instead uses FUA (confirmed via blktrace), and performance improves a bit as a result. However, the benefits will be higher on workloads that mix
O_DSYNCoverwrites with other write IO as we won't be flushing the entire device cache on every DSYNC overwrite IO anymore.Signed-off-by Dave Chinner <[email protected]>--- fs/iomap.c | 38 +++++++++++++++++++++++++++++++++----- fs/xfs/xfs_file.c | 5 +++++ 2 files changed, 38 insertions(+), 5 deletions(-)fs/iomap.c +1
-0@@ -685,6 +685,7 @@ EXPORT_SYMBOL_GPL(iomap_seek_data);* Private flags for iomap_dio, must not overlap with the public ones in * iomap.h: */ +#define IOMAP_DIO_WRITE_FUA (1 << 29)#define IOMAP_DIO_WRITE (1 << 30)#define IOMAP_DIO_DIRTY (1 << 31)
fs/iomap.c static ssize_t iomap_dio_complete(struct iomap_dio *dio) · line 767
Quoted 8 lines
fs/iomap.c +3
-1@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio); +/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete
Minor nit: space-dash-period.
Looks ok to me, but does anyone else have comments? (Looking at hch here. ;))
--D
Quoted 90 lines
fs/iomap.c +29
-4+* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);return ret; }@@ -769,12 +781,9 @@ static void iomap_dio_complete_work(struct work_struct *work) { struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);struct kiocb *iocb = dio->iocb; -bool is_write = (dio->flags &IOMAP_DIO_WRITE );ssize_t ret; ret =iomap_dio_complete (dio); -if (is_write && ret >0 ) - ret =generic_write_sync (iocb, ret); iocb->ki_complete (iocb, ret,0 ); }@@ -883,6 +892,15 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, dio->flags |=IOMAP_DIO_COW ;if (iomap->flags &IOMAP_F_NEW ) need_zeroout = true; +/* +* Use a FUA write if we need datasync semantics and this is a +* pure data IO that doesn't require any metadata updates. This +* allows us to avoid cache flushes on IO completion. +*/ +else if (!(iomap->flags & (IOMAP_F_SHARED |IOMAP_F_DIRTY )) && + (dio->flags &IOMAP_DIO_WRITE ) && + (dio->iocb->ki_flags &IOCB_DSYNC )) + dio->flags |=IOMAP_DIO_WRITE_FUA ;break ;default :WARN_ON_ONCE (1 );@@ -930,7 +948,11 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, n = bio->bi_iter.bi_size;if (dio->flags &IOMAP_DIO_WRITE ) { -bio_set_op_attrs (bio,REQ_OP_WRITE ,REQ_SYNC |REQ_IDLE ); +int op_flags =REQ_SYNC |REQ_IDLE ; + +if (dio->flags &IOMAP_DIO_WRITE_FUA ) + op_flags |=REQ_FUA ; +bio_set_op_attrs (bio,REQ_OP_WRITE , op_flags);task_io_account_write (n); }else {bio_set_op_attrs (bio,REQ_OP_READ ,0 );@@ -961,6 +983,12 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,return copied; } +/* +* iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO +* is being issued as AIO or not. This allows us to optimise pure data writes to +* use REQ_FUA rather than requiring generic_write_sync() to issue a REQ_FLUSH +* post write. +*/ ssize_t iomap_dio_rw (struct kiocb *iocb,struct iov_iter *iter,const struct iomap_ops *ops,iomap_dio_end_io_t end_io)fs/xfs/xfs_file.c +5
-0@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);Signature · 6 lines
2.16.1 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 8 lines
fs/iomap.c +2
-1@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio); +/* +* If a FUA write was done, then that is all we required for datasync
fs/iomap.c static ssize_t iomap_dio_complete(struct iomap_dio *dio) · line 776
Quoted 10 lines
fs/iomap.c +10
-0+* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);
Can please split the move of the generic_write_sync call into generic_write_sync a separate prep patch? It's enough of a logic change on its own that it warrants a separate commit with a separate explanation.
Also I'd be tempted to invert the IOMAP_DIO_WRITE_FUA flag and replace it with an IOMAP_DIO_WRITE_SYNC flag to indicate we need the generic_write_sync call, as that should make the logic much more clear.
Quoted 6 lines
fs/xfs/xfs_file.c +0
-0@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);
fs/xfs/xfs_file.c xfs_file_write_iter( · line 742
Quoted 10 lines
fs/xfs/xfs_file.c +5
-0if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);
The else is not needed and you can now have a much more sensible code flow here:
ret = xfs_file_dio_aio_write(iocb, from); if (ret != -EREMCHG)) return ret; } ret = xfs_file_buffered_aio_write(iocb, from);
Quoted 18 lines · Christoph Hellwig
Quoted 4 lines
fs/xfs/xfs_file.c +0
-0@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);fs/xfs/xfs_file.c xfs_file_write_iter( · line 742
Quoted 10 lines
fs/xfs/xfs_file.c +5
-0if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);The else is not needed and you can now have a much more sensible code flow here:
Quoted 6 lines
ret = xfs_file_dio_aio_write(iocb, from); if (ret != -EREMCHG)) return ret; } ret = xfs_file_buffered_aio_write(iocb, from);
Actually a little more complicated due to the DAX case, and the fact that both your original and this new version miss the XFS_STATS_ADD call. But you get the idea. While we're at it we should probably also skil the generic_write_sync call for DAX pure overwrites while we're at it.
Quoted 3 lines · Christoph Hellwig
While we're at it we should probably
also skil thegeneric_write_synccall for DAX pure overwrites while we're at it.
Now that I've looked at it, DAX is a friggin' mess.
We can't push the generic_write_sync() call into dax_iomap_rw() because dax_iomap_rw is called with the inode_lock() held, and both ext2's and ext4's ->fsync implementation can call __generic_file_fsync() which takes the inode_lock(). Deadlock central right there - someone is going to have to screw with ext4's indoe sync code to before we can do this.
Further, XFS has post-write metadata updates to do in the case of extending writes, and hence we'd still need the call to generic_write_sync() after we have returned from dax_iomap_rw(). I'm thinking we'd really need a dax write IO completion callback (say in the struct iomap_ops) to run the filesystem specific IO completions (like the DIO path) before we can start to think about optimisations like this for DAX for XFS....
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Oh well, lets skip DAX for now then. I still think moving the generic_write_sync call into xfs_file_dax_write/xfs_file_dio_aio_write/ xfs_file_buffered_aio_write functions would be a useful cleanup.
Quoted 22 lines · Dave Chinner
Quoted 3 lines · Christoph Hellwig
While we're at it we should probably
also skil thegeneric_write_synccall for DAX pure overwrites while we're at it.Now that I've looked at it, DAX is a friggin' mess.
We can't push the
generic_write_sync()call intodax_iomap_rw()becausedax_iomap_rwis called with theinode_lock()held, and both ext2's and ext4's ->fsync implementation can call__generic_file_fsync()which takes theinode_lock(). Deadlock central right there - someone is going to have to screw with ext4's indoe sync code to before we can do this.Further, XFS has post-write metadata updates to do in the case of extending writes, and hence we'd still need the call to
generic_write_sync()after we have returned fromdax_iomap_rw(). I'm thinking we'd really need a dax write IO completion callback (say in the structiomap_ops) to run the filesystem specific IO completions (like the DIO path) before we can start to think about optimisations like this for DAX for XFS....
Quoted 6 lines
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
---end quoted text---
Quoted 6 lines · Christoph Hellwig
Quoted 6 lines
fs/iomap.c +0
-1@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio);
Quoted 16 lines
fs/iomap.c static ssize_t iomap_dio_complete(struct iomap_dio *dio) · line 776
Quoted 12 lines
fs/iomap.c +12
-0+/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);Can please split the move of the
generic_write_synccall intogeneric_write_synca separate prep patch? It's enough of a logic change on its own that it warrants a separate commit with a separate explanation.
Ok, that makes sense.
Quoted 3 lines
Also I'd be tempted to invert the
IOMAP_DIO_WRITE_FUAflag and replace it with anIOMAP_DIO_WRITE_SYNCflag to indicate we need thegeneric_write_synccall, as that should make the logic much more clear.
Ah, much cleaner.
Quoted 20 lines
Quoted 6 lines
fs/xfs/xfs_file.c +0
-0@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);fs/xfs/xfs_file.c xfs_file_write_iter( · line 742
Quoted 10 lines
fs/xfs/xfs_file.c +5
-0if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);The else is not needed and you can now have a much more sensible code flow here:
Quoted 6 lines
ret = xfs_file_dio_aio_write(iocb, from); if (ret != -EREMCHG)) return ret; } ret = xfs_file_buffered_aio_write(iocb, from);
I thought about that, but as you noticed the DAX case gets in the way so I didn't bother for a RFC patch.
I'll have a look at making the DAX iomap code do something similar with generic_write_sync() so we can simplify this high level code.
Thanks Christoph!
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Quoted 5 lines · Dave Chinner
I thought about that, but as you noticed the DAX case gets in the way so I didn't bother for a RFC patch.
I'll have a look at making the DAX iomap code do something similar with
generic_write_sync()so we can simplify this high level code.
I suspect it might make sense to juse move generic_write_sync into each of the three write routines as a prep patch before the prep patch, which should clean everything up nicely.
Oh, and another thing: I think you want to make this new code dependent on the block devie actually supporting REQ_FUA natively. Otherwise you'll cause a flush for every emulated FUA write, which is only going make things worse, especially for ATA where FLUSH is not queued. And last time I check libata still disabled FUA by default.
Quoted 62 lines · Dave Chinner
Quoted 6 lines · Christoph Hellwig
Quoted 6 lines
fs/iomap.c +0
-1@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio);Quoted 16 lines
fs/iomap.c static ssize_t iomap_dio_complete(struct iomap_dio *dio) · line 776
Quoted 12 lines
fs/iomap.c +12
-0+/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);Can please split the move of the
generic_write_synccall intogeneric_write_synca separate prep patch? It's enough of a logic change on its own that it warrants a separate commit with a separate explanation.Ok, that makes sense.
Quoted 3 lines
Also I'd be tempted to invert the
IOMAP_DIO_WRITE_FUAflag and replace it with anIOMAP_DIO_WRITE_SYNCflag to indicate we need thegeneric_write_synccall, as that should make the logic much more clear.Ah, much cleaner.
Quoted 20 lines
Quoted 6 lines
fs/xfs/xfs_file.c +0
-0@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);fs/xfs/xfs_file.c xfs_file_write_iter( · line 742
Quoted 10 lines
fs/xfs/xfs_file.c +5
-0if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from);The else is not needed and you can now have a much more sensible code flow here:
Quoted 6 lines
ret = xfs_file_dio_aio_write(iocb, from); if (ret != -EREMCHG)) return ret; } ret = xfs_file_buffered_aio_write(iocb, from);I thought about that, but as you noticed the DAX case gets in the way so I didn't bother for a RFC patch.
Quoted 11 lines
I'll have a look at making the DAX iomap code do something similar with
generic_write_sync()so we can simplify this high level code.Thanks Christoph!
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
---end quoted text---
Quoted 5 lines · Christoph Hellwig
Oh, and another thing: I think you want to make this new code dependent on the block devie actually supporting
REQ_FUAnatively. Otherwise you'll cause a flush for every emulated FUA write, which is only going make things worse, especially for ATA where FLUSH is not queued. And last time I check libata still disabled FUA by default.
Yup, but the issue we have right now is that for pure RWF_DSYNC data overwrites we are already doing a post-flush on every IO. It's being issued as a separate zero-length IO, which is why REQ_FUA is faster and results in lower overall IOPS. The flush comes from this path:
generic_write_sync
vfs_fsync_range
xfs_file_fsync
....
/*
* If we only have a single device, and the log force about was
* a no-op we might have to flush the data device cache here.
* This can only happen for fdatasync/O_DSYNC if we were overwriting
* an already allocated file and thus do not have any metadata to
* commit.
*/
if (!log_flushed && !XFS_IS_REALTIME_INODE(ip) &&
mp->m_logdev_targp == mp->m_ddev_targp)
xfs_blkdev_issue_flush(mp->m_ddev_targp);So the end result of using REQ_FUA and not calling generic_write_sync() on devices that don't support REQ_FUA is that we get a post-flush attached to the IO rather than separately issuing the post-flush via generic_write_sync().
Hence I think we end up with the same behaviour on devices that don't support REQ_FUA, just via a slightly different mechanism.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Quoted 11 lines · Dave Chinner
Quoted 5 lines · Christoph Hellwig
Oh, and another thing: I think you want to make this new code dependent on the block devie actually supporting
REQ_FUAnatively. Otherwise you'll cause a flush for every emulated FUA write, which is only going make things worse, especially for ATA where FLUSH is not queued. And last time I check libata still disabled FUA by default.Yup, but the issue we have right now is that for pure
RWF_DSYNCdata overwrites we are already doing a post-flush on every IO. It's being issued as a separate zero-length IO, which is whyREQ_FUAis faster and results in lower overall IOPS. The flush comes from this path:
That is only the case if your device actually supports FUA. If the device does notit is emulated by the block/flk-flush.c code by issuing a FLUSH once the write has returned.
So for e.g. a direct I/O write() call with O_DSYNC that turns into e.g. four write calls on the wire you currently have:
WRITE
WRITE
WRITE
WRITE
FLUSH
with your patch and a device that supports FUA you get
WRITE (FUA)
WRITE (FUA)
WRITE (FUA)
WRITE (FUA)
but with a device that does not support FUA you get
WRITE
FLUSH
WRITE
FLUSH
WRITE
FLUSH
WRITE
FLUSH
with the additional pain point that on ATA FLUSH is not a queueable command, so it will have to wait for the completion of every other non-related command first, and no other command can be started.
So we should absolutely use your new approach IFF the device actually supports FUA (aka QUEUE_FLAG_FUA is set), but it will not help much or even be harmful if the device does not actually support the FUA bit.
[ adding Robert who had a question about this patch, and Jan + Ted for the ext4 implications ]
I talked with Robert offline and he had some questions about this patch that belong on the mailing list.
Quoted 165 lines · Dave Chinner
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
We know from teh
IOMAP_F_DIRTYflag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.Hence if we have been returned a mapped extent that is not new and the IO mapping is not dirty, then we can use a FUA write to provide datasync semantics. This allows us to short-cut the
generic_write_sync()call in IO completion and hence avoid unnecessary operations. This makes pure direct IO data write behaviour identical to the way block devices useREQ_FUAto provide datasync semantics.Now that
iomap_dio_rw()is determining ifREQ_FUAcan be used, we have to stop issuinggeneric_write_sync()calls from the XFS code whenREQ_FUAis issued, otherwise it will still throw a cache flush to the device viaxfs_file_fsync(). To do this, we need to makeiomap_dio_rw()always responsible for issuinggeneric_write_sync()when necessary, not just for AIO calls. This means the filesystem doesn't have to guess when cache flushes are necessary now.On a FUA enabled device, a synchronous direct IO write workload (sequential 4k overwrites in 32MB file) had the following results:
# xfs_io -fd -c "pwrite -V 1 -D 0 32m" /mnt/scratch/bookernel time write()s write iops Write b/w ------ ---- -------- ---------- --------- (no dsync) 4s 2173/s 2173 8.5MB/s vanilla 22s 370/s 750 1.4MB/s patched 19s 420/s 420 1.6MB/sThe patched code clearly doesn't send cache flushes anymore, but instead uses FUA (confirmed via blktrace), and performance improves a bit as a result. However, the benefits will be higher on workloads that mix
O_DSYNCoverwrites with other write IO as we won't be flushing the entire device cache on every DSYNC overwrite IO anymore.Signed-off-by Dave Chinner <[email protected]>--- fs/iomap.c | 38 +++++++++++++++++++++++++++++++++----- fs/xfs/xfs_file.c | 5 +++++ 2 files changed, 38 insertions(+), 5 deletions(-)fs/iomap.c +33
-5@@ -685,6 +685,7 @@ EXPORT_SYMBOL_GPL(iomap_seek_data);* Private flags for iomap_dio, must not overlap with the public ones in * iomap.h: */ +#define IOMAP_DIO_WRITE_FUA (1 << 29)#define IOMAP_DIO_WRITE (1 << 30)#define IOMAP_DIO_DIRTY (1 << 31)@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio); +/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);return ret; }@@ -769,12 +781,9 @@ static void iomap_dio_complete_work(struct work_struct *work) { struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);struct kiocb *iocb = dio->iocb; -bool is_write = (dio->flags &IOMAP_DIO_WRITE );ssize_t ret; ret =iomap_dio_complete (dio); -if (is_write && ret >0 ) - ret =generic_write_sync (iocb, ret); iocb->ki_complete (iocb, ret,0 ); }@@ -883,6 +892,15 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, dio->flags |=IOMAP_DIO_COW ;if (iomap->flags &IOMAP_F_NEW ) need_zeroout = true; +/* +* Use a FUA write if we need datasync semantics and this is a +* pure data IO that doesn't require any metadata updates. This +* allows us to avoid cache flushes on IO completion. +*/ +else if (!(iomap->flags & (IOMAP_F_SHARED |IOMAP_F_DIRTY )) && + (dio->flags &IOMAP_DIO_WRITE ) && + (dio->iocb->ki_flags &IOCB_DSYNC )) + dio->flags |=IOMAP_DIO_WRITE_FUA ;break ;default :WARN_ON_ONCE (1 );@@ -930,7 +948,11 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, n = bio->bi_iter.bi_size;if (dio->flags &IOMAP_DIO_WRITE ) { -bio_set_op_attrs (bio,REQ_OP_WRITE ,REQ_SYNC |REQ_IDLE ); +int op_flags =REQ_SYNC |REQ_IDLE ; + +if (dio->flags &IOMAP_DIO_WRITE_FUA ) + op_flags |=REQ_FUA ; +bio_set_op_attrs (bio,REQ_OP_WRITE , op_flags);task_io_account_write (n); }else {bio_set_op_attrs (bio,REQ_OP_READ ,0 );@@ -961,6 +983,12 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,return copied; } +/* +* iomap_dio_rw() always completes O_[D]SYNC writes regardless of whether the IO +* is being issued as AIO or not. This allows us to optimise pure data writes to +* use REQ_FUA rather than requiring generic_write_sync() to issue a REQ_FLUSH +* post write. +*/ ssize_t iomap_dio_rw (struct kiocb *iocb,struct iov_iter *iter,const struct iomap_ops *ops,iomap_dio_end_io_t end_io)fs/xfs/xfs_file.c +5
-1@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from); --2.16.1
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hello all. I have a couple of follow-up questions around this effort, thanks you all for all your kind inputs, patience and knowledge transfer.
1. How does xfs or ext4 make sure a pattern of WS followed by FWS does not allow the write (WS) completion to be visible before the flush completes? I suspected the write was held in iomap_dio_complete_work but with the generic_write_sync change in the patch would a O_DSYNC write request to a DpoFua=0 block queue allow T2 to see the completion via io_getevents before T1 completed the actual flush?
2. How will my application be able to dynamically determine if xfs and ext4 have the performance enhancement for FUA or I need engage alternate methods to use fsync/fdatasync at strategic locations?
3. Are there any plans yet to optimize ext4 as well?
4. Before the patched code the xfs_file_write_iter would call generic_write_sync and that calls submit_io_wait. Does this hold the thread issuing the io_submit so it is unable to drive more async I/O?
P.S. I tested the xfs patch today and great results
______________________________________________________________
Stamp the file with all 0xCCs before I do the write timing, so each sector is used and metadata flushed. Throughput way up on my system.
O_DIRECT | O_DSYNC WFS 19.19 sec (getting FUA behavior)O_DIRECT WS 18.65 sec
-----Original Message-----
From: [email protected] <[email protected]> On Behalf Of Dan Williams
Sent: Monday, March 12, 2018 6:54 PM
To: Dave Chinner <[email protected]>
Cc: [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Robert Dorr <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
[ adding Robert who had a question about this patch, and Jan + Ted for the ext4 implications ]
I talked with Robert offline and he had some questions about this patch that belong on the mailing list.
Quoted 172 lines · Dave Chinner
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
We know from teh
IOMAP_F_DIRTYflag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.Hence if we have been returned a mapped extent that is not new and the IO mapping is not dirty, then we can use a FUA write to provide datasync semantics. This allows us to short-cut the
generic_write_sync()call in IO completion and hence avoid unnecessary operations. This makes pure direct IO data write behaviour identical to the way block devices useREQ_FUAto provide datasync semantics.Now that
iomap_dio_rw()is determining ifREQ_FUAcan be used, we have to stop issuinggeneric_write_sync()calls from the XFS code whenREQ_FUAis issued, otherwise it will still throw a cache flush to the device viaxfs_file_fsync(). To do this, we need to makeiomap_dio_rw()always responsible for issuinggeneric_write_sync()when necessary, not just for AIO calls. This means the filesystem doesn't have to guess when cache flushes are necessary now.On a FUA enabled device, a synchronous direct IO write workload (sequential 4k overwrites in 32MB file) had the following results:
# xfs_io -fd -c "pwrite -V 1 -D 0 32m" /mnt/scratch/bookernel time write()s write iops Write b/w ------ ---- -------- ---------- --------- (no dsync) 4s 2173/s 2173 8.5MB/s vanilla 22s 370/s 750 1.4MB/s patched 19s 420/s 420 1.6MB/sThe patched code clearly doesn't send cache flushes anymore, but instead uses FUA (confirmed via blktrace), and performance improves a bit as a result. However, the benefits will be higher on workloads that mix
O_DSYNCoverwrites with other write IO as we won't be flushing the entire device cache on every DSYNC overwrite IO anymore.Signed-off-by Dave Chinner <[email protected]>--- fs/iomap.c | 38 +++++++++++++++++++++++++++++++++----- fs/xfs/xfs_file.c | 5 +++++ 2 files changed, 38 insertions(+), 5 deletions(-)fs/iomap.c +27
-5@@ -685,6 +685,7 @@ EXPORT_SYMBOL_GPL(iomap_seek_data);* Private flags for iomap_dio, must not overlap with the public ones in * iomap.h: */ +#define IOMAP_DIO_WRITE_FUA (1 << 29)#define IOMAP_DIO_WRITE (1 << 30)#define IOMAP_DIO_DIRTY (1 << 31)@@ -760,8 +761,19 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio) }inode_dio_end (file_inode (iocb->ki_filp)); -kfree (dio); +/* +* If a FUA write was done, then that is all we required for datasync +* semantics -. we don't need to call generic_write_sync() to complete +* the write. +*/ +if (ret >0 && + (dio->flags & (IOMAP_DIO_WRITE |IOMAP_DIO_WRITE_FUA )) == +IOMAP_DIO_WRITE ) { + ret =generic_write_sync (iocb, ret); + } + +kfree (dio);return ret; }@@ -769,12 +781,9 @@ static void iomap_dio_complete_work(struct work_struct *work) { struct iomap_dio *dio = container_of(work, struct iomap_dio, aio.work);struct kiocb *iocb = dio->iocb; -bool is_write = (dio->flags &IOMAP_DIO_WRITE );ssize_t ret; ret =iomap_dio_complete (dio); -if (is_write && ret >0 ) - ret =generic_write_sync (iocb, ret); iocb->ki_complete (iocb, ret,0 ); }@@ -883,6 +892,15 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, dio->flags |=IOMAP_DIO_COW ;if (iomap->flags &IOMAP_F_NEW ) need_zeroout = true; +/* +* Use a FUA write if we need datasync semantics and this is a +* pure data IO that doesn't require any metadata updates. This +* allows us to avoid cache flushes on IO completion. +*/ +else if (!(iomap->flags & (IOMAP_F_SHARED |IOMAP_F_DIRTY )) && + (dio->flags &IOMAP_DIO_WRITE ) && + (dio->iocb->ki_flags &IOCB_DSYNC )) + dio->flags |=IOMAP_DIO_WRITE_FUA ;break ;default :WARN_ON_ONCE (1 );@@ -930,7 +948,11 @@ iomap_dio_actor(struct inode *inode, loff_t pos,loff_t length, n = bio->bi_iter.bi_size;if (dio->flags &IOMAP_DIO_WRITE ) { -bio_set_op_attrs (bio,REQ_OP_WRITE ,REQ_SYNC |REQ_IDLE ); +int op_flags =REQ_SYNC |REQ_IDLE ; + +if (dio->flags &IOMAP_DIO_WRITE_FUA ) + op_flags |=REQ_FUA ; +bio_set_op_attrs (bio,REQ_OP_WRITE , op_flags);task_io_account_write (n); }else {bio_set_op_attrs(bio, REQ_OP_READ, 0); @@ -961,6 +983,12 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, return copied;}
fs/iomap.c +9
-0+/* +* iomap_dio_rw() always completes O_[D]SYNC writes regardless of +whether the IO +* is being issued as AIO or not. This allows us to optimise pure +data writes to +* use REQ_FUA rather than requiring generic_write_sync() to issue a +REQ_FLUSH +* post write. +*/ ssize_t iomap_dio_rw (struct kiocb *iocb,struct iov_iter *iter, const struct iomap_ops *ops, iomap_dio_end_io_t
end_io) diff --gita/fs/xfs/xfs_file.cb/fs/xfs/xfs_file.cindex260ff5e5c264..81aa3b73471e100644fs/xfs/xfs_file.c +5
-1@@ -732,6 +732,11 @@ xfs_file_write_iter( ret =xfs_file_dio_aio_write (iocb, from);if (ret == -EREMCHG ) goto buffered; +/* +* Direct IO handles sync type writes internally on I/O +* completion. +*/ +return ret; }else { buffered: ret =xfs_file_buffered_aio_write (iocb, from); --2.16.1
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at
https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger.k
ernel.org%2Fmajordomo-info.html&data=04%7C01%7Crdorr%40microsoft.com%7 C70271d8bc9c84c12e87808d5887485e5%7C72f988bf86f141af91ab2d7cd011db47%7 C1%7C0%7C636564956441249840%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwifQ%3D%3D%7C-1&sdata=KqPTOI97YQxhrm%2 BFu3MpoFMIWieH2nkool4tzs5IJ0M%3D&reserved=0
Quoted 7 lines · Robert Dorr
Hello all. I have a couple of follow-up questions around this effort, thanks you all for all your kind inputs, patience and knowledge transfer.
1. How does xfs or ext4 make sure a pattern of WS followed by
FWS does not allow the write (WS) completion to be visible before the flush completes?
I'm not sure what you are asking here. You need to be more precise about what these IOs are, who dispatched them and what their dependencies are. Where exactly did that FWS (REQ_FLUSH) come from?
I think, though, you're asking questions about IO ordering at the wrong level - filesystems serialise and order IO, not the block layer. Hence what you see at the block layer is not necessary a reflection of the ordering the filesystem is doing.
(I've already explained this earlier today in a different thread:
https://marc.info/?l=linux-xfs&m=152091489100831&w=2)
That's why I ask about the operation causing a REQ_FLUSH to be issued to the storage device, as that cannot be directly issued from userspace. It will occur as a side effect of a data integrity operation the filesystem is asked to perform, but without knowing the relationship between the integrity operation and the write in question an answer cannot be given.
It may would be better to describe your IO ordering and integrity requirements at a higher level (e.g. the syscall layer), because then we know what you are trying to acheive rather that trying to understand your problem from context-less questions about "IO barriers" that don't actually exist...
Quoted 5 lines
I suspected the write was held in
iomap_dio_complete_workbut with thegeneric_write_syncchange in the patch would aO_DSYNCwrite request to a DpoFua=0 block queue allow T2 to see the completion viaio_geteventsbefore T1 completed the actual flush?
Yes, that can happen as concurrent data direct IO are not serialised against each other and will always race to completion without providing any ordering guarantees. IOWs, if you have an IO ordering dependency in your application, then that ordering dependency needs to be handled in the application.
Quoted 4 lines
2. How will my application be able to dynamically determine if
xfs and ext4 have the performance enhancement for FUA or I need engage alternate methods to use fsync/fdatasync at strategic locations?
You don't. The filesystem will provide the same integrity guarantees in either case - FUA is just a performance optimisation that will get used if your hardware supports it. Applications should not care what capabilities the storage hardawre has - the kernel should do what is fastest and most reliable for the underlying storage....
Quoted 1 line
3. Are there any plans yet to optimize ext4 as well?
Not from me.
Quoted 4 lines
4. Before the patched code the
xfs_file_write_iterwould callgeneric_write_syncand that callssubmit_io_wait. Does this hold the thread issuing theio_submitso it is unable to drive more async I/O?
No, -EIOCBQUEUED is returned to avoid blocking. AIO calls generic_write_sync() from the IO completion path via a worker thread so it's all done asynchronously.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Very helpful, allow me to provide some concrete scenarios. SQL Server has data and log files and we honor WAL to provide for proper crash recovery and durability of the database.
* http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/sqlIObasics.mspx * http://download.microsoft.com/download/4/f/8/4f8f2dc9-a9a7-4b68-98cb-163482c95e0b/SQLIOBasicsCh2.doc
---------------------------------------------------------------------------------------------
#1 Scenario - Write vs Flush and io_getevents Ordering
---------------------------------------------------------------------------------------------
If SQL Server opens data and log files with O_DIRECT | O_DSYNC
1. T1 - SQL Server issues io_submit (IOCB_CMD_WRITE) for data file Page
xfs_write_file_iter issues xfs_file_dio_aio_write (W1)
As you pointed out the return is -EIOCBQUEUED (from the block device direct I/O queue insert when !sync) so T1 can continue forward and would skip the generic_write_sync in xfs_write_file_iter
2. T2 - SQL Server is waiting on io_getevents for the I/O (W1) posted by T1 via the same async kernel I/O context
When the W1 is considered complete SQL Server can truncate/reuse our database log file. I need to validate that the kernel only returns from io_getevents for W1 processed by hardware before F1 was issued and completed, then SQL Server can safely truncate the database transaction log.
The code shows iomap_dio_complete_work that I expected to issue the REQ_PREFLUSH for the O_DSYNC based write and prevent the completion from getting to the io_getevents caller. The patch moved this to the iomap_dio_complete which I believe meets my needs.
I think the answer is the iomap* logic makes sure to issue generic_write_sync for O_DSYNC W1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventing io_getevents from processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.
---------------------------------------------------------------------------------------------
#2 Dynamic determination of performant FUA capabilities
---------------------------------------------------------------------------------------------
For SQL Server using O_DIRECT | O_DSYNC on current kernels is very performance impacting. Instead we enable a mode for SQL that opens O_DIRECT only and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.
Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with O_DIRECT | O_DSYNC when REQ_FUA can be properly used and open with O_DIRECT and leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)
-----Original Message-----
From: Dave Chinner <[email protected]>
Sent: Tuesday, March 13, 2018 12:11 AM
To: Robert Dorr <[email protected]>
Cc: Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
[This sender failed our fraud detection checks and may not be who they appear to be. Learn about spoofing at http://aka.ms/LearnAboutSpoofing]
Quoted 7 lines · Robert Dorr
Hello all. I have a couple of follow-up questions around this effort, thanks you all for all your kind inputs, patience and knowledge transfer.
1. How does xfs or ext4 make sure a pattern of WS followed by
FWS does not allow the write (WS) completion to be visible before the flush completes?
I'm not sure what you are asking here. You need to be more precise about what these IOs are, who dispatched them and what their dependencies are. Where exactly did that FWS (REQ_FLUSH) come from?
I think, though, you're asking questions about IO ordering at the wrong level - filesystems serialise and order IO, not the block layer. Hence what you see at the block layer is not necessary a reflection of the ordering the filesystem is doing.
(I've already explained this earlier today in a different thread:
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmarc.info%2F%3Fl%3Dlinux-xfs%26m%3D152091489100831%26w%3D2&data=04%7C01%7Crdorr%40microsoft.com%7C19bb64450eba4b0f2c8308d588a0c4e1%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636565146506974722%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwifQ%3D%3D%7C100&sdata=o0CgiPt1dsfALFS5fXHRGy2jlD1t4HIBjjqD%2BqOKnb4%3D&reserved=0)
That's why I ask about the operation causing a REQ_FLUSH to be issued to the storage device, as that cannot be directly issued from userspace. It will occur as a side effect of a data integrity operation the filesystem is asked to perform, but without knowing the relationship between the integrity operation and the write in question an answer cannot be given.
It may would be better to describe your IO ordering and integrity requirements at a higher level (e.g. the syscall layer), because then we know what you are trying to acheive rather that trying to understand your problem from context-less questions about "IO barriers" that don't actually exist...
Quoted 5 lines
I suspected the write was held in
iomap_dio_complete_workbut with thegeneric_write_syncchange in the patch would aO_DSYNCwrite request to a DpoFua=0 block queue allow T2 to see the completion viaio_geteventsbefore T1 completed the actual flush?
Yes, that can happen as concurrent data direct IO are not serialised against each other and will always race to completion without providing any ordering guarantees. IOWs, if you have an IO ordering dependency in your application, then that ordering dependency needs to be handled in the application.
Quoted 3 lines
2. How will my application be able to dynamically determine if
xfs and ext4 have the performance enhancement for FUA or I need engage alternate methods to use fsync/fdatasync at strategic locations?
You don't. The filesystem will provide the same integrity guarantees in either case - FUA is just a performance optimisation that will get used if your hardware supports it. Applications should not care what capabilities the storage hardawre has - the kernel should do what is fastest and most reliable for the underlying storage....
Quoted 1 line
3. Are there any plans yet to optimize ext4 as well?
Not from me.
Quoted 3 lines
4. Before the patched code the
xfs_file_write_iterwould callgeneric_write_syncand that callssubmit_io_wait. Does this hold the thread issuing theio_submitso it is unable to drive more async I/O?
No, -EIOCBQUEUED is returned to avoid blocking.
AIO calls generic_write_sync() from the IO completion path via a worker thread so it's all done asynchronously.
Cheers,
Dave.
--
Dave Chinner
[email protected]
Quoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.
Yes. that is the case.
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)
There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the RWF_DSYNC flag to the pwritev2 syscall, which allows to apply O_DSYNC semantics on a per-I/O basis instead of using it at open time.
I tried the RWF_ODSYNC and xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Quoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.
Yes. that is the case.
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)
There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the RWF_DSYNC flag to the pwritev2 syscall, which allows to apply O_DSYNC semantics on a per-I/O basis instead of using it at open time.
Jan Kara
reviewerQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊
Yeah, that's a bug in generic direct IO code that I've just recently fixed (d9c10e5b8863 "direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).
Honza
Quoted 20 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate REQ_FUA without generic_write_flush to improve performance like was done for xfs?
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Quoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊
Yeah, that's a bug in generic direct IO code that I've just recently fixed (d9c10e5b8863 "direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).
Honza
Quoted 20 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 7 lines
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.
--
Jan Kara <[email protected]>
SUSE Labs, CR
Jan - are you able to make the ext4 performance changes?
-----Original Message-----
From: Robert Dorr
Sent: Monday, March 19, 2018 11:14 AM
To: Jan Kara <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: RE: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate REQ_FUA without generic_write_flush to improve performance like was done for xfs?
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Quoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊
Yeah, that's a bug in generic direct IO code that I've just recently fixed (d9c10e5b8863 "direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).
Honza
Quoted 20 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 7 lines
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.
--
Jan Kara <[email protected]>
SUSE Labs, CR
Jan Kara
reviewerQuoted 4 lines · Robert Dorr
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate
REQ_FUAwithoutgeneric_write_flushto improve performance like was done for xfs?
I'm currently on a sick leave so I'm slow on replies. Sorry. I don't see a reason why ext4 could not have the same optimization as XFS for that case of direct IO. However I'm not sure when I get to implementing that.
Honza
Quoted 46 lines
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊Yeah, that's a bug in generic direct IO code that I've just recently fixed (
d9c10e5b8863"direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).Honza
Quoted 20 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 7 lines
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.--
Jan Kara <[email protected]>
SUSE Labs, CR
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Sorry to hear that. Get well soon.
Thanks for the response.
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Thursday, March 22, 2018 9:36 AM
To: Robert Dorr <[email protected]>
Cc: Jan Kara <[email protected]>; Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Quoted 4 lines · Robert Dorr
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate
REQ_FUAwithoutgeneric_write_flushto improve performance like was done for xfs?
I'm currently on a sick leave so I'm slow on replies. Sorry. I don't see a reason why ext4 could not have the same optimization as XFS for that case of direct IO. However I'm not sure when I get to implementing that.
Honza
Quoted 47 lines
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊Yeah, that's a bug in generic direct IO code that I've just recently fixed
(d9c10e5b8863"direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).Honza
Quoted 22 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 2 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.--
Jan Kara <[email protected]>
SUSE Labs, CR
--
Jan Kara <[email protected]>
SUSE Labs, CR
Hope you are feeling better.
1. How can we effect similar changes in ext4?
2. How do we get these changes pushed into all common release builds for both xfs or ext4 optimizations?
We are seeing dramatic performance increases with the xfs fixes. https://bugzilla.redhat.com/show_bug.cgi?id=1548524
4 socket, TPCC
9,108 – Old kernel
36,618 – Patched kernel
2 socket, TPCC
9,606 - Old kernel
18,840 - Patched kernel
--------------------------------------------------------------------------------------------------
-- Times in milli-seconds
-- wt=SQL writethrough setting
-- awt=SQL alternatewritethrough setting
-- -T3979=SQL open with Fua behavior
-- -T3982=SQL opens without Fua and use fsync (forced flush) behavior
--------------------------------------------------------------------------------------------------
--
-- Linux patched kernel for XFS FUA opts
-- SQL Server 2017 CU6 -- blktrace active -- Centos7 - 4proc, 8GB ram running on Hyper-V -- Win10, 8proc, 32GB ram host -- Samsung SSD drive -- Clean SQL Server restarts -------------------------------------------------------------------------------------------------- -- PATCHED KERNEL 4.16.x -- Create DB Inserts Checkpoint Options -- ----------------------------------- --------- ------- ---------- ----------------------------------- -- Default (-T3982 = forced flush) 3787 29814 47 O_DIRECT and fsync from SQL -- -T3979 and wt=1 awt=1 4224 25880 30 O_DIRECT and specialized fdatasync (Best without FUA is ~10x slower than FUA) -- -- -T3979 and wt=0 2860 2570 13 O_DIRECT -- -T3979 and wt=1 awt=0 4204 2573 17 O_DIRECT | O_DSYNC - Inserts and checkpoint on allocated space nears O_DIRECT only <--- !!! DESIRED BEHAVIOR !!! -- -T3979 and wt=1 awt=0 NO STAMP 4127 2823 17 O_DIRECT | O_DSYNC - Issues internal flushs for 1st writes, create faster but inserts slower -- -- UNPATCHED KERNEL 3.x -- Create DB Inserts Checkpoint Options -- ----------------------------------- --------- ------- ---------- ----------------------------------- -- Default (-T3982 = forced flush) 3097 29700 26 O_DIRECT and fsync from SQL -- -T3979 and wt=1 awt=1 4210 25800 27 O_DIRECT and specialized fdatasync -- -- -T3979 and wt=0 2880 2134 6 O_DIRECT -- -T3979 and wt=1 awt=0 4443 25290 42 O_DIRECT | O_DSYNC -- -T3979 and wt=1 awt=0 NO STAMP 4120 25680 40 O_DIRECT | O_DSYNC
--
-----Original Message-----
From: Robert Dorr
Sent: Thursday, March 22, 2018 7:38 AM
To: Jan Kara <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: RE: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Sorry to hear that. Get well soon.
Thanks for the response.
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Thursday, March 22, 2018 9:36 AM
To: Robert Dorr <[email protected]>
Cc: Jan Kara <[email protected]>; Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure data O_DSYNC DIO writes
Quoted 4 lines · Robert Dorr
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate
REQ_FUAwithoutgeneric_write_flushto improve performance like was done for xfs?
I'm currently on a sick leave so I'm slow on replies. Sorry. I don't see a reason why ext4 could not have the same optimization as XFS for that case of direct IO. However I'm not sure when I get to implementing that.
Honza
Quoted 47 lines
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊Yeah, that's a bug in generic direct IO code that I've just recently fixed
(d9c10e5b8863"direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).Honza
Quoted 22 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 2 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.--
Jan Kara <[email protected]>
SUSE Labs, CR
--
Jan Kara <[email protected]>
SUSE Labs, CR
Quoted 50 lines · Robert Dorr
Hope you are feeling better.
1. How can we effect similar changes in ext4?
2. How do we get these changes pushed into all common release builds for both xfs or ext4 optimizations?We are seeing dramatic performance increases with the xfs fixes. https://bugzilla.redhat.com/show_bug.cgi?id=1548524
4 socket, TPCC
9,108 – Old kernel
36,618 – Patched kernel2 socket, TPCC
9,606 - Old kernel
18,840 - Patched kernel--------------------------------------------------------------------------------------------------
-- Times in milli-seconds
-- wt=SQL writethrough setting
-- awt=SQL alternatewritethrough setting
-- -T3979=SQL open with Fua behavior
-- -T3982=SQL opens without Fua and use fsync (forced flush) behavior
--------------------------------------------------------------------------------------------------
--
-- Linux patched kernel for XFS FUA opts-- SQL Server 2017 CU6 -- blktrace active -- Centos7 - 4proc, 8GB ram running on Hyper-V -- Win10, 8proc, 32GB ram host -- Samsung SSD drive -- Clean SQL Server restarts -------------------------------------------------------------------------------------------------- -- PATCHED KERNEL 4.16.x -- Create DB Inserts Checkpoint Options -- ----------------------------------- --------- ------- ---------- ----------------------------------- -- Default (-T3982 = forced flush) 3787 29814 47 O_DIRECT and fsync from SQL -- -T3979 and wt=1 awt=1 4224 25880 30 O_DIRECT and specialized fdatasync (Best without FUA is ~10x slower than FUA) -- -- -T3979 and wt=0 2860 2570 13 O_DIRECT -- -T3979 and wt=1 awt=0 4204 2573 17 O_DIRECT | O_DSYNC - Inserts and checkpoint on allocated space nears O_DIRECT only <--- !!! DESIRED BEHAVIOR !!! -- -T3979 and wt=1 awt=0 NO STAMP 4127 2823 17 O_DIRECT | O_DSYNC - Issues internal flushs for 1st writes, create faster but inserts slower -- -- UNPATCHED KERNEL 3.x -- Create DB Inserts Checkpoint Options -- ----------------------------------- --------- ------- ---------- ----------------------------------- -- Default (-T3982 = forced flush) 3097 29700 26 O_DIRECT and fsync from SQL -- -T3979 and wt=1 awt=1 4210 25800 27 O_DIRECT and specialized fdatasync -- -- -T3979 and wt=0 2880 2134 6 O_DIRECT -- -T3979 and wt=1 awt=0 4443 25290 42 O_DIRECT | O_DSYNC -- -T3979 and wt=1 awt=0 NO STAMP 4120 25680 40 O_DIRECT | O_DSYNC
Quoted 2 lines
--
So these number should be taken with a VERY BIG grain of salt. Not because the change is not valid but because at the very least you are comparing kernel 3.x with latest 4.16. It's unlikely that this report will be the thing that tips the scaler to either "implement" or "not" that for ext4. But at the very least show number for the same kernel with the only difference being the patch.
Quoted 83 lines
-----Original Message-----
From: Robert Dorr
Sent: Thursday, March 22, 2018 7:38 AM
To: Jan Kara <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: RE: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesSorry to hear that. Get well soon.
Thanks for the response.
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Thursday, March 22, 2018 9:36 AM
To: Robert Dorr <[email protected]>
Cc: Jan Kara <[email protected]>; Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 4 lines · Robert Dorr
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate
REQ_FUAwithoutgeneric_write_flushto improve performance like was done for xfs?I'm currently on a sick leave so I'm slow on replies. Sorry. I don't see a reason why ext4 could not have the same optimization as XFS for that case of direct IO. However I'm not sure when I get to implementing that.
Honza
Quoted 51 lines
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊Yeah, that's a bug in generic direct IO code that I've just recently fixed
(d9c10e5b8863"direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).Honza
Quoted 26 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 3 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.--
Jan Kara <[email protected]>
SUSE Labs, CR--
Jan Kara <[email protected]>
SUSE Labs, CR N�����r��y���b�X��ǧv�^�){.n�+����{���"��^n�r���z���h����&��
�G���h�(�階�ݢj"���m�����z�ޖ���f���h���~�mml==
Quoted 1 line
Jan Kara
reviewerQuoted 1 line · Robert Dorr
Hope you are feeling better.
Yes :) Thanks.
Quoted 1 line
1. How can we effect similar changes in ext4?
So ext4 currently does not use the iomap infrastructure for direct IO and thus cannot directly use the optimization of using FUA. We'd like to switch ext4 direct IO to use iomap instead of the blkdev_direct_IO() helper. It should be pretty straightforward but not completely trivial. I'll look into it but it will take a while.
Quoted 2 lines
2. How do we get these changes pushed into all common release builds for both xfs or ext4 optimizations?
I'm not sure what are you speaking about here. Do you mean how do you get it to distributions like SLES, RHEL, etc? Generally when they update to new enough kernel version. Which is rather fast (weeks after Linus releases a kernel with this improvement) for community distros such as Fedora or openSUSE Tumbleweed, it will take much longer for enterprise distros (generally only the next major release will pick up a new kernel so a year or two).
Honza
Quoted 87 lines
-----Original Message-----
From: Robert Dorr
Sent: Thursday, March 22, 2018 7:38 AM
To: Jan Kara <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: RE: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesSorry to hear that. Get well soon.
Thanks for the response.
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Thursday, March 22, 2018 9:36 AM
To: Robert Dorr <[email protected]>
Cc: Jan Kara <[email protected]>; Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 4 lines · Robert Dorr
Awesome news on the spin.
Are you going to be able to make changes to EXT4 to accommodate
REQ_FUAwithoutgeneric_write_flushto improve performance like was done for xfs?I'm currently on a sick leave so I'm slow on replies. Sorry. I don't see a reason why ext4 could not have the same optimization as XFS for that case of direct IO. However I'm not sure when I get to implementing that.
Honza
Quoted 47 lines
-----Original Message-----
From: Jan Kara <[email protected]>
Sent: Monday, March 19, 2018 11:07 AM
To: Robert Dorr <[email protected]>
Cc: Christoph Hellwig <[email protected]>; Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 2 lines · Robert Dorr
I tried the
RWF_ODSYNCand xfs seems to honor properly but it causes ext4 to go spin out a single CPU and hang the system. 😊Yeah, that's a bug in generic direct IO code that I've just recently fixed
(d9c10e5b8863"direct-io: Fix sleep in atomic due to sync AIO" in 4.16-rc4).Honza
Quoted 22 lines
-----Original Message-----
From: Christoph Hellwig <[email protected]>
Sent: Tuesday, March 13, 2018 11:13 AM
To: Robert Dorr <[email protected]>
Cc: Dave Chinner <[email protected]>; Dan Williams <[email protected]>; [email protected]; Christoph Hellwig <[email protected]>; linux-fsdevel <[email protected]>; Jan Kara <[email protected]>; Theodore Ts'o <[email protected]>; Matthew Wilcox <[email protected]>; Scott Konersmann <[email protected]>; Slava Oks <[email protected]>; Jasraj Dange <[email protected]>; Michael Nelson <[email protected]>
Subject: Re: [PATCH] [RFC] iomap: Use FUA for pure dataO_DSYNCDIO writesQuoted 1 line
I think the answer is the iomap* logic makes sure to issue
generic_write_syncforO_DSYNCW1 after W1 is completed by hardware and then waits for completion of the flush request (REQ_PREFLUSH) before W1 is returned to the AIO completion ring, preventingio_geteventsfrom processing W1 before the flush occurs and completes. I just need proper confirmation from the experts on this code that this is the expected behavior.Yes. that is the case.
Quoted 2 lines
For SQL Server using
O_DIRECT|O_DSYNCon current kernels is very performance impacting. Instead we enable a mode for SQL that opensO_DIRECTonly and issues fsync/fdatasync when we are hardening log files or checkpointing data files. This reduces the write, flush, write, flush pattern allowing for write, write, write, ... then flush as we only issue flush requests when required to maintain the data integrity boundaries of SQL Server. The performance is significantly better then the device flush for each write as you can imagine.Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Testing shows the FUA enhancement is better then the write, flush pattern. For SQL Server we want to dynamically open with
O_DIRECT|O_DSYNCwhenREQ_FUAcan be properly used and open withO_DIRECTand leverage SQL Server's alternate flush scheme when running on older kernel or a system that does not support FUA (SATA, IDE, ...)There is no really good way to figure this out except for benchmarking, given that the FUA use an implementation detail.
Btw, another feature that might be interesting to you is the
RWF_DSYNCflag to the pwritev2 syscall, which allows to applyO_DSYNCsemantics on a per-I/O basis instead of using it at open time.--
Jan Kara <[email protected]>
SUSE Labs, CR--
Jan Kara <[email protected]>
SUSE Labs, CR
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 8 lines · Dave Chinner
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
Quoted 5 lines
We know from teh
IOMAP_F_DIRTYflag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.
Hi,
I've gotten an inquiry from some engineers at Microsoft who would really like it if ext4 could use FUA writes when doing O_DSYNC writes, since this is soemthing that SQL Server uses. In the discussion for this patch series back in 2018[1], ext4 hadn't yet converted over to iomap for Direct I/O, and so adding this feature for ext4 wasn't really practical.
[1] https://lore.kernel.org/all/[email protected]/
Today, ext4 does use iomap for DIO, but an experiment seems to indicate that something hasn't been wired up to enable FUA for O_DSYNC writes. I've looked at fs/iomap/direct-io.c and it wasn't immediately obvious what I need to add to enable this feature.
I was wondering if you could me some quick hints about what and where I should be looking?
Many thanks!
- Ted
Quoted 7 lines · Theodore Ts'o
Today, ext4 does use iomap for DIO, but an experiment seems to indicate that something hasn't been wired up to enable FUA for
O_DSYNCwrites. I've looked atfs/iomap/direct-io.cand it wasn't immediately obvious what I need to add to enable this feature.I was wondering if you could me some quick hints about what and where I should be looking?
There isn't really anything strange going on. First your device needs to support it. For NVMe the feature is mandatory, but we still disable it globally for SATA, and second you need to remember FUA only makes sense for O_DSYNC-style writes, not O_SYNC that also writes out the inode.
Then you need to make sure neither IOMAP_F_SHARED nor IOMAP_F_DIRTY is set on the iomap. IOMAP_F_SHARED is never set by ext4, so if none of the above is the culprit I'd loke into if IOMAP_F_DIRTY and up beeing set for your test I/O.
Quoted 24 lines · Theodore Ts'o
Quoted 8 lines · Dave Chinner
From: Dave Chinner <[email protected]>
If we are doing direct IO writes with datasync semantics, we often have to flush metadata changes along with the data write. However, if we are overwriting existing data, there are no metadata changes that we need to flush. In this case, optimising the IO by using FUA write makes sense.
Quoted 5 lines
We know from teh
IOMAP_F_DIRTYflag as to whether a specific inode requires a metadata flush - this is currently used by DAX to ensure extent modi$fication as stable in page fault operations. For direct IO writes, we can use it to determine if we need to flush metadata or not once the data is on disk.Hi,
I've gotten an inquiry from some engineers at Microsoft who would really like it if ext4 could use FUA writes when doing
O_DSYNCwrites, since this is soemthing that SQL Server uses. In the discussion for this patch series back in 2018[1], ext4 hadn't yet converted over to iomap for Direct I/O, and so adding this feature for ext4 wasn't really practical.
Quoted 6 lines
[1] https://lore.kernel.org/all/[email protected]/
Today, ext4 does use iomap for DIO, but an experiment seems to indicate that something hasn't been wired up to enable FUA for
O_DSYNCwrites. I've looked atfs/iomap/direct-io.cand it wasn't immediately obvious what I need to add to enable this feature.
I've actually looked briefly into this in the past for ext4 - IIRC the problem is that mtime updates during the write are causing the inode to get marked dirty.
Yeah, typical trace from a RWF_DSYNC direct IO through ext4 is:
xfs_io-6002 [007] 2986.814841: ext4_es_lookup_extent_enter: dev 7,0 ino 12 lblk 0 xfs_io-6002 [007] 2986.814848: ext4_es_lookup_extent_exit: dev 7,0 ino 12 found 1 [0/30720) 34304 W xfs_io-6002 [007] 2986.814856: ext4_journal_start_inode: dev 7,0 blocks 2, rsv_blocks 0, revoke_creds 8, type 1, ino 12, caller ext4_dirty_inode+0x39 xfs_io-6002 [007] 2986.814875: ext4_mark_inode_dirty: dev 7,0 ino 12 caller ext4_dirty_inode+0x5c xfs_io-6002 [007] 2986.814917: iomap_dio_rw_begin: dev 7:0 ino 0xc size 0x40000000 offset 0x0 length 0x20000 done_before 0x0 flags DIRECT dio_flags aio 0 xfs_io-6002 [007] 2986.814922: iomap_iter: dev 7:0 ino 0xc pos 0x0 length 0x0 flags WRITE|DIRECT (0x11) ops ext4_iomap_overwrite_ops caller __iomap_dio_rw+0x1c2
So I think the problem may be through file_modified() from ext4_dio_write_checks() triggering mtime updates which then comes back through mark_inode_dirty and that ends up causing the inode to be marked dirty and tracked by the journal.
Yup, there it is in generic_update_time():
if (updated & (S_ATIME|S_MTIME|S_CTIME))
dirty_flags = inode->i_sb->s_flags & SB_LAZYTIME ? I_DIRTY_TIME : I_DIRTY_SYNC;it's setting the inode I_DIRTY_SYNC for mtime updates.
XFS does not do this. It implements the ->update_time() method so doesn't use generic_update_time(). XFS tracks pure timestamp updates separately to other dirty inode metadata. We then elide "timestamp dirty" state from the IOMAP_F_DIRTY checks because O_DSYNC doesn't require timestamps to be persisted.
FWIW, the patch below allows testing FUA optimisations on loop devices....
-Dave.
Signature · 67 lines
Dave Chinner [email protected] loop: add support for FUA writes From: Dave Chinner <[email protected]> Any file-backed loop device on a filesysetm that support the ->fsync operation can do FUA writes. All a FUA write requires from the loop device is RWF_DSYNC semantics for the specific REQ_FUA request that is being processed. i.e. that it is on stable storage before the request completes. This allows simple testing of things like iomap FUA optimisations, and should also provide better performance for loop device in situations where the upper filesystem is issuing FUA writes to try to avoid needing journal flushes. Using RWF_DSYNC will also allow the lower filesystem to attempt to use REQ_FUA on loop devices using direct IO and potentially improve the IO patterns all the way down the stack as a result. Prep: # losetup --direct-io=on /dev/loop0 /mnt/scratch/foo.img # mkfs.xfs /dev/loop0 # mount /dev/loop0 /mnt/test # xfs_io -fdc "pwrite -b 2m 0 1g" -c fsync /mnt/test/foo # sync Measure: # xfs_io -fdc "pwrite -V 1 -D -b 128k 0 1m" -c fsync /mnt/test/foo Before: # grep . /sys/block/loop0/queue/* .... /sys/block/loop0/queue/fua:0 .... # trace-cmd stream -e block* |grep xfs_io ..... <...>-4654 [007] 809.018173: block_rq_issue: 7,0 WS 131072 () 192 + 256 [xfs_io] <...>-4654 [007] 809.025910: block_bio_queue: 7,0 WS 448 + 256 [xfs_io] <...>-4654 [007] 809.025917: block_getrq: 7,0 WS 448 + 256 [xfs_io] .... After: # grep . /sys/block/loop0/queue/* .... /sys/block/loop0/queue/fua:1 .... # trace-cmd stream -e block* |grep xfs_io ..... <...>-4648 [006] 793.968169: block_rq_issue: 7,0 WFS 131072 () 192 + 256 [xfs_io] <...>-4648 [006] 793.977521: block_bio_queue: 7,0 WFS 448 + 256 [xfs_io] <...>-4648 [006] 793.977531: block_getrq: 7,0 WFS 448 + 256 [xfs_io] The upper XFS filesystem is issuing REQ_FUA writes to the loop device now. Signed-off-by: Dave Chinner <[email protected]> --- drivers/block/loop.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-)
drivers/block/loop.c +20 -9
@@ -238,7 +238,8 @@ static void loop_set_size(struct loop_device *lo, loff_t size)kobject_uevent (&disk_to_dev (lo->lo_disk)->kobj,KOBJ_CHANGE ); } -static int lo_write_bvec (struct file *file,struct bio_vec *bvec,loff_t *ppos) +static int lo_write_bvec (struct file *file,struct bio_vec *bvec,loff_t *ppos, +rwf_t rw_flags) {struct iov_iter i;ssize_t bw;
@@ -246,7 +247,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)iov_iter_bvec (&i,ITER_SOURCE , bvec,1 , bvec->bv_len);file_start_write (file); - bw =vfs_iter_write (file, &i, ppos,0 ); + bw =vfs_iter_write (file, &i, ppos, rw_flags);file_end_write (file);if (likely (bw == bvec->bv_len))
@@ -261,14 +262,14 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) }static int lo_write_simple (struct loop_device *lo,struct request *rq, -loff_t pos) +loff_t pos,rwf_t rw_flags) {struct bio_vec bvec;struct req_iterator iter;int ret =0 ;rq_for_each_segment (bvec, rq, iter) { - ret =lo_write_bvec (lo->lo_backing_file, &bvec, &pos); + ret =lo_write_bvec (lo->lo_backing_file, &bvec, &pos, rw_flags);if (ret <0 )break ;cond_resched ();
@@ -392,7 +393,7 @@ static void lo_rw_aio_complete(struct kiocb *iocb, long ret) }static int lo_rw_aio (struct loop_device *lo,struct loop_cmd *cmd, -loff_t pos,int rw) +loff_t pos,int rw,rwf_t rw_flags) {struct iov_iter iter;struct req_iterator rq_iter;
@@ -446,6 +447,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, cmd->iocb.ki_filp = file; cmd->iocb.ki_complete = lo_rw_aio_complete; cmd->iocb.ki_flags =IOCB_DIRECT ; +kiocb_set_rw_flags (&cmd->iocb, rw_flags); cmd->iocb.ki_ioprio =IOPRIO_PRIO_VALUE (IOPRIO_CLASS_NONE ,0 );if (rw ==ITER_SOURCE )
@@ -464,6 +466,15 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) {struct loop_cmd *cmd =blk_mq_rq_to_pdu (rq);loff_t pos = ((loff_t )blk_rq_pos (rq) <<9 ) + lo->lo_offset; +rwf_t rw_flags =0 ; + +/* +* If we are being asked to do a REQ_FUA write, then we convert that to +* a datasync write so that the contents of the write are on stable +* storage before the write completes. +*/ +if (rq->cmd_flags &REQ_FUA ) + rw_flags =RWF_DSYNC ;/* * lo_write_simple and lo_read_simple should have been covered
@@ -490,12 +501,12 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq)return lo_fallocate (lo, rq, pos,FALLOC_FL_PUNCH_HOLE );case REQ_OP_WRITE :if (cmd->use_aio) -return lo_rw_aio (lo, cmd, pos,ITER_SOURCE ); +return lo_rw_aio (lo, cmd, pos,ITER_SOURCE , rw_flags);else -return lo_write_simple (lo, rq, pos); +return lo_write_simple (lo, rq, pos, rw_flags);case REQ_OP_READ :if (cmd->use_aio) -return lo_rw_aio (lo, cmd, pos,ITER_DEST ); +return lo_rw_aio (lo, cmd, pos,ITER_DEST ,0 );else return lo_read_simple (lo, rq, pos);default :
@@ -1077,7 +1088,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,mapping_set_gfp_mask (mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));if (!(lo->lo_flags &LO_FLAGS_READ_ONLY ) && file->f_op->fsync) -blk_queue_write_cache (lo->lo_queue, true, false); +blk_queue_write_cache (lo->lo_queue, true, true);if (config->block_size) bsize = config->block_size;