diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-31 15:42:53 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:05 -0400 |
commit | 61b4944018449003ac5f9757f4d125dce519cf51 (patch) | |
tree | 553855996c641a945344db870b6dfd0d2d02086e /fs/btrfs/file-item.c | |
parent | 37d1aeee3990385e9bb436c50c2f7e120a668df6 (diff) |
Btrfs: Fix streaming read performance with checksumming on
Large streaming reads make for large bios, which means each entry on the
list async work queues represents a large amount of data. IO
congestion throttling on the device was kicking in before the async
worker threads decided a single thread was busy and needed some help.
The end result was that a streaming read would result in a single CPU
running at 100% instead of balancing the work off to other CPUs.
This patch also changes the pre-IO checksum lookup done by reads to
work on a per-bio basis instead of a per-page. This results in many
extra btree lookups on large streaming reads. Doing the checksum lookup
right before bio submit allows us to reuse searches while processing
adjacent offsets.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 2311061f070e..a5ff19b34b21 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -134,6 +134,83 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
134 | return ret; | 134 | return ret; |
135 | } | 135 | } |
136 | 136 | ||
137 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | ||
138 | struct bio *bio) | ||
139 | { | ||
140 | u32 sum; | ||
141 | struct bio_vec *bvec = bio->bi_io_vec; | ||
142 | int bio_index = 0; | ||
143 | u64 offset; | ||
144 | u64 item_start_offset = 0; | ||
145 | u64 item_last_offset = 0; | ||
146 | u32 diff; | ||
147 | int ret; | ||
148 | struct btrfs_path *path; | ||
149 | struct btrfs_csum_item *item = NULL; | ||
150 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
151 | |||
152 | path = btrfs_alloc_path(); | ||
153 | path->reada = 2; | ||
154 | |||
155 | WARN_ON(bio->bi_vcnt <= 0); | ||
156 | |||
157 | while(bio_index < bio->bi_vcnt) { | ||
158 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | ||
159 | ret = btrfs_find_ordered_sum(inode, offset, &sum); | ||
160 | if (ret == 0) | ||
161 | goto found; | ||
162 | |||
163 | if (!item || offset < item_start_offset || | ||
164 | offset >= item_last_offset) { | ||
165 | struct btrfs_key found_key; | ||
166 | u32 item_size; | ||
167 | |||
168 | if (item) | ||
169 | btrfs_release_path(root, path); | ||
170 | item = btrfs_lookup_csum(NULL, root, path, | ||
171 | inode->i_ino, offset, 0); | ||
172 | if (IS_ERR(item)) { | ||
173 | ret = PTR_ERR(item); | ||
174 | if (ret == -ENOENT || ret == -EFBIG) | ||
175 | ret = 0; | ||
176 | sum = 0; | ||
177 | printk("no csum found for inode %lu start " | ||
178 | "%llu\n", inode->i_ino, | ||
179 | (unsigned long long)offset); | ||
180 | goto found; | ||
181 | } | ||
182 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||
183 | path->slots[0]); | ||
184 | |||
185 | item_start_offset = found_key.offset; | ||
186 | item_size = btrfs_item_size_nr(path->nodes[0], | ||
187 | path->slots[0]); | ||
188 | item_last_offset = item_start_offset + | ||
189 | (item_size / BTRFS_CRC32_SIZE) * | ||
190 | root->sectorsize; | ||
191 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
192 | struct btrfs_csum_item); | ||
193 | } | ||
194 | /* | ||
195 | * this byte range must be able to fit inside | ||
196 | * a single leaf so it will also fit inside a u32 | ||
197 | */ | ||
198 | diff = offset - item_start_offset; | ||
199 | diff = diff / root->sectorsize; | ||
200 | diff = diff * BTRFS_CRC32_SIZE; | ||
201 | |||
202 | read_extent_buffer(path->nodes[0], &sum, | ||
203 | (unsigned long)item + diff, | ||
204 | BTRFS_CRC32_SIZE); | ||
205 | found: | ||
206 | set_state_private(io_tree, offset, sum); | ||
207 | bio_index++; | ||
208 | bvec++; | ||
209 | } | ||
210 | btrfs_free_path(path); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
137 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | 214 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, |
138 | struct bio *bio) | 215 | struct bio *bio) |
139 | { | 216 | { |