Subject: issue with LOCK being able to return an update open_stateid

From: Spencer Shepler <[email-masked]>
Date: Wed, 4 Sep 2002 15:59:34 -0500

In reviewing the state transitions in the protocol, I have found a
problem with the LOCK operation in the case that a new lock_owner is
being used.

The general issue is that the server does not have a method of
returning a new open_owner stateid at the transition from open_owner
to lock_owner.  Since one of the purposes of the stateids and their
respective transitions is to prevent things like out-of-order
processing of READs and WRITEs, the server is unable to protect
against a scenario like the following:

Client						Server
------						------
OPEN(open_owner,seqid[1])	->		
				<-		OPENres(open_stateid[1])
READ(open_stateid[1])		->		
				<-		READres
WRITE(open_stateid[1])		->
	|response delayed|	<-		WRITEres
WRITE(open_stateid[1]) [retrans]->

	|response received to initial WRITE|

LOCK(open_stateid[1],seqid[2],
     lock_owner,lock_seqid[1])	->
				<-		LOCKres(lock_stateid[1])
				|retransmitted WRITE processed|
				<-		WRITEres (of retrans request)

So at the point of processing the retransmitted WRITE, the server has
no method to determine if the retransmitted WRITE request (in this
case) was sent before or after the LOCK operation was processed.
It is true that the servers duplicate request cache may catch this
scenario but it is not a guarantee.

For the client and server to interact appropriately, the server must
be able to return an open_stateid as well as a lock_stateid on the
initial LOCK request.

To correct this, I propose the following changes be made to the
protocol description file: nfs4_prot.x

CHANGE:

struct LOCK4resok {
	stateid4	lock_stateid;
};

TO:

struct new_lock_owner_res4 {
	stateid4	open_stateid;
	stateid4	lock_stateid;
};

union LOCK4resok switch (bool new_lock_owner) {
case TRUE:
	new_lock_owner_res4	open_lock_stateids;
case FALSE:
	stateid4	lock_stateid;
};

As stated above, this allows the server to transition the open_stateid
at the first LOCK for a lock_owner.  This therefore extends the
coverage of stateid checking the server can do for I/O operations.
The client does not have any additional serialization beyond what is
needed today since the client must serialize its requests via the
open_seqid.  Therefore, no additional burden for the client.

This change is easy to make in implementations because the LOCK
processing in this case will have access to the necessary data
structures for checking the open_seqid and generating the new
lock_owner data structures.

Spencer

---

From: Mike Eisler <[email-masked]>
Date: Wed, 04 Sep 2002 18:45:07 -0700

>         new_lock_owner_res4     open_lock_stateids;

Change open_statid and lock_stateid
are swapped.  This way the first 4 bytes in the XDR
tream after the new_lock_owner discriminator are
always a lock_stateid.

	-mre