mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 14:14:24 +08:00
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>
This commit is contained in:
parent
409c6118d3
commit
e1c4b7451e
@ -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,
|
|||||||
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 @@ again:
|
|||||||
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 @@ insert:
|
|||||||
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 @@ insert:
|
|||||||
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 @@ out:
|
|||||||
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,
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em->block_start == EXTENT_MAP_HOLE ||
|
|
||||||
em->block_start == EXTENT_MAP_DELALLOC) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = em->start + em->len - start;
|
len = em->start + em->len - start;
|
||||||
len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size)));
|
len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size)));
|
||||||
|
|
||||||
|
if (em->block_start == EXTENT_MAP_HOLE ||
|
||||||
|
em->block_start == EXTENT_MAP_DELALLOC) {
|
||||||
|
bh_result->b_size = len;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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 @@ out:
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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++;
|
||||||
|
Loading…
Reference in New Issue
Block a user