Flag file systems as supporting parallel dio writes
Subsystems (5)
Jens Axboe
maintainercover Flag file systems as supporting parallel dio writes
Hi,
This has been on my TODO list for a while, and now that ext4 supports parallel dio writes as well, time to dust it off and send it out... This adds an FMODE flag to inform users that a given file supports parallel dio writes. io_uring can use this to avoid serializing dio writes upfront, in case it isn't needed. A few details in patch #2, patch 1 does nothing by itself.
Signature · 1 line
Jens Axboe
Jens Axboe
maintainerPATCH 1/2 fs: add FMODE_DIO_PARALLEL_WRITE flag
Some filesystems support multiple threads writing to the same file with O_DIRECT without requiring exclusive access to it. io_uring can use this hint to avoid serializing dio writes to this inode, instead allowing them to run in parallel.
XFS and ext4 both fall into this category, so set the flag for both of them.
--- fs/ext4/file.c | 3 ++- fs/xfs/xfs_file.c | 3 ++- include/linux/fs.h | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-)
fs/ext4/file.c +2 -1
@@ -899,7 +899,8 @@ static int ext4_file_open(struct inode *inode, struct file *filp)return ret; } - filp->f_mode |=FMODE_NOWAIT |FMODE_BUF_RASYNC ; + filp->f_mode |=FMODE_NOWAIT |FMODE_BUF_RASYNC | +FMODE_DIO_PARALLEL_WRITE ;return dquot_file_open (inode, filp); }
fs/xfs/xfs_file.c +2 -1
@@ -1171,7 +1171,8 @@ xfs_file_open( {if (xfs_is_shutdown (XFS_M (inode->i_sb)))return -EIO ; - file->f_mode |=FMODE_NOWAIT |FMODE_BUF_RASYNC |FMODE_BUF_WASYNC ; + file->f_mode |=FMODE_NOWAIT |FMODE_BUF_RASYNC |FMODE_BUF_WASYNC | +FMODE_DIO_PARALLEL_WRITE ;return generic_file_open (inode, file); }
include/linux/fs.h +3 -0
@@ -168,6 +168,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,#define FMODE_NOREUSE ((__force fmode_t)0x800000) +/* File supports non-exclusive O_DIRECT writes from multiple threads */ +#define FMODE_DIO_PARALLEL_WRITE ((__force fmode_t)0x1000000) +/* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000)
Signature · 1 line
2.39.2
PATCH 1/2 fs: add FMODE_DIO_PARALLEL_WRITE flag
Miklos, Jens,
could we please also set this flag for fuse?
Thanks,
Bernd
fuse: Set FMODE_DIO_PARALLEL_WRITE flag
From: Bernd Schubert <[email protected]>
Fuse can also do parallel DIO writes, if userspace has enabled it.
--- fs/fuse/file.c | 3 +++ 1 file changed, 3 insertions(+)
fs/fuse/file.c +3 -0
@@ -215,6 +215,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) }if ((file->f_mode &FMODE_WRITE ) && fc->writeback_cache)fuse_link_write_file (file); + +if (ff->open_flags &FOPEN_PARALLEL_DIRECT_WRITES ) + file->f_mode |=FMODE_DIO_PARALLEL_WRITE ; }int fuse_open_common (struct inode *inode,struct file *file,bool isdir)
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Sorry, had forgotten to CC Miklos.
Quoted 34 lines · Bernd Schubert
Miklos, Jens,
could we please also set this flag for fuse?
Thanks,
Berndfuse: Set
FMODE_DIO_PARALLEL_WRITEflagFrom: Bernd Schubert <[email protected]>
Fuse can also do parallel DIO writes, if userspace has enabled it.
Signed-off-by Bernd Schubert <[email protected]>--- fs/fuse/file.c | 3 +++ 1 file changed, 3 insertions(+)fs/fuse/file.c +3
-0@@ -215,6 +215,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) }if ((file->f_mode &FMODE_WRITE ) && fc->writeback_cache)fuse_link_write_file (file); + +if (ff->open_flags &FOPEN_PARALLEL_DIRECT_WRITES ) + file->f_mode |=FMODE_DIO_PARALLEL_WRITE ; }int fuse_open_common (struct inode *inode,struct file *file,bool isdir)
Miklos Szeredi
maintainerRe: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
In reply to Bernd SchubertQuoted 26 lines · Bernd Schubert
Miklos, Jens,
could we please also set this flag for fuse?
Thanks,
Berndfuse: Set
FMODE_DIO_PARALLEL_WRITEflagFrom: Bernd Schubert <[email protected]>
Fuse can also do parallel DIO writes, if userspace has enabled it.
Signed-off-by Bernd Schubert <[email protected]>--- fs/fuse/file.c | 3 +++ 1 file changed, 3 insertions(+)fs/fuse/file.c +0
-0
fs/fuse/file.c void fuse_finish_open(struct inode *inode, struct file *file) · line 220
Quoted 6 lines
fs/fuse/file.c +3
-0@@ -215,6 +215,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) }if ((file->f_mode &FMODE_WRITE ) && fc->writeback_cache)fuse_link_write_file (file); + +if (ff->open_flags &FOPEN_PARALLEL_DIRECT_WRITES ) + file->f_mode |=FMODE_DIO_PARALLEL_WRITE ;
fuse_direct_write_iter():
bool exclusive_lock =
!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
iocb->ki_flags & IOCB_APPEND ||
fuse_direct_write_extending_i_size(iocb, from);If the write is size extending, then it will take the lock exclusive. OTOH, I guess that it would be unusual for lots of size extending writes to be done in parallel.
What would be the effect of giving the FMODE_DIO_PARALLEL_WRITE hint and then still serializing the writes?
Thanks,
Miklos
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 41 lines · Miklos Szeredi
Quoted 26 lines · Bernd Schubert
Miklos, Jens,
could we please also set this flag for fuse?
Thanks,
Berndfuse: Set
FMODE_DIO_PARALLEL_WRITEflagFrom: Bernd Schubert <[email protected]>
Fuse can also do parallel DIO writes, if userspace has enabled it.
Signed-off-by Bernd Schubert <[email protected]>--- fs/fuse/file.c | 3 +++ 1 file changed, 3 insertions(+)fs/fuse/file.c +0
-0fs/fuse/file.c void fuse_finish_open(struct inode *inode, struct file *file) · line 220
Quoted 6 lines
fs/fuse/file.c +3
-0@@ -215,6 +215,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) }if ((file->f_mode &FMODE_WRITE ) && fc->writeback_cache)fuse_link_write_file (file); + +if (ff->open_flags &FOPEN_PARALLEL_DIRECT_WRITES ) + file->f_mode |=FMODE_DIO_PARALLEL_WRITE ;
fuse_direct_write_iter():bool
exclusive_lock=!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) || iocb->ki_flags & IOCB_APPEND || fuse_direct_write_extending_i_size(iocb, from);
Quoted 6 lines
If the write is size extending, then it will take the lock exclusive. OTOH, I guess that it would be unusual for lots of size extending writes to be done in parallel.
What would be the effect of giving the
FMODE_DIO_PARALLEL_WRITEhint and then still serializing the writes?
It used here
fuse_finish_open has its own lock, so letting uring handle requests in parallel should not hurt? Is this going like
application -> uring does parallel requests -> fuse.ko -> fuse-deamon
So when fuse-deamon signals that it can handle parallel DIO, it is just fuse.ko that might need its own lock to extend the file?
Thanks,
Bernd
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
In reply to Miklos SzerediQuoted 7 lines · Miklos Szeredi
fuse_direct_write_iter():bool
exclusive_lock=!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) || iocb->ki_flags & IOCB_APPEND || fuse_direct_write_extending_i_size(iocb, from);
Quoted 6 lines
If the write is size extending, then it will take the lock exclusive. OTOH, I guess that it would be unusual for lots of size extending writes to be done in parallel.
What would be the effect of giving the
FMODE_DIO_PARALLEL_WRITEhint and then still serializing the writes?
I have no idea how this flags work, but XFS also takes i_rwsem exclusively for appends, when the positions and size aren't aligned to the block size, and a few other cases.
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 12 lines · Christoph Hellwig
Quoted 11 lines · Miklos Szeredi
fuse_direct_write_iter():bool
exclusive_lock=!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) || iocb->ki_flags & IOCB_APPEND || fuse_direct_write_extending_i_size(iocb, from);If the write is size extending, then it will take the lock exclusive. OTOH, I guess that it would be unusual for lots of size extending writes to be done in parallel.
Quoted 6 lines
Quoted 2 lines
What would be the effect of giving the
FMODE_DIO_PARALLEL_WRITEhint and then still serializing the writes?I have no idea how this flags work, but XFS also takes
i_rwsemexclusively for appends, when the positions and size aren't aligned to the block size, and a few other cases.
IIUC uring wants to avoid the situation where someone sends 300 writes to the same file, all of which end up in background workers, and all of which then contend on exclusive i_rwsem. Hence it has some hashing scheme that executes io requests serially if they hash to the same value (which iirc is the inode number?) to prevent resource waste.
This flag turns off that hashing behavior on the assumption that each of those 300 writes won't serialize on the other 299 writes, hence it's ok to start up 300 workers.
(apologies for precoffee garbled response)
--D
Jens Axboe
maintainerRe: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 26 lines · Darrick J. Wong
Quoted 12 lines · Christoph Hellwig
Quoted 11 lines · Miklos Szeredi
fuse_direct_write_iter():bool
exclusive_lock=!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) || iocb->ki_flags & IOCB_APPEND || fuse_direct_write_extending_i_size(iocb, from);If the write is size extending, then it will take the lock exclusive. OTOH, I guess that it would be unusual for lots of size extending writes to be done in parallel.
Quoted 6 lines
Quoted 2 lines
What would be the effect of giving the
FMODE_DIO_PARALLEL_WRITEhint and then still serializing the writes?I have no idea how this flags work, but XFS also takes
i_rwsemexclusively for appends, when the positions and size aren't aligned to the block size, and a few other cases.IIUC uring wants to avoid the situation where someone sends 300 writes to the same file, all of which end up in background workers, and all of which then contend on exclusive
i_rwsem. Hence it has some hashing scheme that executes io requests serially if they hash to the same value (which iirc is the inode number?) to prevent resource waste.
Quoted 5 lines
This flag turns off that hashing behavior on the assumption that each of those 300 writes won't serialize on the other 299 writes, hence it's ok to start up 300 workers.
(apologies for precoffee garbled response)
Yep, that is pretty much it. If all writes to that inode are serialized by a lock on the fs side, then we'll get a lot of contention on that mutex. And since, originally, nothing supported async writes, everything would get punted to the io-wq workers. io_uring added per-inode hashing for this, so that any punt to io-wq of a write would get serialized.
IOW, it's an efficiency thing, not a correctness thing.
Signature · 1 line
Jens Axboe
Miklos Szeredi
maintainerRe: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 7 lines · Jens Axboe
Yep, that is pretty much it. If all writes to that inode are serialized by a lock on the fs side, then we'll get a lot of contention on that mutex. And since, originally, nothing supported async writes, everything would get punted to the io-wq workers.
io_uringadded per-inode hashing for this, so that any punt to io-wq of a write would get serialized.IOW, it's an efficiency thing, not a correctness thing.
We could still get a performance regression if the majority of writes still trigger the exclusive locking. The questions are:
- how often does that happen in real life?
- how bad the performance regression would be?
Without first attempting to answer those questions, I'd be reluctant to add FMODE_DIO_PARALLEL_WRITE to fuse.
Thanks,
Miklos
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 8 lines · Miklos Szeredi
Quoted 6 lines · Jens Axboe
Yep, that is pretty much it. If all writes to that inode are serialized by a lock on the fs side, then we'll get a lot of contention on that mutex. And since, originally, nothing supported async writes, everything would get punted to the io-wq workers.
io_uringadded per-inode hashing for this, so that any punt to io-wq of a write would get serialized.
Quoted 6 lines
Quoted 1 line
IOW, it's an efficiency thing, not a correctness thing.
We could still get a performance regression if the majority of writes still trigger the exclusive locking. The questions are:
- how often does that happen in real life?
Application depending? My personal opinion is that applications/developers knowing about uring would also know that they should set the right file size first. Like MPIIO is extending files persistently and it is hard to fix with all these different MPI stacks (I can try to notify mpich and mvapich developers). So best would be to document it somewhere in the uring man page that parallel extending files might have negative side effects?
Quoted 1 line
- how bad the performance regression would be?
I can give it a try with fio and fallocate=none over fuse during the next days.
Quoted 4 lines
Without first attempting to answer those questions, I'd be reluctant to add
FMODE_DIO_PARALLEL_WRITEto fuse.
Bernd
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 16 lines · Bernd Schubert
Quoted 8 lines · Miklos Szeredi
Quoted 6 lines · Jens Axboe
Yep, that is pretty much it. If all writes to that inode are serialized by a lock on the fs side, then we'll get a lot of contention on that mutex. And since, originally, nothing supported async writes, everything would get punted to the io-wq workers.
io_uringadded per-inode hashing for this, so that any punt to io-wq of a write would get serialized.Quoted 6 lines
Quoted 1 line
IOW, it's an efficiency thing, not a correctness thing.
We could still get a performance regression if the majority of writes still trigger the exclusive locking. The questions are:
- how often does that happen in real life?
Quoted 7 lines
Application depending? My personal opinion is that applications/developers knowing about uring would also know that they should set the right file size first. Like MPIIO is extending files persistently and it is hard to fix with all these different MPI stacks (I can try to notify mpich and mvapich developers). So best would be to document it somewhere in the uring man page that parallel extending files might have negative side effects?
There are relatively few applications running concurrent async RWF_APPEND DIO writes. IIRC SycallaDB was the first we came across a few years ago. Apps that use RWF_APPEND for individual DIOs expect that it doesn't cause performance anomolies.
These days XFS will run concurrent append DIO writes and it doesn't serialise RWF_APPEND IO against other RWF_APPEND IOs. Avoiding data corruption due to racing append IOs doing file extension has been delegated to the userspace application similar to how we delegate the responsibility for avoiding data corruption due to overlapping concurrent DIO to userspace.
Quoted 4 lines
Quoted 1 line
- how bad the performance regression would be?
I can give it a try with fio and fallocate=none over fuse during the next days.
It depends on where the lock that triggers serialisation is, and how bad the contention on it is. rwsems suck for write contention because of the "spin on owner" "optimisations" for write locking and long write holds that occur in the IO path. In general, it will be no worse than using userspace threads to issue the exact same IO pattern using concurrent sync IO.
Quoted 2 lines
Quoted 2 lines
Without first attempting to answer those questions, I'd be reluctant to add
FMODE_DIO_PARALLEL_WRITEto fuse.
I'd tag it with this anyway - for the majority of apps that are doing concurrent DIO within EOF, shared locking is big win. If there's a corner case that apps trigger that is slow, deal with them when they are reported....
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]
Jens Axboe
maintainerRe: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 7 lines · Dave Chinner
Quoted 2 lines
Quoted 2 lines
Without first attempting to answer those questions, I'd be reluctant to add
FMODE_DIO_PARALLEL_WRITEto fuse.I'd tag it with this anyway - for the majority of apps that are doing concurrent DIO within EOF, shared locking is big win. If there's a corner case that apps trigger that is slow, deal with them when they are reported....
Agree, the common/fast case will be fine, which is really the most important part.
Signature · 1 line
Jens Axboe
Re: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
In reply to Darrick J. WongQuoted 11 lines · Darrick J. Wong
IIUC uring wants to avoid the situation where someone sends 300 writes to the same file, all of which end up in background workers, and all of which then contend on exclusive
i_rwsem. Hence it has some hashing scheme that executes io requests serially if they hash to the same value (which iirc is the inode number?) to prevent resource waste.This flag turns off that hashing behavior on the assumption that each of those 300 writes won't serialize on the other 299 writes, hence it's ok to start up 300 workers.
(apologies for precoffee garbled response)
It might be useful if someone (Jens?) could clearly document the assumptions for this flag.
Jens Axboe
maintainerRe: [PATCH 1/2] fs: add FMODE_DIO_PARALLEL_WRITE flag
Quoted 7 lines · Christoph Hellwig
Quoted 6 lines · Darrick J. Wong
IIUC uring wants to avoid the situation where someone sends 300 writes to the same file, all of which end up in background workers, and all of which then contend on exclusive
i_rwsem. Hence it has some hashing scheme that executes io requests serially if they hash to the same value (which iirc is the inode number?) to prevent resource waste.
Quoted 8 lines
Quoted 5 lines
This flag turns off that hashing behavior on the assumption that each of those 300 writes won't serialize on the other 299 writes, hence it's ok to start up 300 workers.
(apologies for precoffee garbled response)
It might be useful if someone (Jens?) could clearly document the assumptions for this flag.
I guess it can be summed up as the common case should not be using exclusive (per file/inode) locking. If file extensions need exclusive locking that's less of a concern, as I don't think it's unreasonable to expect that to require stricter locking.
Signature · 1 line
Jens Axboe
Jens Axboe
maintainerPATCH 2/2 io_uring: avoid hashing O_DIRECT writes if the filesystem doesn't need it
In reply to Jens Axboeio_uring hashes writes to a given file/inode so that it can serialize them. This is useful if the file system needs exclusive access to the file to perform the write, as otherwise we end up with a ton of io-wq threads trying to lock the inode at the same time. This can cause excessive system time.
But if the file system has flagged that it supports parallel O_DIRECT writes, then there's no need to serialize the writes. Check for that through FMODE_DIO_PARALLEL_WRITE and don't hash it if we don't need to.
In a basic test of 8 threads writing to a file on XFS on a gen2 Optane, with each thread writing in 4k chunks, it improves performance from ~1350K IOPS (or ~5290MiB/sec) to ~1410K IOPS (or ~5500MiB/sec).
--- io_uring/io_uring.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
io_uring/io_uring.c +7 -1
@@ -429,7 +429,13 @@ static void io_prep_async_work(struct io_kiocb *req) }if (req->flags &REQ_F_ISREG ) { -if (def->hash_reg_file || (ctx->flags &IORING_SETUP_IOPOLL )) +bool should_hash = def->hash_reg_file; + +/* don't serialize this request if the fs doesn't need it */ +if (should_hash && (req->file->f_flags &O_DIRECT ) && + (req->file->f_mode &FMODE_DIO_PARALLEL_WRITE )) + should_hash = false; +if (should_hash || (ctx->flags &IORING_SETUP_IOPOLL ))io_wq_hash_work (&req->work,file_inode (req->file)); }else if (!req->file || !S_ISBLK (file_inode (req->file)->i_mode)) {if (def->unbound_nonreg_file)
Signature · 1 line
2.39.2
Jens Axboe
maintainerQuoted 8 lines · Jens Axboe
Hi,
This has been on my TODO list for a while, and now that ext4 supports parallel dio writes as well, time to dust it off and send it out... This adds an FMODE flag to inform users that a given file supports parallel dio writes.
io_uringcan use this to avoid serializing dio writes upfront, in case it isn't needed. A few details in patch #2, patch 1 does nothing by itself.
I'm assuming silence is consent here and folks are fine with this change?
Signature · 1 line
Jens Axboe
Darrick J. Wong
Reviewed-byQuoted 10 lines · Jens Axboe
Quoted 8 lines · Jens Axboe
Hi,
This has been on my TODO list for a while, and now that ext4 supports parallel dio writes as well, time to dust it off and send it out... This adds an FMODE flag to inform users that a given file supports parallel dio writes.
io_uringcan use this to avoid serializing dio writes upfront, in case it isn't needed. A few details in patch #2, patch 1 does nothing by itself.
Quoted 2 lines
I'm assuming silence is consent here and folks are fine with this change?
Oh, yeah, this one fell off my radar.
LGTM,
--D
Quoted 4 lines
Signature · 1 line
Jens Axboe
Jens Axboe
maintainerQuoted 11 lines · Darrick J. Wong
Quoted 10 lines · Jens Axboe
Quoted 8 lines · Jens Axboe
Hi,
This has been on my TODO list for a while, and now that ext4 supports parallel dio writes as well, time to dust it off and send it out... This adds an FMODE flag to inform users that a given file supports parallel dio writes.
io_uringcan use this to avoid serializing dio writes upfront, in case it isn't needed. A few details in patch #2, patch 1 does nothing by itself.
Quoted 7 lines
Quoted 2 lines
I'm assuming silence is consent here and folks are fine with this change?
Oh, yeah, this one fell off my radar.
LGTM,
Reviewed-by Darrick J. Wong <[email protected]>
Thanks Darrick.
Signature · 1 line
Jens Axboe
Quoted 8 lines · Jens Axboe
Hi,
This has been on my TODO list for a while, and now that ext4 supports parallel dio writes as well, time to dust it off and send it out... This adds an FMODE flag to inform users that a given file supports parallel dio writes.
io_uringcan use this to avoid serializing dio writes upfront, in case it isn't needed. A few details in patch #2, patch 1 does nothing by itself.
Looks good,