Commit 42da88a7 authored by Johannes Thumshirn's avatar Johannes Thumshirn Committed by Jens Axboe
Browse files

blktrace: split do_blk_trace_setup into two functions



Split do_blk_trace_setup into two functions, this is done to prepare for
an incoming new BLKTRACESETUP2 ioctl(2) which can receive extended
parameters from user-space.

Also move the size verification logic to the callers in preparation for
using a new internal structure later.

Reviewed-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 370cd70a
Loading
Loading
Loading
Loading
+56 −38
Original line number Diff line number Diff line
@@ -518,9 +518,10 @@ static void blk_trace_setup_lba(struct blk_trace *bt,
/*
 * Setup everything required to start tracing
 */
static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
			      struct block_device *bdev,
			      struct blk_user_trace_setup *buts)
static struct blk_trace *blk_trace_setup_prepare(struct request_queue *q,
						 char *name, dev_t dev,
						 u32 buf_size, u32 buf_nr,
						 struct block_device *bdev)
{
	struct blk_trace *bt = NULL;
	struct dentry *dir = NULL;
@@ -528,31 +529,19 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,

	lockdep_assert_held(&q->debugfs_mutex);

	if (!buts->buf_size || !buts->buf_nr)
		return -EINVAL;

	strscpy_pad(buts->name, name, BLKTRACE_BDEV_SIZE);

	/*
	 * some device names have larger paths - convert the slashes
	 * to underscores for this to work as expected
	 */
	strreplace(buts->name, '/', '_');

	/*
	 * bdev can be NULL, as with scsi-generic, this is a helpful as
	 * we can be.
	 */
	if (rcu_dereference_protected(q->blk_trace,
				      lockdep_is_held(&q->debugfs_mutex))) {
		pr_warn("Concurrent blktraces are not allowed on %s\n",
			buts->name);
		return -EBUSY;
		pr_warn("Concurrent blktraces are not allowed on %s\n", name);
		return ERR_PTR(-EBUSY);
	}

	bt = kzalloc(sizeof(*bt), GFP_KERNEL);
	if (!bt)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);

	ret = -ENOMEM;
	bt->sequence = alloc_percpu(unsigned long);
@@ -572,7 +561,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
	if (bdev && !bdev_is_partition(bdev))
		dir = q->debugfs_dir;
	else
		bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root);
		bt->dir = dir = debugfs_create_dir(name, blk_debugfs_root);

	/*
	 * As blktrace relies on debugfs for its interface the debugfs directory
@@ -580,8 +569,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
	 * files or directories.
	 */
	if (IS_ERR_OR_NULL(dir)) {
		pr_warn("debugfs_dir not present for %s so skipping\n",
			buts->name);
		pr_warn("debugfs_dir not present for %s so skipping\n", name);
		ret = -ENOENT;
		goto err;
	}
@@ -593,17 +581,38 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
	debugfs_create_file("dropped", 0444, dir, bt, &blk_dropped_fops);
	debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops);

	bt->rchan = relay_open("trace", dir, buts->buf_size,
				buts->buf_nr, &blk_relay_callbacks, bt);
	bt->rchan = relay_open("trace", dir, buf_size, buf_nr,
			       &blk_relay_callbacks, bt);
	if (!bt->rchan)
		goto err;

	blk_trace_setup_lba(bt, bdev);

	return bt;

err:
	blk_trace_free(q, bt);

	return ERR_PTR(ret);
}

static void blk_trace_setup_finalize(struct request_queue *q,
				     char *name, struct blk_trace *bt,
				     struct blk_user_trace_setup *buts)

{
	strscpy_pad(buts->name, name, BLKTRACE_BDEV_SIZE);

	/*
	 * some device names have larger paths - convert the slashes
	 * to underscores for this to work as expected
	 */
	strreplace(buts->name, '/', '_');

	bt->act_mask = buts->act_mask;
	if (!bt->act_mask)
		bt->act_mask = (u16) -1;

	blk_trace_setup_lba(bt, bdev);

	/* overwrite with user settings */
	if (buts->start_lba)
		bt->start_lba = buts->start_lba;
@@ -615,12 +624,6 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,

	rcu_assign_pointer(q->blk_trace, bt);
	get_probe_ref();

	ret = 0;
err:
	if (ret)
		blk_trace_free(q, bt);
	return ret;
}

int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
@@ -628,17 +631,25 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
		    char __user *arg)
{
	struct blk_user_trace_setup buts;
	struct blk_trace *bt;
	int ret;

	ret = copy_from_user(&buts, arg, sizeof(buts));
	if (ret)
		return -EFAULT;

	if (!buts.buf_size || !buts.buf_nr)
		return -EINVAL;

	mutex_lock(&q->debugfs_mutex);
	ret = do_blk_trace_setup(q, name, dev, bdev, &buts);
	bt = blk_trace_setup_prepare(q, name, dev, buts.buf_size, buts.buf_nr,
				     bdev);
	if (IS_ERR(bt)) {
		mutex_unlock(&q->debugfs_mutex);
		return PTR_ERR(bt);
	}
	blk_trace_setup_finalize(q, name, bt, &buts);
	mutex_unlock(&q->debugfs_mutex);
	if (ret)
		return ret;

	if (copy_to_user(arg, &buts, sizeof(buts))) {
		blk_trace_remove(q);
@@ -655,11 +666,14 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
{
	struct blk_user_trace_setup buts;
	struct compat_blk_user_trace_setup cbuts;
	int ret;
	struct blk_trace *bt;

	if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
		return -EFAULT;

	if (!cbuts.buf_size || !cbuts.buf_nr)
		return -EINVAL;

	buts = (struct blk_user_trace_setup) {
		.act_mask = cbuts.act_mask,
		.buf_size = cbuts.buf_size,
@@ -670,10 +684,14 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
	};

	mutex_lock(&q->debugfs_mutex);
	ret = do_blk_trace_setup(q, name, dev, bdev, &buts);
	bt = blk_trace_setup_prepare(q, name, dev, buts.buf_size, buts.buf_nr,
				     bdev);
	if (IS_ERR(bt)) {
		mutex_unlock(&q->debugfs_mutex);
		return PTR_ERR(bt);
	}
	blk_trace_setup_finalize(q, name, bt, &buts);
	mutex_unlock(&q->debugfs_mutex);
	if (ret)
		return ret;

	if (copy_to_user(arg, &buts.name, ARRAY_SIZE(buts.name))) {
		blk_trace_remove(q);