]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: change btrfs_encoded_read() so that reading of extent is done by caller
authorMark Harmstone <maharmstone@fb.com>
Tue, 22 Oct 2024 14:50:17 +0000 (15:50 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 11 Nov 2024 13:34:21 +0000 (14:34 +0100)
Change the behaviour of btrfs_encoded_read() so that if it needs to read
an extent from disk, it leaves the extent and inode locked and returns
-EIOCBQUEUED. The caller is then responsible for doing the I/O via
btrfs_encoded_read_regular() and unlocking the extent and inode.

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/btrfs_inode.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c

index 157fd3f4cb333abd2464136da49a79d7d91439c3..2817f0cc692b8c85e3efeca500f8d670c3c9595c 100644 (file)
@@ -615,7 +615,14 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
                                          u64 disk_bytenr, u64 disk_io_size,
                                          struct page **pages);
 ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
-                          struct btrfs_ioctl_encoded_io_args *encoded);
+                          struct btrfs_ioctl_encoded_io_args *encoded,
+                          struct extent_state **cached_state,
+                          u64 *disk_bytenr, u64 *disk_io_size);
+ssize_t btrfs_encoded_read_regular(struct kiocb *iocb, struct iov_iter *iter,
+                                  u64 start, u64 lockend,
+                                  struct extent_state **cached_state,
+                                  u64 disk_bytenr, u64 disk_io_size,
+                                  size_t count, bool compressed, bool *unlocked);
 ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
                               const struct btrfs_ioctl_encoded_io_args *encoded);
 
index dd2e4d57af214bfe9b4c80a4c0e2431d63d7ebb6..98a20edaa1123f8eb4010bdd8aa078462e9534b8 100644 (file)
@@ -9122,13 +9122,11 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
        return blk_status_to_errno(READ_ONCE(priv.status));
 }
 
-static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
-                                         struct iov_iter *iter,
-                                         u64 start, u64 lockend,
-                                         struct extent_state **cached_state,
-                                         u64 disk_bytenr, u64 disk_io_size,
-                                         size_t count, bool compressed,
-                                         bool *unlocked)
+ssize_t btrfs_encoded_read_regular(struct kiocb *iocb, struct iov_iter *iter,
+                                  u64 start, u64 lockend,
+                                  struct extent_state **cached_state,
+                                  u64 disk_bytenr, u64 disk_io_size,
+                                  size_t count, bool compressed, bool *unlocked)
 {
        struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
        struct extent_io_tree *io_tree = &inode->io_tree;
@@ -9189,15 +9187,16 @@ out:
 }
 
 ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
-                          struct btrfs_ioctl_encoded_io_args *encoded)
+                          struct btrfs_ioctl_encoded_io_args *encoded,
+                          struct extent_state **cached_state,
+                          u64 *disk_bytenr, u64 *disk_io_size)
 {
        struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct extent_io_tree *io_tree = &inode->io_tree;
        ssize_t ret;
        size_t count = iov_iter_count(iter);
-       u64 start, lockend, disk_bytenr, disk_io_size;
-       struct extent_state *cached_state = NULL;
+       u64 start, lockend;
        struct extent_map *em;
        bool unlocked = false;
 
@@ -9223,13 +9222,13 @@ 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);
+               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);
+               unlock_extent(io_tree, start, lockend, cached_state);
                cond_resched();
        }
 
@@ -9249,7 +9248,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
                free_extent_map(em);
                em = NULL;
                ret = btrfs_encoded_read_inline(iocb, iter, start, lockend,
-                                               &cached_state, extent_start,
+                                               cached_state, extent_start,
                                                count, encoded, &unlocked);
                goto out_em;
        }
