xfs: nowait aio support
authorGoldwyn Rodrigues <rgoldwyn@suse.com>
Tue, 20 Jun 2017 12:05:48 +0000 (07:05 -0500)
committerJens Axboe <axboe@kernel.dk>
Tue, 20 Jun 2017 13:12:03 +0000 (07:12 -0600)
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.

Return -EAGAIN if we don't have extent list in memory.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/xfs/xfs_file.c
fs/xfs/xfs_iomap.c

index 5fb5a0958a1485db46a2f753446c11828ff1913e..17f27a2fb5e25fdfdfa93612eed424235d15b8de 100644 (file)
@@ -237,7 +237,11 @@ xfs_file_dax_read(
        if (!count)
                return 0; /* skip atime */
 
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
+       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
+               if (iocb->ki_flags & IOCB_NOWAIT)
+                       return -EAGAIN;
+               xfs_ilock(ip, XFS_IOLOCK_SHARED);
+       }
        ret = dax_iomap_rw(iocb, to, &xfs_iomap_ops);
        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
@@ -541,7 +545,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)
@@ -553,9 +561,15 @@ 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)
-               inode_dio_wait(inode);
-       else if (iolock == XFS_IOLOCK_EXCL) {
+       if (unaligned_io) {
+               /* If we are going to wait for other DIO to finish, bail */
+               if (iocb->ki_flags & IOCB_NOWAIT) {
+                       if (atomic_read(&inode->i_dio_count))
+                               return -EAGAIN;
+               } else {
+                       inode_dio_wait(inode);
+               }
+       } else if (iolock == XFS_IOLOCK_EXCL) {
                xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
                iolock = XFS_IOLOCK_SHARED;
        }
@@ -585,7 +599,12 @@ xfs_file_dax_write(
        size_t                  count;
        loff_t                  pos;
 
-       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;
@@ -892,6 +911,7 @@ xfs_file_open(
                return -EFBIG;
        if (XFS_FORCED_SHUTDOWN(XFS_M(inode->i_sb)))
                return -EIO;
+       file->f_mode |= FMODE_AIO_NOWAIT;
        return 0;
 }
 
index 94e5bdf7304cff79c9ad7784013520776e3086f8..05dc87e8c1f59596f671cbc977ed6c9333b67adb 100644 (file)
@@ -995,6 +995,11 @@ xfs_file_iomap_begin(
                lockmode = xfs_ilock_data_map_shared(ip);
        }
 
+       if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) {
+               error = -EAGAIN;
+               goto out_unlock;
+       }
+
        ASSERT(offset <= mp->m_super->s_maxbytes);
        if ((xfs_fsize_t)offset + length > mp->m_super->s_maxbytes)
                length = mp->m_super->s_maxbytes - offset;
@@ -1016,6 +1021,15 @@ 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.
+                        * FIXME: It could still overwrite on unshared extents
+                        * and not need allocation.
+                        */
+                       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 +1046,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