diff options
Diffstat (limited to 'fs/btrfs/file-item.c')
| -rw-r--r-- | fs/btrfs/file-item.c | 85 |
1 files changed, 55 insertions, 30 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index a7bfc9541803..4f53159bdb9d 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "ctree.h" | 23 | #include "ctree.h" |
| 24 | #include "disk-io.h" | 24 | #include "disk-io.h" |
| 25 | #include "transaction.h" | 25 | #include "transaction.h" |
| 26 | #include "volumes.h" | ||
| 26 | #include "print-tree.h" | 27 | #include "print-tree.h" |
| 27 | 28 | ||
| 28 | #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ | 29 | #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ |
| @@ -152,28 +153,54 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
| 152 | return ret; | 153 | return ret; |
| 153 | } | 154 | } |
| 154 | 155 | ||
| 156 | static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) | ||
| 157 | { | ||
| 158 | kfree(bio->csum_allocated); | ||
| 159 | } | ||
| 160 | |||
| 155 | static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | 161 | static int __btrfs_lookup_bio_sums(struct btrfs_root *root, |
| 156 | struct inode *inode, struct bio *bio, | 162 | struct inode *inode, struct bio *bio, |
| 157 | u64 logical_offset, u32 *dst, int dio) | 163 | u64 logical_offset, u32 *dst, int dio) |
| 158 | { | 164 | { |
| 159 | u32 sum[16]; | ||
| 160 | int len; | ||
| 161 | struct bio_vec *bvec = bio->bi_io_vec; | 165 | struct bio_vec *bvec = bio->bi_io_vec; |
| 162 | int bio_index = 0; | 166 | struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); |
| 167 | struct btrfs_csum_item *item = NULL; | ||
| 168 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
| 169 | struct btrfs_path *path; | ||
| 170 | u8 *csum; | ||
| 163 | u64 offset = 0; | 171 | u64 offset = 0; |
| 164 | u64 item_start_offset = 0; | 172 | u64 item_start_offset = 0; |
| 165 | u64 item_last_offset = 0; | 173 | u64 item_last_offset = 0; |
| 166 | u64 disk_bytenr; | 174 | u64 disk_bytenr; |
| 167 | u32 diff; | 175 | u32 diff; |
| 168 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | 176 | int nblocks; |
| 177 | int bio_index = 0; | ||
| 169 | int count; | 178 | int count; |
| 170 | struct btrfs_path *path; | 179 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
| 171 | struct btrfs_csum_item *item = NULL; | ||
| 172 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
| 173 | 180 | ||
| 174 | path = btrfs_alloc_path(); | 181 | path = btrfs_alloc_path(); |
| 175 | if (!path) | 182 | if (!path) |
| 176 | return -ENOMEM; | 183 | return -ENOMEM; |
| 184 | |||
| 185 | nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits; | ||
| 186 | if (!dst) { | ||
| 187 | if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { | ||
| 188 | btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size, | ||
| 189 | GFP_NOFS); | ||
| 190 | if (!btrfs_bio->csum_allocated) { | ||
| 191 | btrfs_free_path(path); | ||
| 192 | return -ENOMEM; | ||
| 193 | } | ||
| 194 | btrfs_bio->csum = btrfs_bio->csum_allocated; | ||
| 195 | btrfs_bio->end_io = btrfs_io_bio_endio_readpage; | ||
| 196 | } else { | ||
| 197 | btrfs_bio->csum = btrfs_bio->csum_inline; | ||
| 198 | } | ||
| 199 | csum = btrfs_bio->csum; | ||
| 200 | } else { | ||
| 201 | csum = (u8 *)dst; | ||
| 202 | } | ||
| 203 | |||
| 177 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) | 204 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) |
| 178 | path->reada = 2; | 205 | path->reada = 2; |
| 179 | 206 | ||
| @@ -194,11 +221,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
| 194 | if (dio) | 221 | if (dio) |
| 195 | offset = logical_offset; | 222 | offset = logical_offset; |
| 196 | while (bio_index < bio->bi_vcnt) { | 223 | while (bio_index < bio->bi_vcnt) { |
| 197 | len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index); | ||
| 198 | if (!dio) | 224 | if (!dio) |
| 199 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 225 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
| 200 | count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, | 226 | count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, |
| 201 | len); | 227 | (u32 *)csum, nblocks); |
| 202 | if (count) | 228 | if (count) |
| 203 | goto found; | 229 | goto found; |
| 204 | 230 | ||
| @@ -213,7 +239,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
| 213 | path, disk_bytenr, 0); | 239 | path, disk_bytenr, 0); |
| 214 | if (IS_ERR(item)) { | 240 | if (IS_ERR(item)) { |
| 215 | count = 1; | 241 | count = 1; |
| 216 | sum[0] = 0; | 242 | memset(csum, 0, csum_size); |
| 217 | if (BTRFS_I(inode)->root->root_key.objectid == | 243 | if (BTRFS_I(inode)->root->root_key.objectid == |
| 218 | BTRFS_DATA_RELOC_TREE_OBJECTID) { | 244 | BTRFS_DATA_RELOC_TREE_OBJECTID) { |
| 219 | set_extent_bits(io_tree, offset, | 245 | set_extent_bits(io_tree, offset, |
| @@ -222,9 +248,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
| 222 | } else { | 248 | } else { |
| 223 | printk(KERN_INFO "btrfs no csum found " | 249 | printk(KERN_INFO "btrfs no csum found " |
| 224 | "for inode %llu start %llu\n", | 250 | "for inode %llu start %llu\n", |
| 225 | (unsigned long long) | 251 | btrfs_ino(inode), offset); |
| 226 | btrfs_ino(inode), | ||
| 227 | (unsigned long long)offset); | ||
| 228 | } | 252 | } |
| 229 | item = NULL; | 253 | item = NULL; |
| 230 | btrfs_release_path(path); | 254 | btrfs_release_path(path); |
| @@ -249,23 +273,14 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
| 249 | diff = disk_bytenr - item_start_offset; | 273 | diff = disk_bytenr - item_start_offset; |
| 250 | diff = diff / root->sectorsize; | 274 | diff = diff / root->sectorsize; |
| 251 | diff = diff * csum_size; | 275 | diff = diff * csum_size; |
| 252 | count = min_t(int, len, (item_last_offset - disk_bytenr) >> | 276 | count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> |
| 253 | inode->i_sb->s_blocksize_bits); | 277 | inode->i_sb->s_blocksize_bits); |
| 254 | read_extent_buffer(path->nodes[0], sum, | 278 | read_extent_buffer(path->nodes[0], csum, |
| 255 | ((unsigned long)item) + diff, | 279 | ((unsigned long)item) + diff, |
| 256 | csum_size * count); | 280 | csum_size * count); |
| 257 | found: | 281 | found: |
| 258 | if (dst) { | 282 | csum += count * csum_size; |
| 259 | memcpy(dst, sum, count * csum_size); | 283 | nblocks -= count; |
| 260 | dst += count; | ||
| 261 | } else { | ||
| 262 | if (dio) | ||
| 263 | extent_cache_csums_dio(io_tree, offset, sum, | ||
| 264 | count); | ||
| 265 | else | ||
| 266 | extent_cache_csums(io_tree, bio, bio_index, sum, | ||
| 267 | count); | ||
| 268 | } | ||
| 269 | while (count--) { | 284 | while (count--) { |
| 270 | disk_bytenr += bvec->bv_len; | 285 | disk_bytenr += bvec->bv_len; |
| 271 | offset += bvec->bv_len; | 286 | offset += bvec->bv_len; |
| @@ -284,9 +299,19 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
| 284 | } | 299 | } |
| 285 | 300 | ||
| 286 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, | 301 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, |
| 287 | struct bio *bio, u64 offset) | 302 | struct btrfs_dio_private *dip, struct bio *bio, |
| 303 | u64 offset) | ||
| 288 | { | 304 | { |
| 289 | return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); | 305 | int len = (bio->bi_sector << 9) - dip->disk_bytenr; |
| 306 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | len >>= inode->i_sb->s_blocksize_bits; | ||
| 310 | len *= csum_size; | ||
| 311 | |||
| 312 | ret = __btrfs_lookup_bio_sums(root, inode, bio, offset, | ||
| 313 | (u32 *)(dip->csum + len), 1); | ||
| 314 | return ret; | ||
| 290 | } | 315 | } |
| 291 | 316 | ||
| 292 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 317 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |
