On Fri, 2010-04-09 at 11:05 -0700, Joe Eykholt wrote:
> Robert Love wrote:
<snip>
> > @@ -328,8 +333,7 @@ static void fc_rport_work(struct work_struct *work)
> > lport->tt.exch_mgr_reset(lport, port_id, 0);
> >
> > if (rport) {
> > - rpriv = rport->dd_data;
> > - rpriv->rp_state = RPORT_ST_DELETE;
> > + rdata->rp_state = RPORT_ST_DELETE;
>
> This should not change the rdata state, which will already
> be either DELETE or RESTART.
I'm not changing the state, I'm just changing the variable name from
rpriv to rdata. If there's a bug because of the state assignment I think
it's different from what I'm trying to accomplish with this patch.
>
> > mutex_lock(&rdata->rp_mutex);
> > rdata->rport = NULL;
> > mutex_unlock(&rdata->rp_mutex);
> > @@ -1687,15 +1691,21 @@ void fc_destroy_rport()
> > }
> >
> > /**
> > - * fc_rport_terminate_io() - Stop all outstanding I/O on a remote port
> > - * @rport: The remote port whose I/O should be terminated
> > + * fc_rport_dev_loss_tmo_callbk() - Final cleanup of fc_rport_priv
> > + * @rport: The remote port that is going to be freed
> > + *
> > + * The rport is about to be freed by the FC Transport. The transport
> > + * has already terminated all rport I/O and now it's about to do
> > + * the final cleanup. To libfc this just means decrementing the
> > + * reference count so the fc_rport_priv can be freed.
> > */
> > -void fc_rport_terminate_io(struct fc_rport *rport)
> > +void fc_rport_dev_loss_tmo_callbk(struct fc_rport *rport)
> > {
> > - struct fc_rport_libfc_priv *rpriv = rport->dd_data;
> > - struct fc_lport *lport = rpriv->local_port;
> > + struct fc_rport_priv *rdata = rport_to_rport_priv(rport);
> > + struct fc_lport *lport = rdata->local_port;
> >
> > lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
> > lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
> > + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
> > }
> > -EXPORT_SYMBOL(fc_rport_terminate_io);
> > +EXPORT_SYMBOL(fc_rport_dev_loss_tmo_callbk);
> > diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
> > index a26bb50..021be0c 100644
> > --- a/include/scsi/libfc.h
> > +++ b/include/scsi/libfc.h
> > @@ -160,24 +160,6 @@ struct fc_rport_operations {
> > };
> >
> > /**
> > - * struct fc_rport_libfc_priv - libfc internal information about a remote
> > port
> > - * @local_port: The associated local port
> > - * @rp_state: Indicates READY for I/O or DELETE when blocked
> > - * @flags: REC and RETRY supported flags
> > - * @e_d_tov: Error detect timeout value (in msec)
> > - * @r_a_tov: Resource allocation timeout value (in msec)
> > - */
> > -struct fc_rport_libfc_priv {
> > - struct fc_lport *local_port;
> > - enum fc_rport_state rp_state;
> > - u16 flags;
> > - #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
> > - #define FC_RP_FLAGS_RETRY (1 << 1)
> > - unsigned int e_d_tov;
> > - unsigned int r_a_tov;
> > -};
>
> Instead of removing this we could make it a bit smaller, perhaps.
> It's already tiny. Flags could be u8. The rp_state could
> be packed into a u8.
>
The size doesn't bother me although I think your suggestions are good.
I'm trying to eliminate the initialization race between fc_rport_work
and fc_queuecommand since there's nothing to guarantee that
fc_queuecommand won't get called before fc_rport_libfc_priv is
initialized and we need it initialized before proceeding to get the
flags.
> > -
> > -/**
> > * struct fc_rport_priv - libfc remote port and discovery info
> > * @local_port: The associated local port
> > * @rport: The FC transport remote port
> > @@ -202,6 +184,8 @@ struct fc_rport_priv {
> > struct kref kref;
> > enum fc_rport_state rp_state;
> > struct fc_rport_identifiers ids;
> > + #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
> > + #define FC_RP_FLAGS_RETRY (1 << 1)
>
> Let's put the definitions after the flags if we do this.
>
Will do.
> > u16 flags;
> > u16 max_seq;
> > u16 disc_id;
> > @@ -218,6 +202,9 @@ struct fc_rport_priv {
> > u32 supported_classes;
> > };
> >
> > +#define rport_to_rport_priv(r) \
> > + (*((struct fc_rport_priv**)r->dd_data))
>
> r should be in parentheses. Space before **.
>
Thanks, will do.
> > +
> > /**
> > * struct fcoe_dev_stats - fcoe stats structure
> > * @SecondsSinceLastReset: Seconds since the last reset
> > @@ -989,7 +976,7 @@ int fc_lport_bsg_request(struct fc_bsg_job *);
> > * REMOTE PORT LAYER
> > *****************************/
> > int fc_rport_init(struct fc_lport *);
> > -void fc_rport_terminate_io(struct fc_rport *);
> > +void fc_rport_dev_loss_tmo_callbk(struct fc_rport *);
> >
> > /*
> > * DISCOVERY LAYER
>
> I remember struggling with this when I did the rport
> rework a year or two ago. I had initially gotten rid
> of fc_rport_libfc_priv and then brought it back.
> A couple of issues I can remember:
>
> First, the dd_data area still will not be filled in immediately after
> fc_rport is created, so rport_to_rport_priv() could return NULL.
There are only a few times when we want to do a rport_to_rport_priv.
1) dev loss callback
- rport would have been allocated
2) fc_rport_work- when assigning the rport_priv to dd_data
- rport was just created with dd_data and returned
3) fcp_cmd_send
- fc_queuecommand checking for rport_to_rport_priv ensures this call is
never made without a valid rport_priv
4) fc_fcp_timeout
- called from fcp_cmd_send, same reasoning as #3
5) fc_fcp_rec
- REC is after an I/O has passed fc_queuecommand, same as #3
6) fc_fcp_rec_resp
- response to command that passed queuecommand, same as #3
7) fc_fcp_srr
- same as #6
8) fc_queuecommand
- checks for NULL to ensure no I/O passes
I think this shows that the only time rport_to_rport_priv could be
called and return NULL is in fc_queuecommand and it's checking for NULL.
> We need to check for that. Maybe creating with no roles and
> changing them after setting the pointer would fix that.
>
> BTW, there's an existing problem where if the roles change, we don't
> report the role change to scsi_transport_fc. I have a fix for
> that in my next set of patches. It doesn't come up unless you
> have a node that changes from initiator to target.
>
> Two: the remote port could restart, and we could end up with
> two rdatas for the same rport.
>
> After fc_rport_work() takes rdata out of the list, any
> newly-discovered rport or received PLOGI
> will cause a new rdata to be created and used. Then when
> the transport create is called it will return with an rport
> with dd_data already set. We have to either drop the old one
> (which may be in use by drivers somehow) or the new one,
> which may be used by new incoming requests. This seems like
Yeah, this is a problem. Thanks for pointing it out. I'll need to think
more about this.
> the main problem. It simplifies the drivers and fc_fcp if
> they don't need to hold/release rdata or worry about it
> going away. Delaying the free until devloss timeout helps
> with that, but since the rport may restart and get re-created,
> there's the above problem.
>
> We can't create the transport rport as soon as we like
> because we don't know the port_name and node_name and roles
> right away, and those might be used in binding. So, we have
> to keep the rdata independent from the rport, but there's
> got to be the separate dd_data that travels with the
> transport rport and gives just enough info (timeouts and
> flags) that is needed for I/O. It's always allocated
> by the transport, but may not be filled in.
>
> Re-reading some of that old mail might reveal some better
> arguments why this is needed.
>
> I think the existing rport stuff works fairly well.
> I trust it. Let's change it too much.
^ "not" ? :)
The only other solution I have right now is to simply set an
'initialized' flag in fc_rport_libfc_priv and then set it to 1 once
fc_rport_work has set up its members after the remote_port_add. In
fc_queuecommand we'd just check if it was initialized or not.
Thanks for the comments, //Rob
_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel