On 11/04/2017 11:26 AM, Jens Axboe wrote:
> On 10/31/2017 05:14 PM, Steven Rostedt wrote:
>> On Tue, 31 Oct 2017 16:30:41 -0600
>> Jens Axboe <[email protected]> wrote:
>>
>>> This code dates back to:
>>>
>>> commit c71a896154119f4ca9e89d6078f5f63ad60ef199
>>> Author: Arnaldo Carvalho de Melo <[email protected]>
>>> Date:   Fri Jan 23 12:06:27 2009 -0200
>>>
>>>     blktrace: add ftrace plugin
>>>
>>> so not really a recent regression :-)
>>
>> How many people run two instances of blktrace? ;-> 
>> Love fuzzers!
> 
> The core code is fine, the bug is actually in sg which added
> hooks for both doing setup/teardown and start/stop of tracing.
> This was done bypassing the internal locking...
> 
> The below should do the trick. It's a fix for this commit:
> 
> commit 6da127ad0918f93ea93678dad62ce15ffed18797
> Author: Christof Schmitt <[email protected]>
> Date:   Fri Jan 11 10:09:43 2008 +0100
> 
>     blktrace: Add blktrace ioctls to SCSI generic devices

Forgot the critical bit, updated.


diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 45a3928544ce..206e0e2ace53 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -66,7 +66,8 @@ static struct tracer_flags blk_tracer_flags = {
 };
 
 /* Global reference count of probes */
-static atomic_t blk_probes_ref = ATOMIC_INIT(0);
+static DEFINE_MUTEX(blk_probe_mutex);
+static int blk_probes_ref;
 
 static void blk_register_tracepoints(void);
 static void blk_unregister_tracepoints(void);
@@ -329,14 +330,29 @@ static void blk_trace_free(struct blk_trace *bt)
        kfree(bt);
 }
 
+static void get_probe_ref(void)
+{
+       mutex_lock(&blk_probe_mutex);
+       if (++blk_probes_ref == 1)
+               blk_register_tracepoints();
+       mutex_unlock(&blk_probe_mutex);
+}
+
+static void put_probe_ref(void)
+{
+       mutex_lock(&blk_probe_mutex);
+       if (!--blk_probes_ref)
+               blk_unregister_tracepoints();
+       mutex_unlock(&blk_probe_mutex);
+}
+
 static void blk_trace_cleanup(struct blk_trace *bt)
 {
        blk_trace_free(bt);
-       if (atomic_dec_and_test(&blk_probes_ref))
-               blk_unregister_tracepoints();
+       put_probe_ref();
 }
 
-int blk_trace_remove(struct request_queue *q)
+static int __blk_trace_remove(struct request_queue *q)
 {
        struct blk_trace *bt;
 
@@ -349,6 +365,17 @@ int blk_trace_remove(struct request_queue *q)
 
        return 0;
 }
+
+int blk_trace_remove(struct request_queue *q)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_remove(q);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_remove);
 
 static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
@@ -538,8 +565,7 @@ static int do_blk_trace_setup(struct request_queue *q, char 
*name, dev_t dev,
        if (cmpxchg(&q->blk_trace, NULL, bt))
                goto err;
 
-       if (atomic_inc_return(&blk_probes_ref) == 1)
-               blk_register_tracepoints();
+       get_probe_ref();
 
        ret = 0;
 err:
@@ -550,9 +576,8 @@ static int do_blk_trace_setup(struct request_queue *q, char 
*name, dev_t dev,
        return ret;
 }
 
-int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
-                   struct block_device *bdev,
-                   char __user *arg)
+static int __blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                            struct block_device *bdev, char __user *arg)
 {
        struct blk_user_trace_setup buts;
        int ret;
@@ -571,6 +596,19 @@ int blk_trace_setup(struct request_queue *q, char *name, 
dev_t dev,
        }
        return 0;
 }
+
+int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                   struct block_device *bdev,
+                   char __user *arg)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_setup(q, name, dev, bdev, arg);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_setup);
 
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
@@ -607,7 +645,7 @@ static int compat_blk_trace_setup(struct request_queue *q, 
char *name,
 }
 #endif
 
-int blk_trace_startstop(struct request_queue *q, int start)
+static int __blk_trace_startstop(struct request_queue *q, int start)
 {
        int ret;
        struct blk_trace *bt = q->blk_trace;
@@ -646,6 +684,17 @@ int blk_trace_startstop(struct request_queue *q, int start)
 
        return ret;
 }
+
+int blk_trace_startstop(struct request_queue *q, int start)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_startstop(q, start);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_startstop);
 
 /*
@@ -676,7 +725,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned 
cmd, char __user *arg)
        switch (cmd) {
        case BLKTRACESETUP:
                bdevname(bdev, b);
-               ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
+               ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
                break;
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
        case BLKTRACESETUP32:
@@ -687,10 +736,10 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned 
cmd, char __user *arg)
        case BLKTRACESTART:
                start = 1;
        case BLKTRACESTOP:
-               ret = blk_trace_startstop(q, start);
+               ret = __blk_trace_startstop(q, start);
                break;
        case BLKTRACETEARDOWN:
-               ret = blk_trace_remove(q);
+               ret = __blk_trace_remove(q);
                break;
        default:
                ret = -ENOTTY;
@@ -708,10 +757,14 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned 
cmd, char __user *arg)
  **/
 void blk_trace_shutdown(struct request_queue *q)
 {
+       mutex_lock(&q->blk_trace_mutex);
+
        if (q->blk_trace) {
-               blk_trace_startstop(q, 0);
-               blk_trace_remove(q);
+               __blk_trace_startstop(q, 0);
+               __blk_trace_remove(q);
        }
+
+       mutex_unlock(&q->blk_trace_mutex);
 }
 
 #ifdef CONFIG_BLK_CGROUP
@@ -1558,9 +1611,7 @@ static int blk_trace_remove_queue(struct request_queue *q)
        if (bt == NULL)
                return -EINVAL;
 
-       if (atomic_dec_and_test(&blk_probes_ref))
-               blk_unregister_tracepoints();
-
+       put_probe_ref();
        blk_trace_free(bt);
        return 0;
 }
@@ -1591,8 +1642,7 @@ static int blk_trace_setup_queue(struct request_queue *q,
        if (cmpxchg(&q->blk_trace, NULL, bt))
                goto free_bt;
 
-       if (atomic_inc_return(&blk_probes_ref) == 1)
-               blk_register_tracepoints();
+       get_probe_ref();
        return 0;
 
 free_bt:

-- 
Jens Axboe

Reply via email to