@@ -9262,12 +9261,12 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
                             inode->vfs_inode.i_size) - iocb->ki_pos;
        if (em->disk_bytenr == EXTENT_MAP_HOLE ||
            (em->flags & EXTENT_FLAG_PREALLOC)) {
-               disk_bytenr = EXTENT_MAP_HOLE;
+               *disk_bytenr = EXTENT_MAP_HOLE;
                count = min_t(u64, count, encoded->len);
                encoded->len = count;
                encoded->unencoded_len = count;
        } else if (extent_map_is_compressed(em)) {
-               disk_bytenr = em->disk_bytenr;
+               *disk_bytenr = em->disk_bytenr;
                /*
                 * Bail if the buffer isn't large enough to return the whole
                 * compressed extent.
@@ -9276,7 +9275,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
                        ret = -ENOBUFS;
                        goto out_em;
                }
-               disk_io_size = em->disk_num_bytes;
+               *disk_io_size = em->disk_num_bytes;
                count = em->disk_num_bytes;
                encoded->unencoded_len = em->ram_bytes;
                encoded->unencoded_offset = iocb->ki_pos - (em->start - em->offset);
@@ -9286,44 +9285,42 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
                        goto out_em;
                encoded->compression = ret;
        } else {
-               disk_bytenr = extent_map_block_start(em) + (start - em->start);
+               *disk_bytenr = extent_map_block_start(em) + (start - em->start);
                if (encoded->len > count)
                        encoded->len = count;
                /*
                 * Don't read beyond what we locked. This also limits the page
                 * allocations that we'll do.
                 */
-               disk_io_size = min(lockend + 1, iocb->ki_pos + encoded->len) - start;
-               count = start + disk_io_size - iocb->ki_pos;
+               *disk_io_size = min(lockend + 1, iocb->ki_pos + encoded->len) - start;
+               count = start + *disk_io_size - iocb->ki_pos;
                encoded->len = count;
                encoded->unencoded_len = count;
-               disk_io_size = ALIGN(disk_io_size, fs_info->sectorsize);
+               *disk_io_size = ALIGN(*disk_io_size, fs_info->sectorsize);
        }
        free_extent_map(em);
        em = NULL;
 
-       if (disk_bytenr == EXTENT_MAP_HOLE) {
-               unlock_extent(io_tree, start, lockend, &cached_state);
+       if (*disk_bytenr == EXTENT_MAP_HOLE) {
+               unlock_extent(io_tree, start, lockend, cached_state);
                btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
                unlocked = true;
                ret = iov_iter_zero(count, iter);
                if (ret != count)
                        ret = -EFAULT;
        } else {
-               ret = btrfs_encoded_read_regular(iocb, iter, start, lockend,
-                                                &cached_state, disk_bytenr,
-                                                disk_io_size, count,
-                                                encoded->compression,
-                                                &unlocked);
+               ret = -EIOCBQUEUED;
+               goto out_em;
        }
 
 out_em:
        free_extent_map(em);
 out_unlock_extent:
-       if (!unlocked)
-               unlock_extent(io_tree, start, lockend, &cached_state);
+       /* Leave inode and extent locked if we need to do a read. */
+       if (!unlocked && ret != -EIOCBQUEUED)
+               unlock_extent(io_tree, start, lockend, cached_state);
 out_unlock_inode:
-       if (!unlocked)
+       if (!unlocked && ret != -EIOCBQUEUED)
                btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
        return ret;
 }
index 28b9b7fda5780be3ea0f1757d4b8c0fa7574dabc..f8ac8bb6c6c743d403cc9955e98566a1fd87127f 100644 (file)
@@ -4513,12 +4513,17 @@ static int btrfs_ioctl_encoded_read(struct file *file, void __user *argp,
        size_t copy_end_kernel = offsetofend(struct btrfs_ioctl_encoded_io_args,
                                             flags);
        size_t copy_end;
+       struct btrfs_inode *inode = BTRFS_I(file_inode(file));
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       struct extent_io_tree *io_tree = &inode->io_tree;
        struct iovec iovstack[UIO_FASTIOV];
        struct iovec *iov = iovstack;
        struct iov_iter iter;
        loff_t pos;
        struct kiocb kiocb;
        ssize_t ret;
+       u64 disk_bytenr, disk_io_size;
+       struct extent_state *cached_state = NULL;
 
        if (!capable(CAP_SYS_ADMIN)) {
                ret = -EPERM;
@@ -4571,7 +4576,32 @@ static int btrfs_ioctl_encoded_read(struct file *file, void __user *argp,
        init_sync_kiocb(&kiocb, file);
        kiocb.ki_pos = pos;
 
-       ret = btrfs_encoded_read(&kiocb, &iter, &args);
+       ret = btrfs_encoded_read(&kiocb, &iter, &args, &cached_state,
+                                &disk_bytenr, &disk_io_size);
+
+       if (ret == -EIOCBQUEUED) {
+               bool unlocked = false;
+               u64 start, lockend, count;
+
+               start = ALIGN_DOWN(kiocb.ki_pos, fs_info->sectorsize);
+               lockend = start + BTRFS_MAX_UNCOMPRESSED - 1;
+
+               if (args.compression)
+                       count = disk_io_size;
+               else
+                       count = args.len;
+
+               ret = btrfs_encoded_read_regular(&kiocb, &iter, start, lockend,
+                                                &cached_state, disk_bytenr,
+                                                disk_io_size, count,
+                                                args.compression, &unlocked);
+
+               if (!unlocked) {
+                       unlock_extent(io_tree, start, lockend, &cached_state);
+                       btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
+               }
+       }
+
        if (ret >= 0) {
                fsnotify_access(file);
                if (copy_to_user(argp + copy_end,