Unverified Commit a56aefca authored by Christian Brauner's avatar Christian Brauner
Browse files

bdev: make struct bdev_handle private to the block layer

parent b1211a25
Loading
Loading
Loading
Loading
+61 −58
Original line number Diff line number Diff line
@@ -703,6 +703,24 @@ static int blkdev_get_part(struct block_device *part, blk_mode_t mode)
	return ret;
}

int bdev_permission(dev_t dev, blk_mode_t mode, void *holder)
{
	int ret;

	ret = devcgroup_check_permission(DEVCG_DEV_BLOCK,
			MAJOR(dev), MINOR(dev),
			((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) |
			((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0));
	if (ret)
		return ret;

	/* Blocking writes requires exclusive opener */
	if (mode & BLK_OPEN_RESTRICT_WRITES && !holder)
		return -EINVAL;

	return 0;
}

static void blkdev_put_part(struct block_device *part)
{
	struct block_device *whole = bdev_whole(part);
@@ -795,69 +813,43 @@ static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode)
}

/**
 * bdev_open_by_dev - open a block device by device number
 * @dev: device number of block device to open
 * bdev_open - open a block device
 * @bdev: block device to open
 * @mode: open mode (BLK_OPEN_*)
 * @holder: exclusive holder identifier
 * @hops: holder operations
 * @bdev_file: file for the block device
 *
 * Open the block device described by device number @dev. If @holder is not
 * %NULL, the block device is opened with exclusive access.  Exclusive opens may
 * nest for the same @holder.
 *
 * Use this interface ONLY if you really do not have anything better - i.e. when
 * you are behind a truly sucky interface and all you are given is a device
 * number.  Everything else should use bdev_open_by_path().
 * Open the block device. If @holder is not %NULL, the block device is opened
 * with exclusive access.  Exclusive opens may nest for the same @holder.
 *
 * CONTEXT:
 * Might sleep.
 *
 * RETURNS:
 * Handle with a reference to the block_device on success, ERR_PTR(-errno) on
 * failure.
 * zero on success, -errno on failure.
 */
struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
				     const struct blk_holder_ops *hops)
