Hi Doug, On Fri, Oct 02, 2020 at 08:28:51AM -0700, Doug Anderson wrote: > 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? >
Well, I drew inspiration from peer drivers and didn't look into the API documentation properly, my bad :( > => 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... > That's how it is supposed to be. So I'm going to roll out next revision with your suggestion for the rest of the deref_slot() calls also. Thanks for your time looking into this. Regards, Mani > -Doug