This short note will potentially explain the states and transitions
available on an FCB complex. For those just tuning in, a fileobject (FO)
refers to an FCB (File Control Block) and an FOBX (File Object
Extension). There is a 1-1 correspondence between FOs and FOBXs. Many
FOs may/will refer to the same FCB which represents a single file
somewhere on some server. A client may have several different opens
(NtCreates) on the same FCB and each of these will create a new file
object. What is interesting is that the rdr may choose to send fewer
SMBcreates than it receives NtCreates in effect sharing a server-open
(SVROPEN) among several FOBXs.

Another interesting tidbit is that the rdr doesn't necessarily close its
SRVOPENs when the user opens close hoping that it can reuse the open and
the data without any contact with the server. We say that an FCB is
client-side-open (CSO) if there are user opens openstanding on the FCB.
It is server-side-open is there are existing SRVOPENs on the FCB. From
all of this, the following table explains what can happen on a user open
(assuming the netroot is good):

   Create?  CS-Open?   SS-Open?    Action
   -----------------------------------------
     Yes      Open      Open       ERROR
              Open     Closed      IMPOSSIBLE
             Closed     Open       CloseAllSrvOpens();NewOpen()
             Closed    Closed      NewOpen()
     No       Open      Open       NotSharable()-->NewOpen()
              Open     Closed      IMPOSSIBLE
             Closed     Open       NotSharable()-->NewOpen()
             Closed    Closed      NewOpen()

Thus, it actually boils down to a pretty simple scheme:

        (Create && CS-Open) ==> return ERROR;
        (Create && SS-Open && !CS-Open) ==> CloseAllSrvOpens();
        (NotShareable()) ==> return NewOpen();
        return SharableOpen();


A careful review here shows us what must happen on cleanup:
specifically, we must do whatever it takes to cleanup the clientside as
appropriate.  Further, if the open is the last user open and
DELETE-ON-CLOSE or TRUNCATE-ON-CLOSE are operative, then we must drive
the FCB into the CLOSED/CLOSED state; otherwise, we may elect to leave
SRVOPENs open even if there are no current opens.  Since the subrdr is
the best judge of whether closing or keeping is appropriate, we call
down on the transition (SRXSrvOpenTransitioningToClosed).  When the
subrdr gets this call, it may elect to (a) close the current SRVOPEN,
(b) close SRVOPENs with no associated user opens, (c) do nothing and
rely on the RDBSS to call down for real closes at the correct time.

If the subrdr chooses to allow the SRVOPEN to remain, the RDBSS will
take some steps close ones that remain according to some criteria that
(a) haven't been worked out yet and (b) need to be very flexible.
Probably this will be another calldown (SRXClosedSrvOpenTimeOut).  The
same is true of the FCB itself....after some reasonbale period, it and
the cached data (if any) that it represents should be finalized.
Another pair of calldowns (i.e.  SRXFcbTransitioningToClosed and
SRXClosedFcbTimeOut).

So, the following sums it up for cleanup:

(Delete||Truncate)&&LastCSOpenPerFcb => CloseAllSrvOpens();
ELSE  LastCSOpenPerSrvOpen => SRXSrvOpenTransitioningToClosed();
ELSE (we'll do it on a timer)

Notice that if the subrdr wants to do something aggressive like close
the srvopen and finalize, then it will have to take out the appropriate
locks itself. The RDBSS isn't going to take the locks just so the subrdr
can say "no, thx". Currently, we uninitialize the cachemap as well and
count on the winding down logic of CM/MM to keep the map open for some
time....we will consider later forcing the CM to stay open (for example,
by putting our own reference on the fileobject).





















