diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/inode.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3717b3d4c2ce..aa1fb534f69f 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, | |||
7239 | u64 start = iblock << inode->i_blkbits; | 7239 | u64 start = iblock << inode->i_blkbits; |
7240 | u64 lockstart, lockend; | 7240 | u64 lockstart, lockend; |
7241 | u64 len = bh_result->b_size; | 7241 | u64 len = bh_result->b_size; |
7242 | u64 orig_len = len; | 7242 | u64 *outstanding_extents = NULL; |
7243 | int unlock_bits = EXTENT_LOCKED; | 7243 | int unlock_bits = EXTENT_LOCKED; |
7244 | int ret = 0; | 7244 | int ret = 0; |
7245 | 7245 | ||
@@ -7251,6 +7251,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
7251 | lockstart = start; | 7251 | lockstart = start; |
7252 | lockend = start + len - 1; | 7252 | lockend = start + len - 1; |
7253 | 7253 | ||
7254 | if (current->journal_info) { | ||
7255 | /* | ||
7256 | * Need to pull our outstanding extents and set journal_info to NULL so | ||
7257 | * that anything that needs to check if there's a transction doesn't get | ||
7258 | * confused. | ||
7259 | */ | ||
7260 | outstanding_extents = current->journal_info; | ||
7261 | current->journal_info = NULL; | ||
7262 | } | ||
7263 | |||
7254 | /* | 7264 | /* |
7255 | * If this errors out it's because we couldn't invalidate pagecache for | 7265 | * If this errors out it's because we couldn't invalidate pagecache for |
7256 | * this range and we need to fallback to buffered. | 7266 | * this range and we need to fallback to buffered. |
@@ -7374,11 +7384,20 @@ unlock: | |||
7374 | if (start + len > i_size_read(inode)) | 7384 | if (start + len > i_size_read(inode)) |
7375 | i_size_write(inode, start + len); | 7385 | i_size_write(inode, start + len); |
7376 | 7386 | ||
7377 | if (len < orig_len) { | 7387 | /* |
7388 | * If we have an outstanding_extents count still set then we're | ||
7389 | * within our reservation, otherwise we need to adjust our inode | ||
7390 | * counter appropriately. | ||
7391 | */ | ||
7392 | if (*outstanding_extents) { | ||
7393 | (*outstanding_extents)--; | ||
7394 | } else { | ||
7378 | spin_lock(&BTRFS_I(inode)->lock); | 7395 | spin_lock(&BTRFS_I(inode)->lock); |
7379 | BTRFS_I(inode)->outstanding_extents++; | 7396 | BTRFS_I(inode)->outstanding_extents++; |
7380 | spin_unlock(&BTRFS_I(inode)->lock); | 7397 | spin_unlock(&BTRFS_I(inode)->lock); |
7381 | } | 7398 | } |
7399 | |||
7400 | current->journal_info = outstanding_extents; | ||
7382 | btrfs_free_reserved_data_space(inode, len); | 7401 | btrfs_free_reserved_data_space(inode, len); |
7383 | } | 7402 | } |
7384 | 7403 | ||
@@ -7402,6 +7421,8 @@ unlock: | |||
7402 | unlock_err: | 7421 | unlock_err: |
7403 | clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, | 7422 | clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, |
7404 | unlock_bits, 1, 0, &cached_state, GFP_NOFS); | 7423 | unlock_bits, 1, 0, &cached_state, GFP_NOFS); |
7424 | if (outstanding_extents) | ||
7425 | current->journal_info = outstanding_extents; | ||
7405 | return ret; | 7426 | return ret; |
7406 | } | 7427 | } |
7407 | 7428 | ||
@@ -8101,6 +8122,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
8101 | { | 8122 | { |
8102 | struct file *file = iocb->ki_filp; | 8123 | struct file *file = iocb->ki_filp; |
8103 | struct inode *inode = file->f_mapping->host; | 8124 | struct inode *inode = file->f_mapping->host; |
8125 | u64 outstanding_extents = 0; | ||
8104 | size_t count = 0; | 8126 | size_t count = 0; |
8105 | int flags = 0; | 8127 | int flags = 0; |
8106 | bool wakeup = true; | 8128 | bool wakeup = true; |
@@ -8138,6 +8160,16 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
8138 | ret = btrfs_delalloc_reserve_space(inode, count); | 8160 | ret = btrfs_delalloc_reserve_space(inode, count); |
8139 | if (ret) | 8161 | if (ret) |
8140 | goto out; | 8162 | goto out; |
8163 | outstanding_extents = div64_u64(count + | ||
8164 | BTRFS_MAX_EXTENT_SIZE - 1, | ||
8165 | BTRFS_MAX_EXTENT_SIZE); | ||
8166 | |||
8167 | /* | ||
8168 | * We need to know how many extents we reserved so that we can | ||
8169 | * do the accounting properly if we go over the number we | ||
8170 | * originally calculated. Abuse current->journal_info for this. | ||
8171 | */ | ||
8172 | current->journal_info = &outstanding_extents; | ||
8141 | } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK, | 8173 | } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK, |
8142 | &BTRFS_I(inode)->runtime_flags)) { | 8174 | &BTRFS_I(inode)->runtime_flags)) { |
8143 | inode_dio_done(inode); | 8175 | inode_dio_done(inode); |
@@ -8150,6 +8182,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
8150 | iter, offset, btrfs_get_blocks_direct, NULL, | 8182 | iter, offset, btrfs_get_blocks_direct, NULL, |
8151 | btrfs_submit_direct, flags); | 8183 | btrfs_submit_direct, flags); |
8152 | if (rw & WRITE) { | 8184 | if (rw & WRITE) { |
8185 | current->journal_info = NULL; | ||
8153 | if (ret < 0 && ret != -EIOCBQUEUED) | 8186 | if (ret < 0 && ret != -EIOCBQUEUED) |
8154 | btrfs_delalloc_release_space(inode, count); | 8187 | btrfs_delalloc_release_space(inode, count); |
8155 | else if (ret >= 0 && (size_t)ret < count) | 8188 | else if (ret >= 0 && (size_t)ret < count) |