Mike Christie wrote:
> Dev, Vasu wrote:
>>> The locking and refcount use is really weird now though. Would it be
>>> cleaner or more standard to just say that you need to always grab the
>>> lock when accessing the ex_refcount instead of sometimes doing it and
>>> sometimes not (too confusing).
>> Currently exch ref count can be changed(inc/dec) without having need to hold
>> exch lock, but this can be revised as suggested above to always have exch
>> lock for changing exch ref. However as you mentioned in other email that
>> exch ref and locking is still nicer than fsp pkt locking and doesn't need
>> expensive del_timer_sync() as used in FCP.
> 
> I am not sure what you mean by combining the two issues? For the FCP 
> path we do not need the pkt lock for the actual release or hold of the 
> refcount. We actually nornally never have the pkt lock when we do the 
> final release, because fc_fcp_unlock_pkt drops the lock then drops the 
> refcount.
> 
> My comment about the del timer and refcounts is just about not needing 
> to use the del_timer_sync with the exahnge code because the timer 
> operation should always have a refcount.
> 
> My comment about taking the lock around the exhange hold/release is just 
> about what the locks and refcounts are protecting? I mean it seems like 
> we are trying to do the two operations:
> 
> exchange mp->exches lookup + hold
> and
> mp->exches clear + release
> 
> atomically. We currently do both the lookup and hold under the 
> mp->em_lock, but we do the release without the lock and take it only if 
> the refcount is zero so we can clear the mp->exches array among other 
> things. And this is racey because it seems like we want do drop the 
> refcount and clear the mp->exches atomically.
> 
> So with your patch we now drop the count without the lock, but if zero 
> grab the lock to check the refcont again which seems weird because 
> normally when a refcount goes to zero it means that we are going to free 
> it. I mean if we were strict and we used krefs this would not be 
> possible, and if you tried to send a patch for kref_put to do an extra 
> check it is easier to imagine Christoph telling us whatever we are 
> trying to do is crap over Greg happily taking it.
> 

After I thought this over the night, I think both solutions are equally 
ugly :) so maybe there is something more fundamentally wrong with what 
we are doing.

I am trying to fix the abort handling and I think that interacts with 
this. Right now we can go from fc_fcp_timeout to fc_timeout_error which 
calls seq_exch_abort then calls fc_io_compl and that calls scsi_done to 
return the command to the scsi layer. The problem with this is that 
after we have sent the abort we do not know the status of it. If it is a 
tape command scsi ml is not going to retry, but we really would like to 
tell st.c what is up with the command (if it got aborted or not). And 
for disk commands, if scsi-ml decides to kill it then we want to make 
sure the device is still not writing out data, when it is returned to 
the FS.

Also for the fc_fcp_timeout->fc_timeout_error path, if the seq_ptr is 
set we never call exch_done to clean up the response handler. 
fc_io_compl then does the release on the fsp from the initial allocation 
so if we ever do get a response the ep->resp is going to be accessing a 
freed (or possible reallocated to some other command) fsp.

Or if we have sent the abort, and then fc_fcp_recv gets a response for 
the scsi command that indicates it is done, then we call exch_done and 
if fc_exch_release frees the ep before the abort response comes in 
fc_exch.c does not get the abort response (which is not needed today 
because fc_eh_abort's response code does not exist and always timesout) 
but will be needed below), so any waiters are left timing out. 
fc_fcp_complete could actually check for this too scenario.

So I think for the abort code we want to do a hold on the exchange if it 
is sent, and fc_fcp.c wants to get a response. In fc_exch.c we want to 
do a hold on the ep in exch_abort. Then in the fc_fcp.c abort response 
handler, we can do a exch_done for the abort to release the 
seq_send_abort's hold. If the abort completely cleaned up the exchange 
fc_fcp.c could do another exch_done to release the hold that was done 
for the scsi command.

exch_done would then need to be modified so that instead of 
fc_exch_release doing

                 spin_lock_bh(&mp->em_lock);
                 WARN_ON(mp->total_exches <= 0);
                 mp->total_exches--;
                 mp->exches[ep->xid - mp->min_xid] = NULL;
                 list_del(&ep->ex_list);
                 spin_unlock_bh(&mp->em_lock);

exch_done would do that, then release its hold. And actually exch_done 
would need to check that if there were multiple ep->resp functions (one 
from fc_fcp_send_cmd and one from the abort) then we do not do the mp 
manipulation above until the exch_done has been called for the last 
ep->resp.

There are more corner cases like with all fun error handler, but I guess 
the main idea is that we would be moving the mp manipulation to 
exch_done instead of doing it in the release function. And exch_done 
would do the release after the mp manipulation, so we would not hit that 
race. The abort has a hold on the ep which is released by the abort 
caller when it calls exch_done. fc_fcp.c gets its abort responses and 
the fc_timeout_error path does not leave dangling ep->resps.

What do you think?
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to