diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 38e721b35d45..b3c1d3dae77d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -116,6 +116,8 @@ EXPORT_SYMBOL(invalidate_bdev); | |||
116 | 116 | ||
117 | int set_blocksize(struct block_device *bdev, int size) | 117 | int set_blocksize(struct block_device *bdev, int size) |
118 | { | 118 | { |
119 | struct address_space *mapping; | ||
120 | |||
119 | /* Size must be a power of two, and between 512 and PAGE_SIZE */ | 121 | /* Size must be a power of two, and between 512 and PAGE_SIZE */ |
120 | if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) | 122 | if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) |
121 | return -EINVAL; | 123 | return -EINVAL; |
@@ -124,6 +126,19 @@ int set_blocksize(struct block_device *bdev, int size) | |||
124 | if (size < bdev_logical_block_size(bdev)) | 126 | if (size < bdev_logical_block_size(bdev)) |
125 | return -EINVAL; | 127 | return -EINVAL; |
126 | 128 | ||
129 | /* Prevent starting I/O or mapping the device */ | ||
130 | percpu_down_write(&bdev->bd_block_size_semaphore); | ||
131 | |||
132 | /* Check that the block device is not memory mapped */ | ||
133 | mapping = bdev->bd_inode->i_mapping; | ||
134 | mutex_lock(&mapping->i_mmap_mutex); | ||
135 | if (mapping_mapped(mapping)) { | ||
136 | mutex_unlock(&mapping->i_mmap_mutex); | ||
137 | percpu_up_write(&bdev->bd_block_size_semaphore); | ||
138 | return -EBUSY; | ||
139 | } | ||
140 | mutex_unlock(&mapping->i_mmap_mutex); | ||
141 | |||
127 | /* Don't change the size if it is same as current */ | 142 | /* Don't change the size if it is same as current */ |
128 | if (bdev->bd_block_size != size) { | 143 | if (bdev->bd_block_size != size) { |
129 | sync_blockdev(bdev); | 144 | sync_blockdev(bdev); |
@@ -131,6 +146,9 @@ int set_blocksize(struct block_device *bdev, int size) | |||
131 | bdev->bd_inode->i_blkbits = blksize_bits(size); | 146 | bdev->bd_inode->i_blkbits = blksize_bits(size); |
132 | kill_bdev(bdev); | 147 | kill_bdev(bdev); |
133 | } | 148 | } |
149 | |||
150 | percpu_up_write(&bdev->bd_block_size_semaphore); | ||
151 | |||
134 | return 0; | 152 | return 0; |
135 | } | 153 | } |
136 | 154 | ||
@@ -441,6 +459,12 @@ static struct inode *bdev_alloc_inode(struct super_block *sb) | |||
441 | struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL); | 459 | struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL); |
442 | if (!ei) | 460 | if (!ei) |
443 | return NULL; | 461 | return NULL; |
462 | |||
463 | if (unlikely(percpu_init_rwsem(&ei->bdev.bd_block_size_semaphore))) { | ||
464 | kmem_cache_free(bdev_cachep, ei); | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
444 | return &ei->vfs_inode; | 468 | return &ei->vfs_inode; |
445 | } | 469 | } |
446 | 470 | ||
@@ -449,6 +473,8 @@ static void bdev_i_callback(struct rcu_head *head) | |||
449 | struct inode *inode = container_of(head, struct inode, i_rcu); | 473 | struct inode *inode = container_of(head, struct inode, i_rcu); |
450 | struct bdev_inode *bdi = BDEV_I(inode); | 474 | struct bdev_inode *bdi = BDEV_I(inode); |
451 | 475 | ||
476 | percpu_free_rwsem(&bdi->bdev.bd_block_size_semaphore); | ||
477 | |||
452 | kmem_cache_free(bdev_cachep, bdi); | 478 | kmem_cache_free(bdev_cachep, bdi); |
453 | } | 479 | } |
454 | 480 | ||
@@ -1567,6 +1593,22 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
1567 | return blkdev_ioctl(bdev, mode, cmd, arg); | 1593 | return blkdev_ioctl(bdev, mode, cmd, arg); |
1568 | } | 1594 | } |
1569 | 1595 | ||
1596 | ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov, | ||
1597 | unsigned long nr_segs, loff_t pos) | ||
1598 | { | ||
1599 | ssize_t ret; | ||
1600 | struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host); | ||
1601 | |||
1602 | percpu_down_read(&bdev->bd_block_size_semaphore); | ||
1603 | |||
1604 | ret = generic_file_aio_read(iocb, iov, nr_segs, pos); | ||
1605 | |||
1606 | percpu_up_read(&bdev->bd_block_size_semaphore); | ||
1607 | |||
1608 | return ret; | ||
1609 | } | ||
1610 | EXPORT_SYMBOL_GPL(blkdev_aio_read); | ||
1611 | |||
1570 | /* | 1612 | /* |
1571 | * Write data to the block device. Only intended for the block device itself | 1613 | * Write data to the block device. Only intended for the block device itself |
1572 | * and the raw driver which basically is a fake block device. | 1614 | * and the raw driver which basically is a fake block device. |
@@ -1578,12 +1620,16 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1578 | unsigned long nr_segs, loff_t pos) | 1620 | unsigned long nr_segs, loff_t pos) |
1579 | { | 1621 | { |
1580 | struct file *file = iocb->ki_filp; | 1622 | struct file *file = iocb->ki_filp; |
1623 | struct block_device *bdev = I_BDEV(file->f_mapping->host); | ||
1581 | struct blk_plug plug; | 1624 | struct blk_plug plug; |
1582 | ssize_t ret; | 1625 | ssize_t ret; |
1583 | 1626 | ||
1584 | BUG_ON(iocb->ki_pos != pos); | 1627 | BUG_ON(iocb->ki_pos != pos); |
1585 | 1628 | ||
1586 | blk_start_plug(&plug); | 1629 | blk_start_plug(&plug); |
1630 | |||
1631 | percpu_down_read(&bdev->bd_block_size_semaphore); | ||
1632 | |||
1587 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | 1633 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); |
1588 | if (ret > 0 || ret == -EIOCBQUEUED) { | 1634 | if (ret > 0 || ret == -EIOCBQUEUED) { |
1589 | ssize_t err; | 1635 | ssize_t err; |
@@ -1592,11 +1638,29 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1592 | if (err < 0 && ret > 0) | 1638 | if (err < 0 && ret > 0) |
1593 | ret = err; | 1639 | ret = err; |
1594 | } | 1640 | } |
1641 | |||
1642 | percpu_up_read(&bdev->bd_block_size_semaphore); | ||
1643 | |||
1595 | blk_finish_plug(&plug); | 1644 | blk_finish_plug(&plug); |
1645 | |||
1596 | return ret; | 1646 | return ret; |
1597 | } | 1647 | } |
1598 | EXPORT_SYMBOL_GPL(blkdev_aio_write); | 1648 | EXPORT_SYMBOL_GPL(blkdev_aio_write); |
1599 | 1649 | ||
1650 | static int blkdev_mmap(struct file *file, struct vm_area_struct *vma) | ||
1651 | { | ||
1652 | int ret; | ||
1653 | struct block_device *bdev = I_BDEV(file->f_mapping->host); | ||
1654 | |||
1655 | percpu_down_read(&bdev->bd_block_size_semaphore); | ||
1656 | |||
1657 | ret = generic_file_mmap(file, vma); | ||
1658 | |||
1659 | percpu_up_read(&bdev->bd_block_size_semaphore); | ||
1660 | |||
1661 | return ret; | ||
1662 | } | ||
1663 | |||
1600 | /* | 1664 | /* |
1601 | * Try to release a page associated with block device when the system | 1665 | * Try to release a page associated with block device when the system |
1602 | * is under memory pressure. | 1666 | * is under memory pressure. |
@@ -1627,9 +1691,9 @@ const struct file_operations def_blk_fops = { | |||
1627 | .llseek = block_llseek, | 1691 | .llseek = block_llseek, |
1628 | .read = do_sync_read, | 1692 | .read = do_sync_read, |
1629 | .write = do_sync_write, | 1693 | .write = do_sync_write, |
1630 | .aio_read = generic_file_aio_read, | 1694 | .aio_read = blkdev_aio_read, |
1631 | .aio_write = blkdev_aio_write, | 1695 | .aio_write = blkdev_aio_write, |
1632 | .mmap = generic_file_mmap, | 1696 | .mmap = blkdev_mmap, |
1633 | .fsync = blkdev_fsync, | 1697 | .fsync = blkdev_fsync, |
1634 | .unlocked_ioctl = block_ioctl, | 1698 | .unlocked_ioctl = block_ioctl, |
1635 | #ifdef CONFIG_COMPAT | 1699 | #ifdef CONFIG_COMPAT |