Commit e1c4b745 authored by Chris Mason's avatar Chris Mason

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: default avatarChris Mason <chris.mason@oracle.com>
parent 409c6118
...@@ -1694,6 +1694,7 @@ extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, ...@@ -1694,6 +1694,7 @@ extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
} }
if (bio) { if (bio) {
bio->bi_size = 0;
bio->bi_bdev = bdev; bio->bi_bdev = bdev;
bio->bi_sector = first_sector; bio->bi_sector = first_sector;
} }
......
...@@ -494,6 +494,7 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio, ...@@ -494,6 +494,7 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio,
bio->bi_end_io = failed_bio->bi_end_io; bio->bi_end_io = failed_bio->bi_end_io;
bio->bi_sector = failrec->logical >> 9; bio->bi_sector = failrec->logical >> 9;
bio->bi_bdev = failed_bio->bi_bdev; bio->bi_bdev = failed_bio->bi_bdev;
bio->bi_size = 0;
bio_add_page(bio, page, failrec->len, start - page_offset(page)); bio_add_page(bio, page, failrec->len, start - page_offset(page));
btrfs_submit_bio_hook(inode, READ, bio, failrec->last_mirror); btrfs_submit_bio_hook(inode, READ, bio, failrec->last_mirror);
return 0; return 0;
...@@ -2187,12 +2188,9 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -2187,12 +2188,9 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
spin_unlock(&em_tree->lock); spin_unlock(&em_tree->lock);
if (em) { if (em) {
if (em->start > start) { if (em->start > start || em->start + em->len <= start)
printk("get_extent lookup [%Lu %Lu] em [%Lu %Lu]\n", free_extent_map(em);
start, len, em->start, em->len); else if (em->block_start == EXTENT_MAP_INLINE && page)
WARN_ON(1);
}
if (em->block_start == EXTENT_MAP_INLINE && page)
free_extent_map(em); free_extent_map(em);
else else
goto out; goto out;
...@@ -2340,7 +2338,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -2340,7 +2338,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
err = 0; err = 0;
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em); ret = add_extent_mapping(em_tree, em);
/* it is possible that someone inserted the extent into the tree /* it is possible that someone inserted the extent into the tree
* while we had the lock dropped. It is also possible that * while we had the lock dropped. It is also possible that
* an overlapping map exists in the tree * an overlapping map exists in the tree
...@@ -2348,6 +2345,11 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -2348,6 +2345,11 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
if (ret == -EEXIST) { if (ret == -EEXIST) {
struct extent_map *existing; struct extent_map *existing;
existing = lookup_extent_mapping(em_tree, start, len); existing = lookup_extent_mapping(em_tree, start, len);
if (existing && (existing->start > start ||
existing->start + existing->len <= start)) {
free_extent_map(existing);
existing = NULL;
}
if (!existing) { if (!existing) {
existing = lookup_extent_mapping(em_tree, em->start, existing = lookup_extent_mapping(em_tree, em->start,
em->len); em->len);
...@@ -2388,6 +2390,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -2388,6 +2390,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
return em; return em;
} }
#if 0 /* waiting for O_DIRECT reads */
static int btrfs_get_block(struct inode *inode, sector_t iblock, static int btrfs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
...@@ -2405,22 +2408,24 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, ...@@ -2405,22 +2408,24 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock,
if (!em || IS_ERR(em)) if (!em || IS_ERR(em))
goto out; goto out;
if (em->start > start || em->start + em->len <= start) if (em->start > start || em->start + em->len <= start) {
goto out; goto out;
}
if (em->block_start == EXTENT_MAP_INLINE) { if (em->block_start == EXTENT_MAP_INLINE) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
len = em->start + em->len - start;
len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size)));
if (em->block_start == EXTENT_MAP_HOLE || if (em->block_start == EXTENT_MAP_HOLE ||
em->block_start == EXTENT_MAP_DELALLOC) { em->block_start == EXTENT_MAP_DELALLOC) {
bh_result->b_size = len;
goto out; goto out;
} }
len = em->start + em->len - start;
len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size)));
logical = start - em->start; logical = start - em->start;
logical = em->block_start + logical; logical = em->block_start + logical;
...@@ -2430,6 +2435,7 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, ...@@ -2430,6 +2435,7 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock,
BUG_ON(ret); BUG_ON(ret);
bh_result->b_blocknr = multi->stripes[0].physical >> inode->i_blkbits; bh_result->b_blocknr = multi->stripes[0].physical >> inode->i_blkbits;
bh_result->b_size = min(map_length, len); bh_result->b_size = min(map_length, len);
bh_result->b_bdev = multi->stripes[0].dev->bdev; bh_result->b_bdev = multi->stripes[0].dev->bdev;
set_buffer_mapped(bh_result); set_buffer_mapped(bh_result);
kfree(multi); kfree(multi);
...@@ -2437,11 +2443,14 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock, ...@@ -2437,11 +2443,14 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock,
free_extent_map(em); free_extent_map(em);
return ret; return ret;
} }
#endif
static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset, const struct iovec *iov, loff_t offset,
unsigned long nr_segs) unsigned long nr_segs)
{ {
return -EINVAL;
#if 0
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
...@@ -2450,6 +2459,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, ...@@ -2450,6 +2459,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, btrfs_get_block, NULL); offset, nr_segs, btrfs_get_block, NULL);
#endif
} }
static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock) static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock)
......
...@@ -1161,7 +1161,6 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, ...@@ -1161,7 +1161,6 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
int total_devs = 1; int total_devs = 1;
length = bio->bi_size; length = bio->bi_size;
map_tree = &root->fs_info->mapping_tree; map_tree = &root->fs_info->mapping_tree;
map_length = length; map_length = length;
...@@ -1192,6 +1191,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, ...@@ -1192,6 +1191,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
} }
bio->bi_sector = multi->stripes[dev_nr].physical >> 9; bio->bi_sector = multi->stripes[dev_nr].physical >> 9;
dev = multi->stripes[dev_nr].dev; dev = multi->stripes[dev_nr].dev;
bio->bi_bdev = dev->bdev; bio->bi_bdev = dev->bdev;
spin_lock(&dev->io_lock); spin_lock(&dev->io_lock);
dev->total_ios++; dev->total_ios++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment