Hi, On Fri, Oct 2, 2020 at 7:15 AM Manivannan Sadhasivam <manivannan.sadhasi...@linaro.org> wrote: > > The rcu_read_lock() is not supposed to lock the kernel_sendmsg() API > since it has the lock_sock() in qrtr_sendmsg() which will sleep. Hence, > fix it by excluding the locking for kernel_sendmsg(). > > Fixes: a7809ff90ce6 ("net: qrtr: ns: Protect radix_tree_deref_slot() using > rcu read locks") > Reported-by: Doug Anderson <diand...@chromium.org> > Tested-by: Alex Elder <el...@linaro.org> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasi...@linaro.org> > --- > net/qrtr/ns.c | 20 ++++++++++++++------ > 1 file changed, 14 insertions(+), 6 deletions(-) > > diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c > index 934999b56d60..0515433de922 100644 > --- a/net/qrtr/ns.c > +++ b/net/qrtr/ns.c > @@ -203,15 +203,17 @@ static int announce_servers(struct sockaddr_qrtr *sq) > /* Announce the list of servers registered in this node */ > radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { > srv = radix_tree_deref_slot(slot); > + rcu_read_unlock();
My RCU-fu is mediocre at best and my radix-tree knowledge is non-existent. However: => Reading through radix_tree_deref_slot() it says that if you are only holding the read lock that you need to be calling radix_tree_deref_retry(). Why don't I see that here? => Without any real knowledge, it seems super sketchy to drop the lock while iterating over the tree. Somehow that feels unsafe. Hrm, there seems to be a function radix_tree_iter_resume() that might be exactly what you want, but I'm not totally sure. The only user I can see in-tree (other than radix tree regression testing) is btrfs-tests.c but it's using it together with radix_tree_deref_slot_protected(). In any case, my totally untested and totally knowedge-free proposal would look something like this: rcu_read_lock(); /* Announce the list of servers registered in this node */ radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { srv = radix_tree_deref_slot(slot); if (!srv) continue; if (radix_tree_deref_retry(srv)) { slot = radix_tree_iter_retry(&iter); continue; } slot = radix_tree_iter_resume(slot, &iter); rcu_read_unlock(); ret = service_announce_new(sq, srv); if (ret < 0) { pr_err("failed to announce new service\n"); return ret; } rcu_read_lock(); } rcu_read_unlock(); What a beast! Given that this doesn't seem to be what anyone else in the kernel is doing exactly, it makes me suspect that there's a more fundamental design issue here, though... -Doug