diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-22 13:26:46 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | e1c4b7451e22f5b0a9fbccfa560ee7b80c35b8cd (patch) | |
tree | 4e9d3f9d0a8084ad6282965fa190200de3a91d7d /fs/btrfs | |
parent | 409c6118d39cb2d8666bee3d61a1a9ae5bbd4f5d (diff) |
Fix btrfs_get_extent and get_block corner cases, and disable O_DIRECT reads
The generic O_DIRECT code assumes all the bios have the same bdev,
which isn't true for multi-device btrfs.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent_io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 32 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 2 |
3 files changed, 23 insertions, 12 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 81f8b4fd069b..6e4bf029c6d4 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1694,6 +1694,7 @@ extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, | |||
1694 | } | 1694 | } |
1695 | 1695 | ||
1696 | if (bio) { | 1696 | if (bio) { |
1697 | bio->bi_size = 0; | ||
1697 | bio->bi_bdev = bdev; | 1698 | bio->bi_bdev = bdev; |
1698 | bio->bi_sector = first_sector; | 1699 | bio->bi_sector = first_sector; |
1699 | } | 1700 | } |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e875c7c8a647..abfe86df02d2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -494,6 +494,7 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio, | |||
494 | bio->bi_end_io = failed_bio->bi_end_io; | 494 | bio->bi_end_io = failed_bio->bi_end_io; |
495 | bio->bi_sector = failrec->logical >> 9; | 495 | bio->bi_sector = failrec->logical >> 9; |
496 | bio->bi_bdev = failed_bio->bi_bdev; | 496 | bio->bi_bdev = failed_bio->bi_bdev; |
497 | bio->bi_size = 0; | ||
497 | bio_add_page(bio, page, failrec->len, start - page_offset(page)); | 498 | bio_add_page(bio, page, failrec->len, start - page_offset(page)); |
498 | btrfs_submit_bio_hook(inode, READ, bio, failrec->last_mirror); | 499 | btrfs_submit_bio_hook(inode, READ, bio, failrec->last_mirror); |
499 | return 0; | 500 | return 0; |
@@ -2187,12 +2188,9 @@ again: | |||
2187 | spin_unlock(&em_tree->lock); | 2188 | spin_unlock(&em_tree->lock); |
2188 | 2189 | ||
2189 | if (em) { | 2190 | if (em) { |
2190 | if (em->start > start) { | 2191 | if (em->start > start || em->start + em->len <= start) |
2191 | printk("get_extent lookup [%Lu %Lu] em [%Lu %Lu]\n", | 2192 | free_extent_map(em); |
2192 | start, len, em->start, em->len); | 2193 | else if (em->block_start == EXTENT_MAP_INLINE && page) |
2193 | WARN_ON(1); | ||
2194 | } | ||
2195 | if (em->block_start == EXTENT_MAP_INLINE && page) | ||
2196 | free_extent_map(em); | 2194 | free_extent_map(em); |
2197 | else | 2195 | else |
2198 | goto out; | 2196 | goto out; |
@@ -2340,7 +2338,6 @@ insert: | |||
2340 | err = 0; | 2338 | err = 0; |
2341 | spin_lock(&em_tree->lock); | 2339 | spin_lock(&em_tree->lock); |
2342 | ret = add_extent_mapping(em_tree, em); | 2340 | ret = add_extent_mapping(em_tree, em); |
2343 | |||
2344 | /* it is possible that someone inserted the extent into the tree | 2341 | /* it is possible that someone inserted the extent into the tree |
2345 | * while we had the lock dropped. It is also possible that | 2342 | * while we had the lock dropped. It is also possible that |
2346 | * an overlapping map exists in the tree | 2343 | * an overlapping map exists in the tree |
@@ -2348,6 +2345,11 @@ insert: | |||
2348 | if (ret == -EEXIST) { | 2345 | if (ret == -EEXIST) { |
2349 | struct extent_map *existing; | 2346 | struct extent_map *existing; |
2350 | existing = lookup_extent_mapping(em_tree, start, len); | 2347 | existing = lookup_extent_mapping(em_tree, start, len); |
2348 | if (existing && (existing->start > start || | ||
2349 | existing->start + existing->len <= start)) { | ||
2350 | free_extent_map(existing); | ||
2351 | existing = NULL; | ||
2352 | } | ||
2351 | if (!existing) { | 2353 | if (!existing) { |
2352 | existing = lookup_extent_mapping(em_tree, em->start, | 2354 | existing = lookup_extent_mapping(em_tree, em->start, |
2353 | em->len); | 2355 | em->len); |
@@ -2388,6 +2390,7 @@ out: | |||
2388 | return em; | 2390 | return em; |
2389 | } | 2391 | } |
2390 | 2392 | ||
2393 | #if 0 /* waiting for O_DIRECT reads */ | ||
2391 | static int btrfs_get_block(struct inode *inode, sector_t iblock, | 2394 | static int btrfs_get_block(struct inode *inode, sector_t iblock, |
2392 | struct buffer_head *bh_result, int create) | 2395 | struct buffer_head *bh_result, int create) |
2393 | { | 2396 | { |
@@ -2405,22 +2408,24 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, | |||
2405 | if (!em || IS_ERR(em)) | 2408 | if (!em || IS_ERR(em)) |
2406 | goto out; | 2409 | goto out; |
2407 | 2410 | ||
2408 | if (em->start > start || em->start + em->len <= start) | 2411 | if (em->start > start || em->start + em->len <= start) { |
2409 | goto out; | 2412 | goto out; |
2413 | } | ||
2410 | 2414 | ||
2411 | if (em->block_start == EXTENT_MAP_INLINE) { | 2415 | if (em->block_start == EXTENT_MAP_INLINE) { |
2412 | ret = -EINVAL; | 2416 | ret = -EINVAL; |
2413 | goto out; | 2417 | goto out; |
2414 | } | 2418 | } |
2415 | 2419 | ||
2420 | len = em->start + em->len - start; | ||
2421 | len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size))); | ||
2422 | |||
2416 | if (em->block_start == EXTENT_MAP_HOLE || | 2423 | if (em->block_start == EXTENT_MAP_HOLE || |
2417 | em->block_start == EXTENT_MAP_DELALLOC) { | 2424 | em->block_start == EXTENT_MAP_DELALLOC) { |
2425 | bh_result->b_size = len; | ||
2418 | goto out; | 2426 | goto out; |
2419 | } | 2427 | } |
2420 | 2428 | ||
2421 | len = em->start + em->len - start; | ||
2422 | len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size))); | ||
2423 | |||
2424 | logical = start - em->start; | 2429 | logical = start - em->start; |
2425 | logical = em->block_start + logical; | 2430 | logical = em->block_start + logical; |
2426 | 2431 | ||
@@ -2430,6 +2435,7 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, | |||
2430 | BUG_ON(ret); | 2435 | BUG_ON(ret); |
2431 | bh_result->b_blocknr = multi->stripes[0].physical >> inode->i_blkbits; | 2436 | bh_result->b_blocknr = multi->stripes[0].physical >> inode->i_blkbits; |
2432 | bh_result->b_size = min(map_length, len); | 2437 | bh_result->b_size = min(map_length, len); |
2438 | |||
2433 | bh_result->b_bdev = multi->stripes[0].dev->bdev; | 2439 | bh_result->b_bdev = multi->stripes[0].dev->bdev; |
2434 | set_buffer_mapped(bh_result); | 2440 | set_buffer_mapped(bh_result); |
2435 | kfree(multi); | 2441 | kfree(multi); |
@@ -2437,11 +2443,14 @@ out: | |||
2437 | free_extent_map(em); | 2443 | free_extent_map(em); |
2438 | return ret; | 2444 | return ret; |
2439 | } | 2445 | } |
2446 | #endif | ||
2440 | 2447 | ||
2441 | static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | 2448 | static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, |
2442 | const struct iovec *iov, loff_t offset, | 2449 | const struct iovec *iov, loff_t offset, |
2443 | unsigned long nr_segs) | 2450 | unsigned long nr_segs) |
2444 | { | 2451 | { |
2452 | return -EINVAL; | ||
2453 | #if 0 | ||
2445 | struct file *file = iocb->ki_filp; | 2454 | struct file *file = iocb->ki_filp; |
2446 | struct inode *inode = file->f_mapping->host; | 2455 | struct inode *inode = file->f_mapping->host; |
2447 | 2456 | ||
@@ -2450,6 +2459,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
2450 | 2459 | ||
2451 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 2460 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
2452 | offset, nr_segs, btrfs_get_block, NULL); | 2461 | offset, nr_segs, btrfs_get_block, NULL); |
2462 | #endif | ||
2453 | } | 2463 | } |
2454 | 2464 | ||
2455 | static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock) | 2465 | static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock) |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5619e50583e3..bccb5566fd84 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -1161,7 +1161,6 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, | |||
1161 | int total_devs = 1; | 1161 | int total_devs = 1; |
1162 | 1162 | ||
1163 | length = bio->bi_size; | 1163 | length = bio->bi_size; |
1164 | |||
1165 | map_tree = &root->fs_info->mapping_tree; | 1164 | map_tree = &root->fs_info->mapping_tree; |
1166 | map_length = length; | 1165 | map_length = length; |
1167 | 1166 | ||
@@ -1192,6 +1191,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, | |||
1192 | } | 1191 | } |
1193 | bio->bi_sector = multi->stripes[dev_nr].physical >> 9; | 1192 | bio->bi_sector = multi->stripes[dev_nr].physical >> 9; |
1194 | dev = multi->stripes[dev_nr].dev; | 1193 | dev = multi->stripes[dev_nr].dev; |
1194 | |||
1195 | bio->bi_bdev = dev->bdev; | 1195 | bio->bi_bdev = dev->bdev; |
1196 | spin_lock(&dev->io_lock); | 1196 | spin_lock(&dev->io_lock); |
1197 | dev->total_ios++; | 1197 | dev->total_ios++; |