Skip to content

Commit 9e556da

Browse files
Casey Bodleyunknown
authored andcommitted
deleg: handle locks locally on write delegation
new flags for nfs41_lock_state: exclusive, delegated, and id on lock, open_lock_delegate() attempts to register a delegated lock instead of sending a LOCK request to the server on unlock, open_unlock_delegate() removes/frees delegated locks instead of sending a LOCKU request on delegreturn, delegation_flush_locks() sends LOCK requests for all delegated locks before returning a delegation on recovery, recover_locks() avoids lock state recovery for delegated locks Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
1 parent 284c273 commit 9e556da

File tree

4 files changed

+294
-109
lines changed

4 files changed

+294
-109
lines changed

daemon/delegation.c

Lines changed: 138 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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

91137
static 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;
101147
out:
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

Comments
 (0)