On Tue, Mar 17, 2015 at 8:38 PM, Josef Bacik <jbacik@xxxxxx> wrote:
> We are keeping track of how many extents we need to reserve properly based on
> the amount we want to write, but we were still incrementing outstanding_extents
> if we wrote less than what we requested. This isn't quite right since we will
> be limited to our max extent size. So instead lets do something horrible! Keep
> track of how many outstanding_extents we reserved, and decrement each time we
> allocate an extent. If we use our entire reserve make sure to jack up
> outstanding_extents on the inode so the accounting works out properly. Thanks,
>
> Reported-by: Filipe Manana <fdmanana@xxxxxxxx>
> Signed-off-by: Josef Bacik <jbacik@xxxxxx>
Tested-by: Filipe Manana <fdmanana@xxxxxxxx>
Reviewed-by: Filipe Manana <fdmanana@xxxxxxxx>
> ---
> fs/btrfs/inode.c | 37 +++++++++++++++++++++++++++++++++++--
> 1 file changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 3717b3d..aa1fb53 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -7239,7 +7239,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
> u64 start = iblock << inode->i_blkbits;
> u64 lockstart, lockend;
> u64 len = bh_result->b_size;
> - u64 orig_len = len;
> + u64 *outstanding_extents = NULL;
> int unlock_bits = EXTENT_LOCKED;
> int ret = 0;
>
> @@ -7251,6 +7251,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
> lockstart = start;
> lockend = start + len - 1;
>
> + if (current->journal_info) {
> + /*
> + * Need to pull our outstanding extents and set journal_info to NULL so
> + * that anything that needs to check if there's a transction doesn't get
> + * confused.
> + */
> + outstanding_extents = current->journal_info;
> + current->journal_info = NULL;
> + }
> +
> /*
> * If this errors out it's because we couldn't invalidate pagecache for
> * this range and we need to fallback to buffered.
> @@ -7374,11 +7384,20 @@ unlock:
> if (start + len > i_size_read(inode))
> i_size_write(inode, start + len);
>
> - if (len < orig_len) {
> + /*
> + * If we have an outstanding_extents count still set then we're
> + * within our reservation, otherwise we need to adjust our inode
> + * counter appropriately.
> + */
> + if (*outstanding_extents) {
> + (*outstanding_extents)--;
> + } else {
> spin_lock(&BTRFS_I(inode)->lock);
> BTRFS_I(inode)->outstanding_extents++;
> spin_unlock(&BTRFS_I(inode)->lock);
> }
> +
> + current->journal_info = outstanding_extents;
> btrfs_free_reserved_data_space(inode, len);
> }
>
> @@ -7402,6 +7421,8 @@ unlock:
> unlock_err:
> clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
> unlock_bits, 1, 0, &cached_state, GFP_NOFS);
> + if (outstanding_extents)
> + current->journal_info = outstanding_extents;
> return ret;
> }
>
> @@ -8101,6 +8122,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
> {
> struct file *file = iocb->ki_filp;
> struct inode *inode = file->f_mapping->host;
> + u64 outstanding_extents = 0;
> size_t count = 0;
> int flags = 0;
> bool wakeup = true;
> @@ -8138,6 +8160,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
> ret = btrfs_delalloc_reserve_space(inode, count);
> if (ret)
> goto out;
> + outstanding_extents = div64_u64(count +
> + BTRFS_MAX_EXTENT_SIZE - 1,
> + BTRFS_MAX_EXTENT_SIZE);
> +
> + /*
> + * We need to know how many extents we reserved so that we can
> + * do the accounting properly if we go over the number we
> + * originally calculated. Abuse current->journal_info for this.
> + */
> + current->journal_info = &outstanding_extents;
> } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
> &BTRFS_I(inode)->runtime_flags)) {
> inode_dio_done(inode);
> @@ -8150,6 +8182,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
> iter, offset, btrfs_get_blocks_direct, NULL,
> btrfs_submit_direct, flags);
> if (rw & WRITE) {
> + current->journal_info = NULL;
> if (ret < 0 && ret != -EIOCBQUEUED)
> btrfs_delalloc_release_space(inode, count);
> else if (ret >= 0 && (size_t)ret < count)
> --
> 1.8.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Filipe David Manana,
"Reasonable men adapt themselves to the world.
Unreasonable men adapt the world to themselves.
That's why all progress depends on unreasonable men."
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html