diff options
author | Josef Bacik <jbacik@fusionio.com> | 2012-08-03 16:49:19 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-08-28 16:53:30 -0400 |
commit | c329861da40623cd838b8c9ee31a850242fd88cf (patch) | |
tree | d395b6dae57c00c25f1b890db1f39871575a7013 | |
parent | 99f5944b8477914406173b47b4f261356286730b (diff) |
Btrfs: don't allocate a seperate csums array for direct reads
We've been allocating a big array for csums instead of storing them in the
io_tree like we do for buffered reads because previously we were locking the
entire range, so we didn't have an extent state for each sector of the
range. But now that we do the range locking as we map the buffers we can
limit the mapping lenght to sectorsize and use the private part of the
io_tree for our csums. This allows us to avoid an extra memory allocation
for direct reads which could incur latency. Thanks,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 45 |
3 files changed, 19 insertions, 32 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index adb1cd7ceb9b..348196350bf0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3192,7 +3192,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, | |||
3192 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | 3192 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, |
3193 | struct bio *bio, u32 *dst); | 3193 | struct bio *bio, u32 *dst); |
3194 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, | 3194 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, |
3195 | struct bio *bio, u64 logical_offset, u32 *dst); | 3195 | struct bio *bio, u64 logical_offset); |
3196 | int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, | 3196 | int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, |
3197 | struct btrfs_root *root, | 3197 | struct btrfs_root *root, |
3198 | u64 objectid, u64 pos, | 3198 | u64 objectid, u64 pos, |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index b45b9de0c21d..857d93cd01dc 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -272,9 +272,9 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
272 | } | 272 | } |
273 | 273 | ||
274 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, | 274 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, |
275 | struct bio *bio, u64 offset, u32 *dst) | 275 | struct bio *bio, u64 offset) |
276 | { | 276 | { |
277 | return __btrfs_lookup_bio_sums(root, inode, bio, offset, dst, 1); | 277 | return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); |
278 | } | 278 | } |
279 | 279 | ||
280 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 280 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 09182449cbdf..2d65c52b0944 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -5847,15 +5847,18 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
5847 | int unlock_bits = EXTENT_LOCKED; | 5847 | int unlock_bits = EXTENT_LOCKED; |
5848 | int ret; | 5848 | int ret; |
5849 | 5849 | ||
5850 | lockstart = start; | ||
5851 | lockend = start + len - 1; | ||
5852 | if (create) { | 5850 | if (create) { |
5853 | ret = btrfs_delalloc_reserve_space(inode, len); | 5851 | ret = btrfs_delalloc_reserve_space(inode, len); |
5854 | if (ret) | 5852 | if (ret) |
5855 | return ret; | 5853 | return ret; |
5856 | unlock_bits |= EXTENT_DELALLOC | EXTENT_DIRTY; | 5854 | unlock_bits |= EXTENT_DELALLOC | EXTENT_DIRTY; |
5855 | } else { | ||
5856 | len = min_t(u64, len, root->sectorsize); | ||
5857 | } | 5857 | } |
5858 | 5858 | ||
5859 | lockstart = start; | ||
5860 | lockend = start + len - 1; | ||
5861 | |||
5859 | /* | 5862 | /* |
5860 | * If this errors out it's because we couldn't invalidate pagecache for | 5863 | * If this errors out it's because we couldn't invalidate pagecache for |
5861 | * this range and we need to fallback to buffered. | 5864 | * this range and we need to fallback to buffered. |
@@ -6015,7 +6018,6 @@ struct btrfs_dio_private { | |||
6015 | u64 logical_offset; | 6018 | u64 logical_offset; |
6016 | u64 disk_bytenr; | 6019 | u64 disk_bytenr; |
6017 | u64 bytes; | 6020 | u64 bytes; |
6018 | u32 *csums; | ||
6019 | void *private; | 6021 | void *private; |
6020 | 6022 | ||
6021 | /* number of bios pending for this dio */ | 6023 | /* number of bios pending for this dio */ |
@@ -6035,7 +6037,6 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) | |||
6035 | struct inode *inode = dip->inode; | 6037 | struct inode *inode = dip->inode; |
6036 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6038 | struct btrfs_root *root = BTRFS_I(inode)->root; |
6037 | u64 start; | 6039 | u64 start; |
6038 | u32 *private = dip->csums; | ||
6039 | 6040 | ||
6040 | start = dip->logical_offset; | 6041 | start = dip->logical_offset; |
6041 | do { | 6042 | do { |
@@ -6043,8 +6044,12 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) | |||
6043 | struct page *page = bvec->bv_page; | 6044 | struct page *page = bvec->bv_page; |
6044 | char *kaddr; | 6045 | char *kaddr; |
6045 | u32 csum = ~(u32)0; | 6046 | u32 csum = ~(u32)0; |
6047 | u64 private = ~(u32)0; | ||
6046 | unsigned long flags; | 6048 | unsigned long flags; |
6047 | 6049 | ||
6050 | if (get_state_private(&BTRFS_I(inode)->io_tree, | ||
6051 | start, &private)) | ||
6052 | goto failed; | ||
6048 | local_irq_save(flags); | 6053 | local_irq_save(flags); |
6049 | kaddr = kmap_atomic(page); | 6054 | kaddr = kmap_atomic(page); |
6050 | csum = btrfs_csum_data(root, kaddr + bvec->bv_offset, | 6055 | csum = btrfs_csum_data(root, kaddr + bvec->bv_offset, |
@@ -6054,18 +6059,18 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) | |||
6054 | local_irq_restore(flags); | 6059 | local_irq_restore(flags); |
6055 | 6060 | ||
6056 | flush_dcache_page(bvec->bv_page); | 6061 | flush_dcache_page(bvec->bv_page); |
6057 | if (csum != *private) { | 6062 | if (csum != private) { |
6063 | failed: | ||
6058 | printk(KERN_ERR "btrfs csum failed ino %llu off" | 6064 | printk(KERN_ERR "btrfs csum failed ino %llu off" |
6059 | " %llu csum %u private %u\n", | 6065 | " %llu csum %u private %u\n", |
6060 | (unsigned long long)btrfs_ino(inode), | 6066 | (unsigned long long)btrfs_ino(inode), |
6061 | (unsigned long long)start, | 6067 | (unsigned long long)start, |
6062 | csum, *private); | 6068 | csum, (unsigned)private); |
6063 | err = -EIO; | 6069 | err = -EIO; |
6064 | } | 6070 | } |
6065 | } | 6071 | } |
6066 | 6072 | ||
6067 | start += bvec->bv_len; | 6073 | start += bvec->bv_len; |
6068 | private++; | ||
6069 | bvec++; | 6074 | bvec++; |
6070 | } while (bvec <= bvec_end); | 6075 | } while (bvec <= bvec_end); |
6071 | 6076 | ||
@@ -6073,7 +6078,6 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) | |||
6073 | dip->logical_offset + dip->bytes - 1); | 6078 | dip->logical_offset + dip->bytes - 1); |
6074 | bio->bi_private = dip->private; | 6079 | bio->bi_private = dip->private; |
6075 | 6080 | ||
6076 | kfree(dip->csums); | ||
6077 | kfree(dip); | 6081 | kfree(dip); |
6078 | 6082 | ||
6079 | /* If we had a csum failure make sure to clear the uptodate flag */ | 6083 | /* If we had a csum failure make sure to clear the uptodate flag */ |
@@ -6179,7 +6183,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, | |||
6179 | 6183 | ||
6180 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | 6184 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, |
6181 | int rw, u64 file_offset, int skip_sum, | 6185 | int rw, u64 file_offset, int skip_sum, |
6182 | u32 *csums, int async_submit) | 6186 | int async_submit) |
6183 | { | 6187 | { |
6184 | int write = rw & REQ_WRITE; | 6188 | int write = rw & REQ_WRITE; |
6185 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6189 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -6212,8 +6216,7 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
6212 | if (ret) | 6216 | if (ret) |
6213 | goto err; | 6217 | goto err; |
6214 | } else if (!skip_sum) { | 6218 | } else if (!skip_sum) { |
6215 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, | 6219 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset); |
6216 | file_offset, csums); | ||
6217 | if (ret) | 6220 | if (ret) |
6218 | goto err; | 6221 | goto err; |
6219 | } | 6222 | } |
@@ -6239,10 +6242,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6239 | u64 submit_len = 0; | 6242 | u64 submit_len = 0; |
6240 | u64 map_length; | 6243 | u64 map_length; |
6241 | int nr_pages = 0; | 6244 | int nr_pages = 0; |
6242 | u32 *csums = dip->csums; | ||
6243 | int ret = 0; | 6245 | int ret = 0; |
6244 | int async_submit = 0; | 6246 | int async_submit = 0; |
6245 | int write = rw & REQ_WRITE; | ||
6246 | 6247 | ||
6247 | map_length = orig_bio->bi_size; | 6248 | map_length = orig_bio->bi_size; |
6248 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, | 6249 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, |
@@ -6278,16 +6279,13 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6278 | atomic_inc(&dip->pending_bios); | 6279 | atomic_inc(&dip->pending_bios); |
6279 | ret = __btrfs_submit_dio_bio(bio, inode, rw, | 6280 | ret = __btrfs_submit_dio_bio(bio, inode, rw, |
6280 | file_offset, skip_sum, | 6281 | file_offset, skip_sum, |
6281 | csums, async_submit); | 6282 | async_submit); |
6282 | if (ret) { | 6283 | if (ret) { |
6283 | bio_put(bio); | 6284 | bio_put(bio); |
6284 | atomic_dec(&dip->pending_bios); | 6285 | atomic_dec(&dip->pending_bios); |
6285 | goto out_err; | 6286 | goto out_err; |
6286 | } | 6287 | } |
6287 | 6288 | ||
6288 | /* Write's use the ordered csums */ | ||
6289 | if (!write && !skip_sum) | ||
6290 | csums = csums + nr_pages; | ||
6291 | start_sector += submit_len >> 9; | 6289 | start_sector += submit_len >> 9; |
6292 | file_offset += submit_len; | 6290 | file_offset += submit_len; |
6293 | 6291 | ||
@@ -6317,7 +6315,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6317 | 6315 | ||
6318 | submit: | 6316 | submit: |
6319 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, | 6317 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, |
6320 | csums, async_submit); | 6318 | async_submit); |
6321 | if (!ret) | 6319 | if (!ret) |
6322 | return 0; | 6320 | return 0; |
6323 | 6321 | ||
@@ -6353,17 +6351,6 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
6353 | ret = -ENOMEM; | 6351 | ret = -ENOMEM; |
6354 | goto free_ordered; | 6352 | goto free_ordered; |
6355 | } | 6353 | } |
6356 | dip->csums = NULL; | ||
6357 | |||
6358 | /* Write's use the ordered csum stuff, so we don't need dip->csums */ | ||
6359 | if (!write && !skip_sum) { | ||
6360 | dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS); | ||
6361 | if (!dip->csums) { | ||
6362 | kfree(dip); | ||
6363 | ret = -ENOMEM; | ||
6364 | goto free_ordered; | ||
6365 | } | ||
6366 | } | ||
6367 | 6354 | ||
6368 | dip->private = bio->bi_private; | 6355 | dip->private = bio->bi_private; |
6369 | dip->inode = inode; | 6356 | dip->inode = inode; |