diff options
Diffstat (limited to 'fs/block_dev.c')
| -rw-r--r-- | fs/block_dev.c | 109 | 
1 files changed, 84 insertions, 25 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 1e86823a9cb..6d7274619bf 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -83,7 +83,7 @@ void kill_bdev(struct block_device *bdev)  {  	struct address_space *mapping = bdev->bd_inode->i_mapping; -	if (mapping->nrpages == 0) +	if (mapping->nrpages == 0 && mapping->nrshadows == 0)  		return;  	invalidate_bh_lrus(); @@ -165,14 +165,15 @@ blkdev_get_block(struct inode *inode, sector_t iblock,  }  static ssize_t -blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, -			loff_t offset, unsigned long nr_segs) +blkdev_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, +			loff_t offset)  {  	struct file *file = iocb->ki_filp;  	struct inode *inode = file->f_mapping->host; -	return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset, -				    nr_segs, blkdev_get_block, NULL, NULL, 0); +	return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iter, +				    offset, blkdev_get_block, +				    NULL, NULL, 0);  }  int __sync_blockdev(struct block_device *bdev, int wait) @@ -363,6 +364,69 @@ int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync)  }  EXPORT_SYMBOL(blkdev_fsync); +/** + * bdev_read_page() - Start reading a page from a block device + * @bdev: The device to read the page from + * @sector: The offset on the device to read the page to (need not be aligned) + * @page: The page to read + * + * On entry, the page should be locked.  It will be unlocked when the page + * has been read.  If the block driver implements rw_page synchronously, + * that will be true on exit from this function, but it need not be. + * + * Errors returned by this function are usually "soft", eg out of memory, or + * queue full; callers should try a different route to read this page rather + * than propagate an error back up the stack. + * + * Return: negative errno if an error occurs, 0 if submission was successful. + */ +int bdev_read_page(struct block_device *bdev, sector_t sector, +			struct page *page) +{ +	const struct block_device_operations *ops = bdev->bd_disk->fops; +	if (!ops->rw_page) +		return -EOPNOTSUPP; +	return ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ); +} +EXPORT_SYMBOL_GPL(bdev_read_page); + +/** + * bdev_write_page() - Start writing a page to a block device + * @bdev: The device to write the page to + * @sector: The offset on the device to write the page to (need not be aligned) + * @page: The page to write + * @wbc: The writeback_control for the write + * + * On entry, the page should be locked and not currently under writeback. + * On exit, if the write started successfully, the page will be unlocked and + * under writeback.  If the write failed already (eg the driver failed to + * queue the page to the device), the page will still be locked.  If the + * caller is a ->writepage implementation, it will need to unlock the page. + * + * Errors returned by this function are usually "soft", eg out of memory, or + * queue full; callers should try a different route to write this page rather + * than propagate an error back up the stack. + * + * Return: negative errno if an error occurs, 0 if submission was successful. + */ +int bdev_write_page(struct block_device *bdev, sector_t sector, +			struct page *page, struct writeback_control *wbc) +{ +	int result; +	int rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE; +	const struct block_device_operations *ops = bdev->bd_disk->fops; +	if (!ops->rw_page) +		return -EOPNOTSUPP; +	set_page_writeback(page); +	result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, rw); +	if (result) +		end_page_writeback(page); +	else +		unlock_page(page); +	return result; +} +EXPORT_SYMBOL_GPL(bdev_write_page); +  /*   * pseudo-fs   */ @@ -419,7 +483,7 @@ static void bdev_evict_inode(struct inode *inode)  {  	struct block_device *bdev = &BDEV_I(inode)->bdev;  	struct list_head *p; -	truncate_inode_pages(&inode->i_data, 0); +	truncate_inode_pages_final(&inode->i_data);  	invalidate_inode_buffers(inode); /* is it needed here? */  	clear_inode(inode);  	spin_lock(&bdev_lock); @@ -1508,43 +1572,38 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)   * Does not take i_mutex for the write and thus is not for general purpose   * use.   */ -ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, -			 unsigned long nr_segs, loff_t pos) +ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)  {  	struct file *file = iocb->ki_filp;  	struct blk_plug plug;  	ssize_t ret; -	BUG_ON(iocb->ki_pos != pos); -  	blk_start_plug(&plug); -	ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); +	ret = __generic_file_write_iter(iocb, from);  	if (ret > 0) {  		ssize_t err; - -		err = generic_write_sync(file, pos, ret); -		if (err < 0 && ret > 0) +		err = generic_write_sync(file, iocb->ki_pos - ret, ret); +		if (err < 0)  			ret = err;  	}  	blk_finish_plug(&plug);  	return ret;  } -EXPORT_SYMBOL_GPL(blkdev_aio_write); +EXPORT_SYMBOL_GPL(blkdev_write_iter); -static ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov, -			 unsigned long nr_segs, loff_t pos) +static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)  {  	struct file *file = iocb->ki_filp;  	struct inode *bd_inode = file->f_mapping->host;  	loff_t size = i_size_read(bd_inode); +	loff_t pos = iocb->ki_pos;  	if (pos >= size)  		return 0;  	size -= pos; -	if (size < iocb->ki_nbytes) -		nr_segs = iov_shorten((struct iovec *)iov, nr_segs, size); -	return generic_file_aio_read(iocb, iov, nr_segs, pos); +	iov_iter_truncate(to, size); +	return generic_file_read_iter(iocb, to);  }  /* @@ -1576,10 +1635,10 @@ const struct file_operations def_blk_fops = {  	.open		= blkdev_open,  	.release	= blkdev_close,  	.llseek		= block_llseek, -	.read		= do_sync_read, -	.write		= do_sync_write, -	.aio_read	= blkdev_aio_read, -	.aio_write	= blkdev_aio_write, +	.read		= new_sync_read, +	.write		= new_sync_write, +	.read_iter	= blkdev_read_iter, +	.write_iter	= blkdev_write_iter,  	.mmap		= generic_file_mmap,  	.fsync		= blkdev_fsync,  	.unlocked_ioctl	= block_ioctl, @@ -1587,7 +1646,7 @@ const struct file_operations def_blk_fops = {  	.compat_ioctl	= compat_blkdev_ioctl,  #endif  	.splice_read	= generic_file_splice_read, -	.splice_write	= generic_file_splice_write, +	.splice_write	= iter_file_splice_write,  };  int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)  | 
