mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
btrfs: change btrfs_encoded_read() so that reading of extent is done by caller
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>
This commit is contained in:
parent
4bca7412b8
commit
26efd44796
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user