Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0
0002 
0003 =================
0004 Lockdep-RCU Splat
0005 =================
0006 
0007 Lockdep-RCU was added to the Linux kernel in early 2010
0008 (http://lwn.net/Articles/371986/).  This facility checks for some common
0009 misuses of the RCU API, most notably using one of the rcu_dereference()
0010 family to access an RCU-protected pointer without the proper protection.
0011 When such misuse is detected, an lockdep-RCU splat is emitted.
0012 
0013 The usual cause of a lockdep-RCU slat is someone accessing an
0014 RCU-protected data structure without either (1) being in the right kind of
0015 RCU read-side critical section or (2) holding the right update-side lock.
0016 This problem can therefore be serious: it might result in random memory
0017 overwriting or worse.  There can of course be false positives, this
0018 being the real world and all that.
0019 
0020 So let's look at an example RCU lockdep splat from 3.0-rc5, one that
0021 has long since been fixed::
0022 
0023     =============================
0024     WARNING: suspicious RCU usage
0025     -----------------------------
0026     block/cfq-iosched.c:2776 suspicious rcu_dereference_protected() usage!
0027 
0028 other info that might help us debug this::
0029 
0030     rcu_scheduler_active = 1, debug_locks = 0
0031     3 locks held by scsi_scan_6/1552:
0032     #0:  (&shost->scan_mutex){+.+.}, at: [<ffffffff8145efca>]
0033     scsi_scan_host_selected+0x5a/0x150
0034     #1:  (&eq->sysfs_lock){+.+.}, at: [<ffffffff812a5032>]
0035     elevator_exit+0x22/0x60
0036     #2:  (&(&q->__queue_lock)->rlock){-.-.}, at: [<ffffffff812b6233>]
0037     cfq_exit_queue+0x43/0x190
0038 
0039     stack backtrace:
0040     Pid: 1552, comm: scsi_scan_6 Not tainted 3.0.0-rc5 #17
0041     Call Trace:
0042     [<ffffffff810abb9b>] lockdep_rcu_dereference+0xbb/0xc0
0043     [<ffffffff812b6139>] __cfq_exit_single_io_context+0xe9/0x120
0044     [<ffffffff812b626c>] cfq_exit_queue+0x7c/0x190
0045     [<ffffffff812a5046>] elevator_exit+0x36/0x60
0046     [<ffffffff812a802a>] blk_cleanup_queue+0x4a/0x60
0047     [<ffffffff8145cc09>] scsi_free_queue+0x9/0x10
0048     [<ffffffff81460944>] __scsi_remove_device+0x84/0xd0
0049     [<ffffffff8145dca3>] scsi_probe_and_add_lun+0x353/0xb10
0050     [<ffffffff817da069>] ? error_exit+0x29/0xb0
0051     [<ffffffff817d98ed>] ? _raw_spin_unlock_irqrestore+0x3d/0x80
0052     [<ffffffff8145e722>] __scsi_scan_target+0x112/0x680
0053     [<ffffffff812c690d>] ? trace_hardirqs_off_thunk+0x3a/0x3c
0054     [<ffffffff817da069>] ? error_exit+0x29/0xb0
0055     [<ffffffff812bcc60>] ? kobject_del+0x40/0x40
0056     [<ffffffff8145ed16>] scsi_scan_channel+0x86/0xb0
0057     [<ffffffff8145f0b0>] scsi_scan_host_selected+0x140/0x150
0058     [<ffffffff8145f149>] do_scsi_scan_host+0x89/0x90
0059     [<ffffffff8145f170>] do_scan_async+0x20/0x160
0060     [<ffffffff8145f150>] ? do_scsi_scan_host+0x90/0x90
0061     [<ffffffff810975b6>] kthread+0xa6/0xb0
0062     [<ffffffff817db154>] kernel_thread_helper+0x4/0x10
0063     [<ffffffff81066430>] ? finish_task_switch+0x80/0x110
0064     [<ffffffff817d9c04>] ? retint_restore_args+0xe/0xe
0065     [<ffffffff81097510>] ? __kthread_init_worker+0x70/0x70
0066     [<ffffffff817db150>] ? gs_change+0xb/0xb
0067 
0068 Line 2776 of block/cfq-iosched.c in v3.0-rc5 is as follows::
0069 
0070         if (rcu_dereference(ioc->ioc_data) == cic) {
0071 
0072 This form says that it must be in a plain vanilla RCU read-side critical
0073 section, but the "other info" list above shows that this is not the
0074 case.  Instead, we hold three locks, one of which might be RCU related.
0075 And maybe that lock really does protect this reference.  If so, the fix
0076 is to inform RCU, perhaps by changing __cfq_exit_single_io_context() to
0077 take the struct request_queue "q" from cfq_exit_queue() as an argument,
0078 which would permit us to invoke rcu_dereference_protected as follows::
0079 
0080         if (rcu_dereference_protected(ioc->ioc_data,
0081                                       lockdep_is_held(&q->queue_lock)) == cic) {
0082 
0083 With this change, there would be no lockdep-RCU splat emitted if this
0084 code was invoked either from within an RCU read-side critical section
0085 or with the ->queue_lock held.  In particular, this would have suppressed
0086 the above lockdep-RCU splat because ->queue_lock is held (see #2 in the
0087 list above).
0088 
0089 On the other hand, perhaps we really do need an RCU read-side critical
0090 section.  In this case, the critical section must span the use of the
0091 return value from rcu_dereference(), or at least until there is some
0092 reference count incremented or some such.  One way to handle this is to
0093 add rcu_read_lock() and rcu_read_unlock() as follows::
0094 
0095         rcu_read_lock();
0096         if (rcu_dereference(ioc->ioc_data) == cic) {
0097                 spin_lock(&ioc->lock);
0098                 rcu_assign_pointer(ioc->ioc_data, NULL);
0099                 spin_unlock(&ioc->lock);
0100         }
0101         rcu_read_unlock();
0102 
0103 With this change, the rcu_dereference() is always within an RCU
0104 read-side critical section, which again would have suppressed the
0105 above lockdep-RCU splat.
0106 
0107 But in this particular case, we don't actually dereference the pointer
0108 returned from rcu_dereference().  Instead, that pointer is just compared
0109 to the cic pointer, which means that the rcu_dereference() can be replaced
0110 by rcu_access_pointer() as follows::
0111 
0112         if (rcu_access_pointer(ioc->ioc_data) == cic) {
0113 
0114 Because it is legal to invoke rcu_access_pointer() without protection,
0115 this change would also suppress the above lockdep-RCU splat.