@@ -84,19 +84,65 @@ void nfs41_delegation_deref(
8484 free (state );
8585}
8686
87+ #define open_entry (pos ) list_container(pos, nfs41_open_state, client_entry)
88+
89+ static void delegation_remove (
90+ IN nfs41_client * client ,
91+ IN nfs41_delegation_state * deleg )
92+ {
93+ struct list_entry * entry ;
94+
95+ /* remove from the client's list */
96+ EnterCriticalSection (& client -> state .lock );
97+ list_remove (& deleg -> client_entry );
98+
99+ /* remove from each associated open */
100+ list_for_each (entry , & client -> state .opens ) {
101+ nfs41_open_state * open = open_entry (entry );
102+ AcquireSRWLockExclusive (& open -> lock );
103+ if (open -> delegation .state == deleg ) {
104+ /* drop the delegation reference */
105+ nfs41_delegation_deref (open -> delegation .state );
106+ open -> delegation .state = NULL ;
107+ }
108+ ReleaseSRWLockExclusive (& open -> lock );
109+ }
110+ LeaveCriticalSection (& client -> state .lock );
111+
112+ /* signal threads waiting on delegreturn */
113+ AcquireSRWLockExclusive (& deleg -> lock );
114+ deleg -> status = DELEGATION_RETURNED ;
115+ WakeAllConditionVariable (& deleg -> cond );
116+ ReleaseSRWLockExclusive (& deleg -> lock );
117+
118+ /* release the client's reference */
119+ nfs41_delegation_deref (deleg );
120+ }
121+
87122
88123/* delegation return */
89- #define open_entry (pos ) list_container(pos, nfs41_open_state, client_entry)
124+ #define lock_entry (pos ) list_container(pos, nfs41_lock_state, open_entry)
125+
126+ static bool_t has_delegated_locks (
127+ IN nfs41_open_state * open )
128+ {
129+ struct list_entry * entry ;
130+ list_for_each (entry , & open -> locks .list ) {
131+ if (lock_entry (entry )-> delegated )
132+ return TRUE;
133+ }
134+ return FALSE;
135+ }
90136
91137static int open_deleg_cmp (const struct list_entry * entry , const void * value )
92138{
93139 nfs41_open_state * open = open_entry (entry );
94140 int result = -1 ;
95141
96- /* open must match the delegation and have no open stateid */
142+ /* open must match the delegation and have state to reclaim */
97143 AcquireSRWLockShared (& open -> lock );
98144 if (open -> delegation .state != value ) goto out ;
99- if (open -> do_close ) goto out ;
145+ if (open -> do_close && ! has_delegated_locks ( open ) ) goto out ;
100146 result = 0 ;
101147out :
102148 ReleaseSRWLockShared (& open -> lock );
@@ -121,37 +167,95 @@ static nfs41_open_state* deleg_open_find(
121167 return open ;
122168}
123169
124- static void delegation_remove (
125- IN nfs41_client * client ,
126- IN nfs41_delegation_state * deleg )
170+ /* find the first lock that needs recovery */
171+ static bool_t deleg_lock_find (
172+ IN nfs41_open_state * open ,
173+ OUT nfs41_lock_state * lock_out )
127174{
128175 struct list_entry * entry ;
176+ bool_t found = FALSE;
129177
130- /* remove from the client's list */
131- EnterCriticalSection (& client -> state .lock );
132- list_remove (& deleg -> client_entry );
178+ AcquireSRWLockShared (& open -> lock );
179+ list_for_each (entry , & open -> locks .list ) {
180+ nfs41_lock_state * lock = lock_entry (entry );
181+ if (lock -> delegated ) {
182+ /* copy offset, length, type */
183+ lock_out -> offset = lock -> offset ;
184+ lock_out -> length = lock -> length ;
185+ lock_out -> exclusive = lock -> exclusive ;
186+ lock_out -> id = lock -> id ;
187+ found = TRUE;
188+ break ;
189+ }
190+ }
191+ ReleaseSRWLockShared (& open -> lock );
192+ return found ;
193+ }
133194
134- /* remove from each associated open */
135- list_for_each (entry , & client -> state .opens ) {
136- nfs41_open_state * open = open_entry (entry );
137- AcquireSRWLockExclusive (& open -> lock );
138- if (open -> delegation .state == deleg ) {
139- /* drop the delegation reference */
140- nfs41_delegation_deref (open -> delegation .state );
141- open -> delegation .state = NULL ;
195+ /* find the matching lock by id, and reset lock.delegated */
196+ static void deleg_lock_update (
197+ IN nfs41_open_state * open ,
198+ IN const nfs41_lock_state * source )
199+ {
200+ struct list_entry * entry ;
201+
202+ AcquireSRWLockExclusive (& open -> lock );
203+ list_for_each (entry , & open -> locks .list ) {
204+ nfs41_lock_state * lock = lock_entry (entry );
205+ if (lock -> id == source -> id ) {
206+ lock -> delegated = FALSE;
207+ break ;
142208 }
143- ReleaseSRWLockExclusive (& open -> lock );
144209 }
145- LeaveCriticalSection (& client -> state .lock );
210+ ReleaseSRWLockExclusive (& open -> lock );
211+ }
146212
147- /* signal threads waiting on delegreturn */
148- AcquireSRWLockExclusive (& deleg -> lock );
149- deleg -> status = DELEGATION_RETURNED ;
150- WakeAllConditionVariable (& deleg -> cond );
151- ReleaseSRWLockExclusive (& deleg -> lock );
213+ static int delegation_flush_locks (
214+ IN nfs41_open_state * open ,
215+ IN bool_t try_recovery )
216+ {
217+ stateid_arg stateid ;
218+ nfs41_lock_state lock ;
219+ int status = NFS4_OK ;
152220
153- /* release the client's reference */
154- nfs41_delegation_deref (deleg );
221+ stateid .open = open ;
222+ stateid .delegation = NULL ;
223+
224+ /* get the starting open/lock stateid */
225+ AcquireSRWLockShared (& open -> lock );
226+ if (open -> locks .stateid .seqid ) {
227+ memcpy (& stateid .stateid , & open -> locks .stateid , sizeof (stateid4 ));
228+ stateid .type = STATEID_LOCK ;
229+ } else {
230+ memcpy (& stateid .stateid , & open -> stateid , sizeof (stateid4 ));
231+ stateid .type = STATEID_OPEN ;
232+ }
233+ ReleaseSRWLockShared (& open -> lock );
234+
235+ /* send LOCK requests for each delegated lock range */
236+ while (deleg_lock_find (open , & lock )) {
237+ status = nfs41_lock (open -> session , & open -> file ,
238+ & open -> owner , lock .exclusive ? WRITE_LT : READ_LT ,
239+ lock .offset , lock .length , FALSE, try_recovery , & stateid );
240+ if (status )
241+ break ;
242+ deleg_lock_update (open , & lock );
243+ }
244+
245+ /* save the updated lock stateid */
246+ if (stateid .type == STATEID_LOCK ) {
247+ AcquireSRWLockExclusive (& open -> lock );
248+ if (open -> locks .stateid .seqid == 0 ) {
249+ /* if it's a new lock stateid, copy it in */
250+ memcpy (& open -> locks .stateid , & stateid .stateid , sizeof (stateid4 ));
251+ } else if (stateid .stateid .seqid > open -> locks .stateid .seqid ) {
252+ /* update the seqid if it's more recent */
253+ open -> locks .stateid .seqid = stateid .stateid .seqid ;
254+ }
255+ ReleaseSRWLockExclusive (& open -> lock );
256+ }
257+ out :
258+ return status ;
155259}
156260
157261#pragma warning (disable : 4706) /* assignment within conditional expression */
@@ -163,16 +267,18 @@ static int delegation_return(
163267 IN bool_t try_recovery )
164268{
165269 stateid_arg stateid ;
166- int status = NFS4_OK ;
167-
168- /* recover opens associated with the delegation */
169270 nfs41_open_state * open ;
271+ int status ;
272+
273+ /* recover opens and locks associated with the delegation */
170274 while (open = deleg_open_find (& client -> state , deleg )) {
171275 status = nfs41_delegation_to_open (open , try_recovery );
276+ if (status == NFS4_OK )
277+ status = delegation_flush_locks (open , try_recovery );
172278 nfs41_open_state_deref (open );
173279
174- if (status == NFS4ERR_BADSESSION )
175- goto out ;
280+ if (status )
281+ break ;
176282 }
177283
178284 /* return the delegation */
@@ -494,7 +600,7 @@ int nfs41_delegation_return(
494600 }
495601 } else {
496602 /* the delegation is being returned, wait for it to finish */
497- while (deleg -> status != DELEGATION_RETURNED )
603+ while (deleg -> status == DELEGATION_RETURNING )
498604 SleepConditionVariableSRW (& deleg -> cond , & deleg -> lock , INFINITE , 0 );
499605 status = NFS4ERR_BADHANDLE ;
500606 }
0 commit comments