Re: [PATCH v3 08/16] nvmet-fc: untangle cross refcounting objects

From: Daniel Wagner
Date: Fri Jan 26 2024 - 10:32:46 EST


On Thu, Dec 21, 2023 at 10:17:30AM +0100, Daniel Wagner wrote:
> On Tue, Dec 19, 2023 at 06:16:48AM +0100, Christoph Hellwig wrote:
> > On Mon, Dec 18, 2023 at 04:30:56PM +0100, Daniel Wagner wrote:
> > > The live time of the queues are strictly bound to the lifetime of an
> >
> > > + struct nvmet_fc_tgt_queue *_queues[NVMET_NR_QUEUES + 1];
> > > struct nvmet_fc_tgt_queue __rcu *queues[NVMET_NR_QUEUES + 1];
> >
> > For magic prefixes we use __, not _ in Linux. But having two arrays
> > of queues right next to each other, once with rcu annotation and one
> > not rings a bit far warning bell to me. Why do we have both? When
> > are we supposed to use either? Why is FC different from rest?
>
> This is my attempt to solve the problem that after NULLing the rcu
> pointer and wait for an RCU graceperiod I still need to cleanup the
> queues. Thus I need to keep hold on the queue pointers a bit longer.
> Indeed not so elegant.
>
> I'm sure there is a better way to do it, I just didn't figure it out
> when I wrote this part. Any tips are highly welcomed how to solve this
> puzzle.

Looking at this code again, I don't think we need use RCU for the queues
pointers at all. The association is already under RCU and thus the
queues pointers don't need additional RCUing. We either can lookup the
association or not and the queue pointer's lifetime is under kref rules.
So with this in mind the lookup would be:

rcu_read_lock();
list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
if (association_id == assoc->association_id) {
queue = assoc->queues[qid];
if (queue &&
(!atomic_read(&queue->connected) ||
!nvmet_fc_tgt_q_get(queue)))
queue = NULL;
rcu_read_unlock();
return queue;
}
}
rcu_read_unlock();
return NULL;

No need for more complexity :)