diff options
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r-- | fs/nfs/delegation.c | 80 |
1 files changed, 50 insertions, 30 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9f17b91205cf..cee2ba42b68d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -57,7 +57,7 @@ out_err: | |||
57 | return status; | 57 | return status; |
58 | } | 58 | } |
59 | 59 | ||
60 | static void nfs_delegation_claim_opens(struct inode *inode) | 60 | static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) |
61 | { | 61 | { |
62 | struct nfs_inode *nfsi = NFS_I(inode); | 62 | struct nfs_inode *nfsi = NFS_I(inode); |
63 | struct nfs_open_context *ctx; | 63 | struct nfs_open_context *ctx; |
@@ -72,6 +72,8 @@ again: | |||
72 | continue; | 72 | continue; |
73 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 73 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
74 | continue; | 74 | continue; |
75 | if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) | ||
76 | continue; | ||
75 | get_nfs_open_context(ctx); | 77 | get_nfs_open_context(ctx); |
76 | spin_unlock(&inode->i_lock); | 78 | spin_unlock(&inode->i_lock); |
77 | err = nfs4_open_delegation_recall(ctx, state); | 79 | err = nfs4_open_delegation_recall(ctx, state); |
@@ -170,33 +172,55 @@ static void nfs_msync_inode(struct inode *inode) | |||
170 | /* | 172 | /* |
171 | * Basic procedure for returning a delegation to the server | 173 | * Basic procedure for returning a delegation to the server |
172 | */ | 174 | */ |
173 | int __nfs_inode_return_delegation(struct inode *inode) | 175 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) |
174 | { | 176 | { |
175 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 177 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
176 | struct nfs_inode *nfsi = NFS_I(inode); | 178 | struct nfs_inode *nfsi = NFS_I(inode); |
177 | struct nfs_delegation *delegation; | ||
178 | int res = 0; | ||
179 | 179 | ||
180 | nfs_msync_inode(inode); | 180 | nfs_msync_inode(inode); |
181 | down_read(&clp->cl_sem); | 181 | down_read(&clp->cl_sem); |
182 | /* Guard against new delegated open calls */ | 182 | /* Guard against new delegated open calls */ |
183 | down_write(&nfsi->rwsem); | 183 | down_write(&nfsi->rwsem); |
184 | spin_lock(&clp->cl_lock); | 184 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
185 | delegation = nfsi->delegation; | ||
186 | if (delegation != NULL) { | ||
187 | list_del_init(&delegation->super_list); | ||
188 | nfsi->delegation = NULL; | ||
189 | nfsi->delegation_state = 0; | ||
190 | } | ||
191 | spin_unlock(&clp->cl_lock); | ||
192 | nfs_delegation_claim_opens(inode); | ||
193 | up_write(&nfsi->rwsem); | 185 | up_write(&nfsi->rwsem); |
194 | up_read(&clp->cl_sem); | 186 | up_read(&clp->cl_sem); |
195 | nfs_msync_inode(inode); | 187 | nfs_msync_inode(inode); |
196 | 188 | ||
197 | if (delegation != NULL) | 189 | return nfs_do_return_delegation(inode, delegation); |
198 | res = nfs_do_return_delegation(inode, delegation); | 190 | } |
199 | return res; | 191 | |
192 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | ||
193 | { | ||
194 | struct nfs_delegation *delegation = nfsi->delegation; | ||
195 | |||
196 | if (delegation == NULL) | ||
197 | goto nomatch; | ||
198 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | ||
199 | sizeof(delegation->stateid.data)) != 0) | ||
200 | goto nomatch; | ||
201 | list_del_init(&delegation->super_list); | ||
202 | nfsi->delegation = NULL; | ||
203 | nfsi->delegation_state = 0; | ||
204 | return delegation; | ||
205 | nomatch: | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | int nfs_inode_return_delegation(struct inode *inode) | ||
210 | { | ||
211 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
212 | struct nfs_inode *nfsi = NFS_I(inode); | ||
213 | struct nfs_delegation *delegation; | ||
214 | int err = 0; | ||
215 | |||
216 | if (nfsi->delegation_state != 0) { | ||
217 | spin_lock(&clp->cl_lock); | ||
218 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | ||
219 | spin_unlock(&clp->cl_lock); | ||
220 | if (delegation != NULL) | ||
221 | err = __nfs_inode_return_delegation(inode, delegation); | ||
222 | } | ||
223 | return err; | ||
200 | } | 224 | } |
201 | 225 | ||
202 | /* | 226 | /* |
@@ -218,8 +242,9 @@ restart: | |||
218 | inode = igrab(delegation->inode); | 242 | inode = igrab(delegation->inode); |
219 | if (inode == NULL) | 243 | if (inode == NULL) |
220 | continue; | 244 | continue; |
245 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
221 | spin_unlock(&clp->cl_lock); | 246 | spin_unlock(&clp->cl_lock); |
222 | nfs_inode_return_delegation(inode); | 247 | __nfs_inode_return_delegation(inode, delegation); |
223 | iput(inode); | 248 | iput(inode); |
224 | goto restart; | 249 | goto restart; |
225 | } | 250 | } |
@@ -243,8 +268,9 @@ restart: | |||
243 | inode = igrab(delegation->inode); | 268 | inode = igrab(delegation->inode); |
244 | if (inode == NULL) | 269 | if (inode == NULL) |
245 | continue; | 270 | continue; |
271 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
246 | spin_unlock(&clp->cl_lock); | 272 | spin_unlock(&clp->cl_lock); |
247 | nfs_inode_return_delegation(inode); | 273 | __nfs_inode_return_delegation(inode, delegation); |
248 | iput(inode); | 274 | iput(inode); |
249 | goto restart; | 275 | goto restart; |
250 | } | 276 | } |
@@ -285,8 +311,9 @@ restart: | |||
285 | inode = igrab(delegation->inode); | 311 | inode = igrab(delegation->inode); |
286 | if (inode == NULL) | 312 | if (inode == NULL) |
287 | continue; | 313 | continue; |
314 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
288 | spin_unlock(&clp->cl_lock); | 315 | spin_unlock(&clp->cl_lock); |
289 | nfs_inode_return_delegation(inode); | 316 | __nfs_inode_return_delegation(inode, delegation); |
290 | iput(inode); | 317 | iput(inode); |
291 | goto restart; | 318 | goto restart; |
292 | } | 319 | } |
@@ -316,21 +343,14 @@ static int recall_thread(void *data) | |||
316 | down_read(&clp->cl_sem); | 343 | down_read(&clp->cl_sem); |
317 | down_write(&nfsi->rwsem); | 344 | down_write(&nfsi->rwsem); |
318 | spin_lock(&clp->cl_lock); | 345 | spin_lock(&clp->cl_lock); |
319 | delegation = nfsi->delegation; | 346 | delegation = nfs_detach_delegation_locked(nfsi, args->stateid); |
320 | if (delegation != NULL && memcmp(delegation->stateid.data, | 347 | if (delegation != NULL) |
321 | args->stateid->data, | ||
322 | sizeof(delegation->stateid.data)) == 0) { | ||
323 | list_del_init(&delegation->super_list); | ||
324 | nfsi->delegation = NULL; | ||
325 | nfsi->delegation_state = 0; | ||
326 | args->result = 0; | 348 | args->result = 0; |
327 | } else { | 349 | else |
328 | delegation = NULL; | ||
329 | args->result = -ENOENT; | 350 | args->result = -ENOENT; |
330 | } | ||
331 | spin_unlock(&clp->cl_lock); | 351 | spin_unlock(&clp->cl_lock); |
332 | complete(&args->started); | 352 | complete(&args->started); |
333 | nfs_delegation_claim_opens(inode); | 353 | nfs_delegation_claim_opens(inode, args->stateid); |
334 | up_write(&nfsi->rwsem); | 354 | up_write(&nfsi->rwsem); |
335 | up_read(&clp->cl_sem); | 355 | up_read(&clp->cl_sem); |
336 | nfs_msync_inode(inode); | 356 | nfs_msync_inode(inode); |