diff options
| -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) |