int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
	      const struct blk_holder_ops *hops, struct file *bdev_file)
{
	struct bdev_handle *handle = kmalloc(sizeof(struct bdev_handle),
					     GFP_KERNEL);
	struct block_device *bdev;
	struct bdev_handle *handle;
	bool unblock_events = true;
	struct gendisk *disk;
	struct gendisk *disk = bdev->bd_disk;
	int ret;

	handle = kmalloc(sizeof(struct bdev_handle), GFP_KERNEL);
	if (!handle)
		return ERR_PTR(-ENOMEM);

	ret = devcgroup_check_permission(DEVCG_DEV_BLOCK,
			MAJOR(dev), MINOR(dev),
			((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) |
			((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0));
	if (ret)
		goto free_handle;

	/* Blocking writes requires exclusive opener */
	if (mode & BLK_OPEN_RESTRICT_WRITES && !holder) {
		ret = -EINVAL;
		goto free_handle;
	}

	bdev = blkdev_get_no_open(dev);
	if (!bdev) {
		ret = -ENXIO;
		goto free_handle;
	}
	disk = bdev->bd_disk;
		return -ENOMEM;

	if (holder) {
		mode |= BLK_OPEN_EXCL;
		ret = bd_prepare_to_claim(bdev, holder, hops);
		if (ret)
			goto put_blkdev;
			goto free_handle;
	} else {
		if (WARN_ON_ONCE(mode & BLK_OPEN_EXCL)) {
			ret = -EIO;
			goto put_blkdev;
			goto free_handle;
		}
	}

@@ -902,7 +894,16 @@ struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
	handle->bdev = bdev;
	handle->holder = holder;
	handle->mode = mode;
	return handle;

	bdev_file->f_flags |= O_LARGEFILE;
	bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
	if (bdev_nowait(bdev))
		bdev_file->f_mode |= FMODE_NOWAIT;
	bdev_file->f_mapping = handle->bdev->bd_inode->i_mapping;
	bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping);
	bdev_file->private_data = handle;

	return 0;
put_module:
	module_put(disk->fops->owner);
abort_claiming:
@@ -910,11 +911,9 @@ struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
		bd_abort_claiming(bdev, holder);
	mutex_unlock(&disk->open_mutex);
	disk_unblock_events(disk);
put_blkdev:
	blkdev_put_no_open(bdev);
free_handle:
	kfree(handle);
	return ERR_PTR(ret);
	return ret;
}

/*
@@ -951,29 +950,33 @@ struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
				   const struct blk_holder_ops *hops)
{
	struct file *bdev_file;
	struct bdev_handle *handle;
	struct block_device *bdev;
	unsigned int flags;
	int ret;

	handle = bdev_open_by_dev(dev, mode, holder, hops);
	if (IS_ERR(handle))
		return ERR_CAST(handle);
	ret = bdev_permission(dev, mode, holder);
	if (ret)
		return ERR_PTR(ret);

	bdev = blkdev_get_no_open(dev);
	if (!bdev)
		return ERR_PTR(-ENXIO);

	flags = blk_to_file_flags(mode);
	bdev_file = alloc_file_pseudo_noaccount(handle->bdev->bd_inode,
	bdev_file = alloc_file_pseudo_noaccount(bdev->bd_inode,
			blockdev_mnt, "", flags | O_LARGEFILE, &def_blk_fops);
	if (IS_ERR(bdev_file)) {
		bdev_release(handle);
		blkdev_put_no_open(bdev);
		return bdev_file;
	}
	ihold(handle->bdev->bd_inode);

	bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
	if (bdev_nowait(handle->bdev))
		bdev_file->f_mode |= FMODE_NOWAIT;
	ihold(bdev->bd_inode);

	bdev_file->f_mapping = handle->bdev->bd_inode->i_mapping;
	bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping);
	bdev_file->private_data = handle;
	ret = bdev_open(bdev, mode, holder, hops, bdev_file);
	if (ret) {
		blkdev_put_no_open(bdev);
		fput(bdev_file);
		return ERR_PTR(ret);
	}
	return bdev_file;
}
EXPORT_SYMBOL(bdev_file_open_by_dev);
+9 −3
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@ struct blk_flush_queue {
	struct request		*flush_rq;
};

struct bdev_handle {
	struct block_device *bdev;
	void *holder;
	blk_mode_t mode;
};

bool is_flush_rq(struct request *req);

struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
@@ -517,7 +523,7 @@ static inline int req_ref_read(struct request *req)
}

void bdev_release(struct bdev_handle *handle);
struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
		const struct blk_holder_ops *hops);

int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
	      const struct blk_holder_ops *hops, struct file *bdev_file);
int bdev_permission(dev_t dev, blk_mode_t mode, void *holder);
#endif /* BLK_INTERNAL_H */
+16 −21
Original line number Diff line number Diff line
@@ -599,35 +599,30 @@ blk_mode_t file_to_blk_mode(struct file *file)

static int blkdev_open(struct inode *inode, struct file *filp)
{
	struct bdev_handle *handle;
	struct block_device *bdev;
	blk_mode_t mode;

	/*
	 * Preserve backwards compatibility and allow large file access
	 * even if userspace doesn't ask for it explicitly. Some mkfs
	 * binary needs it. We might want to drop this workaround
	 * during an unstable branch.
	 */
	filp->f_flags |= O_LARGEFILE;
	filp->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
	void *holder;
	int ret;

	mode = file_to_blk_mode(filp);
	handle = bdev_open_by_dev(inode->i_rdev, mode,
			mode & BLK_OPEN_EXCL ? filp : NULL, NULL);
	if (IS_ERR(handle))
		return PTR_ERR(handle);
	holder = mode & BLK_OPEN_EXCL ? filp : NULL;
	ret = bdev_permission(inode->i_rdev, mode, holder);
	if (ret)
		return ret;

	if (bdev_nowait(handle->bdev))
		filp->f_mode |= FMODE_NOWAIT;
	bdev = blkdev_get_no_open(inode->i_rdev);
	if (!bdev)
		return -ENXIO;

	filp->f_mapping = handle->bdev->bd_inode->i_mapping;
	filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping);
	filp->private_data = handle;
	return 0;
	ret = bdev_open(bdev, mode, holder, NULL, filp);
	if (ret)
		blkdev_put_no_open(bdev);
	return ret;
}

static int blkdev_release(struct inode *inode, struct file *filp)
{
	if (filp->private_data)
		bdev_release(filp->private_data);
	return 0;
}
+0 −7
Original line number Diff line number Diff line
@@ -1475,13 +1475,6 @@ extern const struct blk_holder_ops fs_holder_ops;
	(BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES | \
	 (((flags) & SB_RDONLY) ? 0 : BLK_OPEN_WRITE))

/* @bdev_handle will be removed soon. */
struct bdev_handle {
	struct block_device *bdev;
	void *holder;
	blk_mode_t mode;
};

struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder,
		const struct blk_holder_ops *hops);
struct file *bdev_file_open_by_path(const char *path, blk_mode_t mode,
+0 −6
Original line number Diff line number Diff line
@@ -1327,12 +1327,6 @@ struct super_block {
	struct list_head	s_inodes_wb;	/* writeback inodes */
} __randomize_layout;

/* Temporary helper that will go away. */
static inline struct bdev_handle *sb_bdev_handle(struct super_block *sb)
{
	return sb->s_bdev_file->private_data;
}

static inline struct user_namespace *i_user_ns(const struct inode *inode)
{
	return inode->i_sb->s_user_ns;