Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cdea01b2 authored by Davidlohr Bueso's avatar Davidlohr Bueso Committed by Jens Axboe
Browse files

blktrace: re-write setting q->blk_trace



This is really about simplifying the double xchg patterns into
a single cmpxchg, with the same logic. Other than the immediate
cleanup, there are some subtleties this change deals with:

(i) While the load of the old bt is fully ordered wrt everything,
ie:

        old_bt = xchg(&q->blk_trace, bt);             [barrier]
        if (old_bt)
	     (void) xchg(&q->blk_trace, old_bt);    [barrier]

blk_trace could still be changed between the xchg and the old_bt
load. Note that this description is merely theoretical and afaict
very small, but doing everything in a single context with cmpxchg
closes this potential race.

(ii) Ordering guarantees are obviously kept with cmpxchg.

(iii) Gets rid of the hacky-by-nature (void)xchg pattern.

Signed-off-by: default avatarDavidlohr Bueso <dbueso@suse.de>
eviewed-by: default avatarJeff Moyer <jmoyer@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent cfd0c552
Loading
Loading
Loading
Loading
+5 −11
Original line number Original line Diff line number Diff line
@@ -437,7 +437,7 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
		       struct block_device *bdev,
		       struct block_device *bdev,
		       struct blk_user_trace_setup *buts)
		       struct blk_user_trace_setup *buts)
{
{
	struct blk_trace *old_bt, *bt = NULL;
	struct blk_trace *bt = NULL;
	struct dentry *dir = NULL;
	struct dentry *dir = NULL;
	int ret;
	int ret;


@@ -519,11 +519,8 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
	bt->trace_state = Blktrace_setup;
	bt->trace_state = Blktrace_setup;


	ret = -EBUSY;
	ret = -EBUSY;
	old_bt = xchg(&q->blk_trace, bt);
	if (cmpxchg(&q->blk_trace, NULL, bt))
	if (old_bt) {
		(void) xchg(&q->blk_trace, old_bt);
		goto err;
		goto err;
	}


	if (atomic_inc_return(&blk_probes_ref) == 1)
	if (atomic_inc_return(&blk_probes_ref) == 1)
		blk_register_tracepoints();
		blk_register_tracepoints();
@@ -1481,7 +1478,7 @@ static int blk_trace_remove_queue(struct request_queue *q)
static int blk_trace_setup_queue(struct request_queue *q,
static int blk_trace_setup_queue(struct request_queue *q,
				 struct block_device *bdev)
				 struct block_device *bdev)
{
{
	struct blk_trace *old_bt, *bt = NULL;
	struct blk_trace *bt = NULL;
	int ret = -ENOMEM;
	int ret = -ENOMEM;


	bt = kzalloc(sizeof(*bt), GFP_KERNEL);
	bt = kzalloc(sizeof(*bt), GFP_KERNEL);
@@ -1497,12 +1494,9 @@ static int blk_trace_setup_queue(struct request_queue *q,


	blk_trace_setup_lba(bt, bdev);
	blk_trace_setup_lba(bt, bdev);


	old_bt = xchg(&q->blk_trace, bt);
	if (old_bt != NULL) {
		(void)xchg(&q->blk_trace, old_bt);
	ret = -EBUSY;
	ret = -EBUSY;
	if (cmpxchg(&q->blk_trace, NULL, bt))
		goto free_bt;
		goto free_bt;
	}


	if (atomic_inc_return(&blk_probes_ref) == 1)
	if (atomic_inc_return(&blk_probes_ref) == 1)
		blk_register_tracepoints();
		blk_register_tracepoints();