Message ID | 20170403185307.6243-8-rgoldwyn@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
> + if (unaligned_io) { > + /* If we are going to wait for other DIO to finish, bail */ > + if ((iocb->ki_flags & IOCB_NOWAIT) && > + atomic_read(&inode->i_dio_count)) > + return -EAGAIN; > inode_dio_wait(inode); This checks i_dio_count twice in the nowait case, I think it should be: if (iocb->ki_flags & IOCB_NOWAIT) { if (atomic_read(&inode->i_dio_count)) return -EAGAIN; } else { inode_dio_wait(inode); } > if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { > if (flags & IOMAP_DIRECT) { > + /* A reflinked inode will result in CoW alloc */ > + if (flags & IOMAP_NOWAIT) { > + error = -EAGAIN; > + goto out_unlock; > + } This is a bit pessimistic - just because the inode has any shared extents we could still write into unshared ones. For now I think this pessimistic check is fine, but the comment should be corrected.
On Mon, Apr 03, 2017 at 11:52:11PM -0700, Christoph Hellwig wrote: > > + if (unaligned_io) { > > + /* If we are going to wait for other DIO to finish, bail */ > > + if ((iocb->ki_flags & IOCB_NOWAIT) && > > + atomic_read(&inode->i_dio_count)) > > + return -EAGAIN; > > inode_dio_wait(inode); > > This checks i_dio_count twice in the nowait case, I think it should be: > > if (iocb->ki_flags & IOCB_NOWAIT) { > if (atomic_read(&inode->i_dio_count)) > return -EAGAIN; > } else { > inode_dio_wait(inode); > } > > > if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { > > if (flags & IOMAP_DIRECT) { > > + /* A reflinked inode will result in CoW alloc */ > > + if (flags & IOMAP_NOWAIT) { > > + error = -EAGAIN; > > + goto out_unlock; > > + } > > This is a bit pessimistic - just because the inode has any shared > extents we could still write into unshared ones. For now I think this > pessimistic check is fine, but the comment should be corrected. Consider what happens in both _reflink_{allocate,reserve}_cow. If there is already an existing reservation in the CoW fork then we'll have to CoW and therefore can't satisfy the NOWAIT flag. If there isn't already anything in the CoW fork, then we have to see if there are shared blocks by calling _reflink_trim_around_shared. That performs a refcountbt lookup, which involves locking the AGF, so we also can't satisfy NOWAIT. IOWs, I think this hunk has to move outside the IOMAP_DIRECT check to cover both write-to-reflinked-file cases. --D > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
On 04/06/2017 05:54 PM, Darrick J. Wong wrote: > On Mon, Apr 03, 2017 at 11:52:11PM -0700, Christoph Hellwig wrote: >>> + if (unaligned_io) { >>> + /* If we are going to wait for other DIO to finish, bail */ >>> + if ((iocb->ki_flags & IOCB_NOWAIT) && >>> + atomic_read(&inode->i_dio_count)) >>> + return -EAGAIN; >>> inode_dio_wait(inode); >> >> This checks i_dio_count twice in the nowait case, I think it should be: >> >> if (iocb->ki_flags & IOCB_NOWAIT) { >> if (atomic_read(&inode->i_dio_count)) >> return -EAGAIN; >> } else { >> inode_dio_wait(inode); >> } >> >>> if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { >>> if (flags & IOMAP_DIRECT) { >>> + /* A reflinked inode will result in CoW alloc */ >>> + if (flags & IOMAP_NOWAIT) { >>> + error = -EAGAIN; >>> + goto out_unlock; >>> + } >> >> This is a bit pessimistic - just because the inode has any shared >> extents we could still write into unshared ones. For now I think this >> pessimistic check is fine, but the comment should be corrected. > > Consider what happens in both _reflink_{allocate,reserve}_cow. If there > is already an existing reservation in the CoW fork then we'll have to > CoW and therefore can't satisfy the NOWAIT flag. If there isn't already > anything in the CoW fork, then we have to see if there are shared blocks > by calling _reflink_trim_around_shared. That performs a refcountbt > lookup, which involves locking the AGF, so we also can't satisfy NOWAIT. > > IOWs, I think this hunk has to move outside the IOMAP_DIRECT check to > cover both write-to-reflinked-file cases. > IOMAP_NOWAIT is set only with IOMAP_DIRECT since the nowait feature is for direct-IO only. This is checked early on, when we are checking for user-passed flags, and if not, -EINVAL is returned.
On Fri, Apr 07, 2017 at 06:34:28AM -0500, Goldwyn Rodrigues wrote: > > > On 04/06/2017 05:54 PM, Darrick J. Wong wrote: > > On Mon, Apr 03, 2017 at 11:52:11PM -0700, Christoph Hellwig wrote: > >>> + if (unaligned_io) { > >>> + /* If we are going to wait for other DIO to finish, bail */ > >>> + if ((iocb->ki_flags & IOCB_NOWAIT) && > >>> + atomic_read(&inode->i_dio_count)) > >>> + return -EAGAIN; > >>> inode_dio_wait(inode); > >> > >> This checks i_dio_count twice in the nowait case, I think it should be: > >> > >> if (iocb->ki_flags & IOCB_NOWAIT) { > >> if (atomic_read(&inode->i_dio_count)) > >> return -EAGAIN; > >> } else { > >> inode_dio_wait(inode); > >> } > >> > >>> if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { > >>> if (flags & IOMAP_DIRECT) { > >>> + /* A reflinked inode will result in CoW alloc */ > >>> + if (flags & IOMAP_NOWAIT) { > >>> + error = -EAGAIN; > >>> + goto out_unlock; > >>> + } > >> > >> This is a bit pessimistic - just because the inode has any shared > >> extents we could still write into unshared ones. For now I think this > >> pessimistic check is fine, but the comment should be corrected. > > > > Consider what happens in both _reflink_{allocate,reserve}_cow. If there > > is already an existing reservation in the CoW fork then we'll have to > > CoW and therefore can't satisfy the NOWAIT flag. If there isn't already > > anything in the CoW fork, then we have to see if there are shared blocks > > by calling _reflink_trim_around_shared. That performs a refcountbt > > lookup, which involves locking the AGF, so we also can't satisfy NOWAIT. > > > > IOWs, I think this hunk has to move outside the IOMAP_DIRECT check to > > cover both write-to-reflinked-file cases. > > > > IOMAP_NOWAIT is set only with IOMAP_DIRECT since the nowait feature is > for direct-IO only. This is checked early on, when we are checking for Ah, ok. Disregard what I said about moving it then. --D > user-passed flags, and if not, -EINVAL is returned. > > > -- > Goldwyn
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 35703a8..08a5eef 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -541,8 +541,11 @@ xfs_file_dio_aio_write( iolock = XFS_IOLOCK_SHARED; } - xfs_ilock(ip, iolock); - + if (!xfs_ilock_nowait(ip, iolock)) { + if (iocb->ki_flags & IOCB_NOWAIT) + return -EAGAIN; + xfs_ilock(ip, iolock); + } ret = xfs_file_aio_write_checks(iocb, from, &iolock); if (ret) goto out; @@ -553,9 +556,13 @@ xfs_file_dio_aio_write( * otherwise demote the lock if we had to take the exclusive lock * for other reasons in xfs_file_aio_write_checks. */ - if (unaligned_io) + if (unaligned_io) { + /* If we are going to wait for other DIO to finish, bail */ + if ((iocb->ki_flags & IOCB_NOWAIT) && + atomic_read(&inode->i_dio_count)) + return -EAGAIN; inode_dio_wait(inode); - else if (iolock == XFS_IOLOCK_EXCL) { + } else if (iolock == XFS_IOLOCK_EXCL) { xfs_ilock_demote(ip, XFS_IOLOCK_EXCL); iolock = XFS_IOLOCK_SHARED; } diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 288ee5b..6843725 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -1015,6 +1015,11 @@ xfs_file_iomap_begin( if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { if (flags & IOMAP_DIRECT) { + /* A reflinked inode will result in CoW alloc */ + if (flags & IOMAP_NOWAIT) { + error = -EAGAIN; + goto out_unlock; + } /* may drop and re-acquire the ilock */ error = xfs_reflink_allocate_cow(ip, &imap, &shared, &lockmode); @@ -1032,6 +1037,14 @@ xfs_file_iomap_begin( if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) { /* + * If nowait is set bail since we are going to make + * allocations. + */ + if (flags & IOMAP_NOWAIT) { + error = -EAGAIN; + goto out_unlock; + } + /* * We cap the maximum length we map here to MAX_WRITEBACK_PAGES * pages to keep the chunks of work done where somewhat symmetric * with the work writeback does. This is a completely arbitrary diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 685c042..070a30e 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1749,7 +1749,7 @@ static struct file_system_type xfs_fs_type = { .name = "xfs", .mount = xfs_fs_mount, .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, + .fs_flags = FS_REQUIRES_DEV | FS_NOWAIT, }; MODULE_ALIAS_FS("xfs");
From: Goldwyn Rodrigues <rgoldwyn@suse.com> If IOCB_NOWAIT is set, bail if the i_rwsem is not lockable immediately. IF IOMAP_NOWAIT is set, return EAGAIN in xfs_file_iomap_begin if it needs allocation either due to file extension, writing to a hole, or COW or waiting for other DIOs to finish. --- fs/xfs/xfs_file.c | 15 +++++++++++---- fs/xfs/xfs_iomap.c | 13 +++++++++++++ fs/xfs/xfs_super.c | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-)