]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: don't sleep in btrfs_encoded_read() if IOCB_NOWAIT is set
authorMark Harmstone <maharmstone@fb.com>
Tue, 22 Oct 2024 14:50:18 +0000 (15:50 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 11 Nov 2024 13:34:21 +0000 (14:34 +0100)
Change btrfs_encoded_read() so that it returns -EAGAIN rather than sleeps
if IOCB_NOWAIT is set in iocb->ki_flags. The conditions that require
sleeping are: inode lock, writeback, extent lock, ordered range.

Signed-off-by: Mark Harmstone <maharmstone@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 98a20edaa1123f8eb4010bdd8aa078462e9534b8..358a282de7fea27ff9a3f7eb3484ae7cc2d9332c 100644 (file)
@@ -8983,12 +8983,16 @@ static ssize_t btrfs_encoded_read_inline(
        unsigned long ptr;
        void *tmp;
        ssize_t ret;
+       const bool nowait = (iocb->ki_flags & IOCB_NOWAIT);
 
        path = btrfs_alloc_path();
        if (!path) {
                ret = -ENOMEM;
                goto out;
        }
+
+       path->nowait = nowait;
+
        ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode),
                                       extent_start, 0);
        if (ret) {
@@ -9198,11 +9202,15 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
        size_t count = iov_iter_count(iter);
        u64 start, lockend;
        struct extent_map *em;
+       const bool nowait = (iocb->ki_flags & IOCB_NOWAIT);
        bool unlocked = false;
 
        file_accessed(iocb->ki_filp);
 
-       btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
+       ret = btrfs_inode_lock(inode,
+                              BTRFS_ILOCK_SHARED | (nowait ? BTRFS_ILOCK_TRY : 0));
+       if (ret)
+               return ret;
 
        if (iocb->ki_pos >= inode->vfs_inode.i_size) {
                btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
@@ -9215,21 +9223,46 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
         */
        lockend = start + BTRFS_MAX_UNCOMPRESSED - 1;
 
-       for (;;) {
+       if (nowait) {
                struct btrfs_ordered_extent *ordered;
 
-               ret = btrfs_wait_ordered_range(inode, start,
-                                              lockend - start + 1);
-               if (ret)
+               if (filemap_range_needs_writeback(inode->vfs_inode.i_mapping,
+                                                 start, lockend)) {
+                       ret = -EAGAIN;
                        goto out_unlock_inode;
-               lock_extent(io_tree, start, lockend, cached_state);
+               }
+
+               if (!try_lock_extent(io_tree, start, lockend, cached_state)) {
+                       ret = -EAGAIN;
+                       goto out_unlock_inode;
+               }
+
                ordered = btrfs_lookup_ordered_range(inode, start,
                                                     lockend - start + 1);
-               if (!ordered)
-                       break;
-               btrfs_put_ordered_extent(ordered);
-               unlock_extent(io_tree, start, lockend, cached_state);
-               cond_resched();
+               if (ordered) {
+                       btrfs_put_ordered_extent(ordered);
+                       unlock_extent(io_tree, start, lockend, cached_state);
+                       ret = -EAGAIN;
+                       goto out_unlock_inode;
+               }
+       } else {
+               for (;;) {
+                       struct btrfs_ordered_extent *ordered;
+
+                       ret = btrfs_wait_ordered_range(inode, start,
+                                                      lockend - start + 1);
+                       if (ret)
+                               goto out_unlock_inode;
+
+                       lock_extent(io_tree, start, lockend, cached_state);
+                       ordered = btrfs_lookup_ordered_range(inode, start,
+                                                            lockend - start + 1);
+                       if (!ordered)
+                               break;
+                       btrfs_put_ordered_extent(ordered);
+                       unlock_extent(io_tree, start, lockend, cached_state);
+                       cond_resched();
+               }
        }
 
        em = btrfs_get_extent(inode, NULL, start, lockend - start + 1);