aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file-item.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-31 15:42:53 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commit61b4944018449003ac5f9757f4d125dce519cf51 (patch)
tree553855996c641a945344db870b6dfd0d2d02086e /fs/btrfs/file-item.c
parent37d1aeee3990385e9bb436c50c2f7e120a668df6 (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.c77
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
137int 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);
205found:
206 set_state_private(io_tree, offset, sum);
207 bio_index++;
208 bvec++;
209 }
210 btrfs_free_path(path);
211 return 0;
212}
213
137int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 214int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
138 struct bio *bio) 215 struct bio *bio)
139{ 216{