Commit 973a4326 authored by Mark Harmstone's avatar Mark Harmstone Committed by David Sterba
Browse files

btrfs: don't sleep in btrfs_encoded_read() if IOCB_NOWAIT is set



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: default avatarMark Harmstone <maharmstone@fb.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 26efd447
Loading
Loading
Loading
Loading
+44 −11
Original line number Diff line number Diff line
@@ -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,6 +9223,29 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
	 */
	lockend = start + BTRFS_MAX_UNCOMPRESSED - 1;

	if (nowait) {
		struct btrfs_ordered_extent *ordered;

		if (filemap_range_needs_writeback(inode->vfs_inode.i_mapping,
						  start, lockend)) {
			ret = -EAGAIN;
			goto out_unlock_inode;
		}

		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) {
			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;

@@ -9222,6 +9253,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
						       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);
@@ -9231,6 +9263,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
			unlock_extent(io_tree, start, lockend, cached_state);
			cond_resched();
		}
	}

	em = btrfs_get_extent(inode, NULL, start, lockend - start + 1);
	if (IS_ERR(em)) {