diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 1480 |
1 files changed, 930 insertions, 550 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f988a9417b13..984ca3454d04 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -57,11 +57,13 @@ | |||
57 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 57 | #define NFS4_POLL_RETRY_MIN (1*HZ) |
58 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 58 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
59 | 59 | ||
60 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); | 60 | struct nfs4_opendata; |
61 | static int _nfs4_proc_open(struct nfs4_opendata *data); | ||
61 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 62 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
62 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 63 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
63 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 64 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
64 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 65 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
66 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | ||
65 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 67 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
66 | extern struct rpc_procinfo nfs4_procedures[]; | 68 | extern struct rpc_procinfo nfs4_procedures[]; |
67 | 69 | ||
@@ -173,8 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
173 | kunmap_atomic(start, KM_USER0); | 175 | kunmap_atomic(start, KM_USER0); |
174 | } | 176 | } |
175 | 177 | ||
176 | static void | 178 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
177 | renew_lease(struct nfs_server *server, unsigned long timestamp) | ||
178 | { | 179 | { |
179 | struct nfs4_client *clp = server->nfs4_state; | 180 | struct nfs4_client *clp = server->nfs4_state; |
180 | spin_lock(&clp->cl_lock); | 181 | spin_lock(&clp->cl_lock); |
@@ -194,21 +195,123 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf | |||
194 | spin_unlock(&inode->i_lock); | 195 | spin_unlock(&inode->i_lock); |
195 | } | 196 | } |
196 | 197 | ||
198 | struct nfs4_opendata { | ||
199 | atomic_t count; | ||
200 | struct nfs_openargs o_arg; | ||
201 | struct nfs_openres o_res; | ||
202 | struct nfs_open_confirmargs c_arg; | ||
203 | struct nfs_open_confirmres c_res; | ||
204 | struct nfs_fattr f_attr; | ||
205 | struct nfs_fattr dir_attr; | ||
206 | struct dentry *dentry; | ||
207 | struct dentry *dir; | ||
208 | struct nfs4_state_owner *owner; | ||
209 | struct iattr attrs; | ||
210 | unsigned long timestamp; | ||
211 | int rpc_status; | ||
212 | int cancelled; | ||
213 | }; | ||
214 | |||
215 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | ||
216 | struct nfs4_state_owner *sp, int flags, | ||
217 | const struct iattr *attrs) | ||
218 | { | ||
219 | struct dentry *parent = dget_parent(dentry); | ||
220 | struct inode *dir = parent->d_inode; | ||
221 | struct nfs_server *server = NFS_SERVER(dir); | ||
222 | struct nfs4_opendata *p; | ||
223 | |||
224 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
225 | if (p == NULL) | ||
226 | goto err; | ||
227 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
228 | if (p->o_arg.seqid == NULL) | ||
229 | goto err_free; | ||
230 | atomic_set(&p->count, 1); | ||
231 | p->dentry = dget(dentry); | ||
232 | p->dir = parent; | ||
233 | p->owner = sp; | ||
234 | atomic_inc(&sp->so_count); | ||
235 | p->o_arg.fh = NFS_FH(dir); | ||
236 | p->o_arg.open_flags = flags, | ||
237 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | ||
238 | p->o_arg.id = sp->so_id; | ||
239 | p->o_arg.name = &dentry->d_name; | ||
240 | p->o_arg.server = server; | ||
241 | p->o_arg.bitmask = server->attr_bitmask; | ||
242 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | ||
243 | p->o_res.f_attr = &p->f_attr; | ||
244 | p->o_res.dir_attr = &p->dir_attr; | ||
245 | p->o_res.server = server; | ||
246 | nfs_fattr_init(&p->f_attr); | ||
247 | nfs_fattr_init(&p->dir_attr); | ||
248 | if (flags & O_EXCL) { | ||
249 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
250 | s[0] = jiffies; | ||
251 | s[1] = current->pid; | ||
252 | } else if (flags & O_CREAT) { | ||
253 | p->o_arg.u.attrs = &p->attrs; | ||
254 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
255 | } | ||
256 | p->c_arg.fh = &p->o_res.fh; | ||
257 | p->c_arg.stateid = &p->o_res.stateid; | ||
258 | p->c_arg.seqid = p->o_arg.seqid; | ||
259 | return p; | ||
260 | err_free: | ||
261 | kfree(p); | ||
262 | err: | ||
263 | dput(parent); | ||
264 | return NULL; | ||
265 | } | ||
266 | |||
267 | static void nfs4_opendata_free(struct nfs4_opendata *p) | ||
268 | { | ||
269 | if (p != NULL && atomic_dec_and_test(&p->count)) { | ||
270 | nfs_free_seqid(p->o_arg.seqid); | ||
271 | nfs4_put_state_owner(p->owner); | ||
272 | dput(p->dir); | ||
273 | dput(p->dentry); | ||
274 | kfree(p); | ||
275 | } | ||
276 | } | ||
277 | |||
197 | /* Helper for asynchronous RPC calls */ | 278 | /* Helper for asynchronous RPC calls */ |
198 | static int nfs4_call_async(struct rpc_clnt *clnt, rpc_action tk_begin, | 279 | static int nfs4_call_async(struct rpc_clnt *clnt, |
199 | rpc_action tk_exit, void *calldata) | 280 | const struct rpc_call_ops *tk_ops, void *calldata) |
200 | { | 281 | { |
201 | struct rpc_task *task; | 282 | struct rpc_task *task; |
202 | 283 | ||
203 | if (!(task = rpc_new_task(clnt, tk_exit, RPC_TASK_ASYNC))) | 284 | if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata))) |
204 | return -ENOMEM; | 285 | return -ENOMEM; |
205 | |||
206 | task->tk_calldata = calldata; | ||
207 | task->tk_action = tk_begin; | ||
208 | rpc_execute(task); | 286 | rpc_execute(task); |
209 | return 0; | 287 | return 0; |
210 | } | 288 | } |
211 | 289 | ||
290 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | ||
291 | { | ||
292 | sigset_t oldset; | ||
293 | int ret; | ||
294 | |||
295 | rpc_clnt_sigmask(task->tk_client, &oldset); | ||
296 | ret = rpc_wait_for_completion_task(task); | ||
297 | rpc_clnt_sigunmask(task->tk_client, &oldset); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | ||
302 | { | ||
303 | switch (open_flags) { | ||
304 | case FMODE_WRITE: | ||
305 | state->n_wronly++; | ||
306 | break; | ||
307 | case FMODE_READ: | ||
308 | state->n_rdonly++; | ||
309 | break; | ||
310 | case FMODE_READ|FMODE_WRITE: | ||
311 | state->n_rdwr++; | ||
312 | } | ||
313 | } | ||
314 | |||
212 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 315 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
213 | { | 316 | { |
214 | struct inode *inode = state->inode; | 317 | struct inode *inode = state->inode; |
@@ -218,41 +321,134 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
218 | spin_lock(&state->owner->so_lock); | 321 | spin_lock(&state->owner->so_lock); |
219 | spin_lock(&inode->i_lock); | 322 | spin_lock(&inode->i_lock); |
220 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | 323 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); |
221 | if ((open_flags & FMODE_WRITE)) | 324 | update_open_stateflags(state, open_flags); |
222 | state->nwriters++; | ||
223 | if (open_flags & FMODE_READ) | ||
224 | state->nreaders++; | ||
225 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 325 | nfs4_state_set_mode_locked(state, state->state | open_flags); |
226 | spin_unlock(&inode->i_lock); | 326 | spin_unlock(&inode->i_lock); |
227 | spin_unlock(&state->owner->so_lock); | 327 | spin_unlock(&state->owner->so_lock); |
228 | } | 328 | } |
229 | 329 | ||
330 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | ||
331 | { | ||
332 | struct inode *inode; | ||
333 | struct nfs4_state *state = NULL; | ||
334 | |||
335 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | ||
336 | goto out; | ||
337 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | ||
338 | if (inode == NULL) | ||
339 | goto out; | ||
340 | state = nfs4_get_open_state(inode, data->owner); | ||
341 | if (state == NULL) | ||
342 | goto put_inode; | ||
343 | update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | ||
344 | put_inode: | ||
345 | iput(inode); | ||
346 | out: | ||
347 | return state; | ||
348 | } | ||
349 | |||
350 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | ||
351 | { | ||
352 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
353 | struct nfs_open_context *ctx; | ||
354 | |||
355 | spin_lock(&state->inode->i_lock); | ||
356 | list_for_each_entry(ctx, &nfsi->open_files, list) { | ||
357 | if (ctx->state != state) | ||
358 | continue; | ||
359 | get_nfs_open_context(ctx); | ||
360 | spin_unlock(&state->inode->i_lock); | ||
361 | return ctx; | ||
362 | } | ||
363 | spin_unlock(&state->inode->i_lock); | ||
364 | return ERR_PTR(-ENOENT); | ||
365 | } | ||
366 | |||
367 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | opendata->o_arg.open_flags = openflags; | ||
372 | ret = _nfs4_proc_open(opendata); | ||
373 | if (ret != 0) | ||
374 | return ret; | ||
375 | memcpy(stateid->data, opendata->o_res.stateid.data, | ||
376 | sizeof(stateid->data)); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | ||
381 | { | ||
382 | nfs4_stateid stateid; | ||
383 | struct nfs4_state *newstate; | ||
384 | int mode = 0; | ||
385 | int delegation = 0; | ||
386 | int ret; | ||
387 | |||
388 | /* memory barrier prior to reading state->n_* */ | ||
389 | smp_rmb(); | ||
390 | if (state->n_rdwr != 0) { | ||
391 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | ||
392 | if (ret != 0) | ||
393 | return ret; | ||
394 | mode |= FMODE_READ|FMODE_WRITE; | ||
395 | if (opendata->o_res.delegation_type != 0) | ||
396 | delegation = opendata->o_res.delegation_type; | ||
397 | smp_rmb(); | ||
398 | } | ||
399 | if (state->n_wronly != 0) { | ||
400 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | ||
401 | if (ret != 0) | ||
402 | return ret; | ||
403 | mode |= FMODE_WRITE; | ||
404 | if (opendata->o_res.delegation_type != 0) | ||
405 | delegation = opendata->o_res.delegation_type; | ||
406 | smp_rmb(); | ||
407 | } | ||
408 | if (state->n_rdonly != 0) { | ||
409 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | ||
410 | if (ret != 0) | ||
411 | return ret; | ||
412 | mode |= FMODE_READ; | ||
413 | } | ||
414 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
415 | if (mode == 0) | ||
416 | return 0; | ||
417 | if (opendata->o_res.delegation_type == 0) | ||
418 | opendata->o_res.delegation_type = delegation; | ||
419 | opendata->o_arg.open_flags |= mode; | ||
420 | newstate = nfs4_opendata_to_nfs4_state(opendata); | ||
421 | if (newstate != NULL) { | ||
422 | if (opendata->o_res.delegation_type != 0) { | ||
423 | struct nfs_inode *nfsi = NFS_I(newstate->inode); | ||
424 | int delegation_flags = 0; | ||
425 | if (nfsi->delegation) | ||
426 | delegation_flags = nfsi->delegation->flags; | ||
427 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
428 | nfs_inode_set_delegation(newstate->inode, | ||
429 | opendata->owner->so_cred, | ||
430 | &opendata->o_res); | ||
431 | else | ||
432 | nfs_inode_reclaim_delegation(newstate->inode, | ||
433 | opendata->owner->so_cred, | ||
434 | &opendata->o_res); | ||
435 | } | ||
436 | nfs4_close_state(newstate, opendata->o_arg.open_flags); | ||
437 | } | ||
438 | if (newstate != state) | ||
439 | return -ESTALE; | ||
440 | return 0; | ||
441 | } | ||
442 | |||
230 | /* | 443 | /* |
231 | * OPEN_RECLAIM: | 444 | * OPEN_RECLAIM: |
232 | * reclaim state on the server after a reboot. | 445 | * reclaim state on the server after a reboot. |
233 | */ | 446 | */ |
234 | static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | 447 | static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
235 | { | 448 | { |
236 | struct inode *inode = state->inode; | 449 | struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; |
237 | struct nfs_server *server = NFS_SERVER(inode); | 450 | struct nfs4_opendata *opendata; |
238 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 451 | int delegation_type = 0; |
239 | struct nfs_openargs o_arg = { | ||
240 | .fh = NFS_FH(inode), | ||
241 | .id = sp->so_id, | ||
242 | .open_flags = state->state, | ||
243 | .clientid = server->nfs4_state->cl_clientid, | ||
244 | .claim = NFS4_OPEN_CLAIM_PREVIOUS, | ||
245 | .bitmask = server->attr_bitmask, | ||
246 | }; | ||
247 | struct nfs_openres o_res = { | ||
248 | .server = server, /* Grrr */ | ||
249 | }; | ||
250 | struct rpc_message msg = { | ||
251 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], | ||
252 | .rpc_argp = &o_arg, | ||
253 | .rpc_resp = &o_res, | ||
254 | .rpc_cred = sp->so_cred, | ||
255 | }; | ||
256 | int status; | 452 | int status; |
257 | 453 | ||
258 | if (delegation != NULL) { | 454 | if (delegation != NULL) { |
@@ -262,38 +458,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
262 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 458 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
263 | return 0; | 459 | return 0; |
264 | } | 460 | } |
265 | o_arg.u.delegation_type = delegation->type; | 461 | delegation_type = delegation->type; |
266 | } | 462 | } |
267 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 463 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); |
268 | if (o_arg.seqid == NULL) | 464 | if (opendata == NULL) |
269 | return -ENOMEM; | 465 | return -ENOMEM; |
270 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 466 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; |
271 | /* Confirm the sequence as being established */ | 467 | opendata->o_arg.fh = NFS_FH(state->inode); |
272 | nfs_confirm_seqid(&sp->so_seqid, status); | 468 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); |
273 | nfs_increment_open_seqid(status, o_arg.seqid); | 469 | opendata->o_arg.u.delegation_type = delegation_type; |
274 | if (status == 0) { | 470 | status = nfs4_open_recover(opendata, state); |
275 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | 471 | nfs4_opendata_free(opendata); |
276 | if (o_res.delegation_type != 0) { | ||
277 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | ||
278 | /* Did the server issue an immediate delegation recall? */ | ||
279 | if (o_res.do_recall) | ||
280 | nfs_async_inode_return_delegation(inode, &o_res.stateid); | ||
281 | } | ||
282 | } | ||
283 | nfs_free_seqid(o_arg.seqid); | ||
284 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
285 | /* Ensure we update the inode attributes */ | ||
286 | NFS_CACHEINV(inode); | ||
287 | return status; | 472 | return status; |
288 | } | 473 | } |
289 | 474 | ||
290 | static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | 475 | static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
291 | { | 476 | { |
292 | struct nfs_server *server = NFS_SERVER(state->inode); | 477 | struct nfs_server *server = NFS_SERVER(state->inode); |
293 | struct nfs4_exception exception = { }; | 478 | struct nfs4_exception exception = { }; |
294 | int err; | 479 | int err; |
295 | do { | 480 | do { |
296 | err = _nfs4_open_reclaim(sp, state); | 481 | err = _nfs4_do_open_reclaim(sp, state, dentry); |
297 | if (err != -NFS4ERR_DELAY) | 482 | if (err != -NFS4ERR_DELAY) |
298 | break; | 483 | break; |
299 | nfs4_handle_exception(server, err, &exception); | 484 | nfs4_handle_exception(server, err, &exception); |
@@ -301,63 +486,36 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
301 | return err; | 486 | return err; |
302 | } | 487 | } |
303 | 488 | ||
489 | static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
490 | { | ||
491 | struct nfs_open_context *ctx; | ||
492 | int ret; | ||
493 | |||
494 | ctx = nfs4_state_find_open_context(state); | ||
495 | if (IS_ERR(ctx)) | ||
496 | return PTR_ERR(ctx); | ||
497 | ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); | ||
498 | put_nfs_open_context(ctx); | ||
499 | return ret; | ||
500 | } | ||
501 | |||
304 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 502 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) |
305 | { | 503 | { |
306 | struct nfs4_state_owner *sp = state->owner; | 504 | struct nfs4_state_owner *sp = state->owner; |
307 | struct inode *inode = dentry->d_inode; | 505 | struct nfs4_opendata *opendata; |
308 | struct nfs_server *server = NFS_SERVER(inode); | 506 | int ret; |
309 | struct dentry *parent = dget_parent(dentry); | ||
310 | struct nfs_openargs arg = { | ||
311 | .fh = NFS_FH(parent->d_inode), | ||
312 | .clientid = server->nfs4_state->cl_clientid, | ||
313 | .name = &dentry->d_name, | ||
314 | .id = sp->so_id, | ||
315 | .server = server, | ||
316 | .bitmask = server->attr_bitmask, | ||
317 | .claim = NFS4_OPEN_CLAIM_DELEGATE_CUR, | ||
318 | }; | ||
319 | struct nfs_openres res = { | ||
320 | .server = server, | ||
321 | }; | ||
322 | struct rpc_message msg = { | ||
323 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], | ||
324 | .rpc_argp = &arg, | ||
325 | .rpc_resp = &res, | ||
326 | .rpc_cred = sp->so_cred, | ||
327 | }; | ||
328 | int status = 0; | ||
329 | 507 | ||
330 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 508 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
331 | goto out; | 509 | return 0; |
332 | if (state->state == 0) | 510 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); |
333 | goto out; | 511 | if (opendata == NULL) |
334 | arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 512 | return -ENOMEM; |
335 | status = -ENOMEM; | 513 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
336 | if (arg.seqid == NULL) | 514 | memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, |
337 | goto out; | 515 | sizeof(opendata->o_arg.u.delegation.data)); |
338 | arg.open_flags = state->state; | 516 | ret = nfs4_open_recover(opendata, state); |
339 | memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); | 517 | nfs4_opendata_free(opendata); |
340 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 518 | return ret; |
341 | nfs_increment_open_seqid(status, arg.seqid); | ||
342 | if (status != 0) | ||
343 | goto out_free; | ||
344 | if(res.rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
345 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), | ||
346 | sp, &res.stateid, arg.seqid); | ||
347 | if (status != 0) | ||
348 | goto out_free; | ||
349 | } | ||
350 | nfs_confirm_seqid(&sp->so_seqid, 0); | ||
351 | if (status >= 0) { | ||
352 | memcpy(state->stateid.data, res.stateid.data, | ||
353 | sizeof(state->stateid.data)); | ||
354 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
355 | } | ||
356 | out_free: | ||
357 | nfs_free_seqid(arg.seqid); | ||
358 | out: | ||
359 | dput(parent); | ||
360 | return status; | ||
361 | } | 519 | } |
362 | 520 | ||
363 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 521 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) |
@@ -382,82 +540,202 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
382 | return err; | 540 | return err; |
383 | } | 541 | } |
384 | 542 | ||
385 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) | 543 | static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) |
386 | { | 544 | { |
387 | struct nfs_open_confirmargs arg = { | 545 | struct nfs4_opendata *data = calldata; |
388 | .fh = fh, | 546 | struct rpc_message msg = { |
389 | .seqid = seqid, | 547 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], |
390 | .stateid = *stateid, | 548 | .rpc_argp = &data->c_arg, |
391 | }; | 549 | .rpc_resp = &data->c_res, |
392 | struct nfs_open_confirmres res; | 550 | .rpc_cred = data->owner->so_cred, |
393 | struct rpc_message msg = { | ||
394 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], | ||
395 | .rpc_argp = &arg, | ||
396 | .rpc_resp = &res, | ||
397 | .rpc_cred = sp->so_cred, | ||
398 | }; | 551 | }; |
552 | data->timestamp = jiffies; | ||
553 | rpc_call_setup(task, &msg, 0); | ||
554 | } | ||
555 | |||
556 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | ||
557 | { | ||
558 | struct nfs4_opendata *data = calldata; | ||
559 | |||
560 | data->rpc_status = task->tk_status; | ||
561 | if (RPC_ASSASSINATED(task)) | ||
562 | return; | ||
563 | if (data->rpc_status == 0) { | ||
564 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | ||
565 | sizeof(data->o_res.stateid.data)); | ||
566 | renew_lease(data->o_res.server, data->timestamp); | ||
567 | } | ||
568 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
569 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | ||
570 | } | ||
571 | |||
572 | static void nfs4_open_confirm_release(void *calldata) | ||
573 | { | ||
574 | struct nfs4_opendata *data = calldata; | ||
575 | struct nfs4_state *state = NULL; | ||
576 | |||
577 | /* If this request hasn't been cancelled, do nothing */ | ||
578 | if (data->cancelled == 0) | ||
579 | goto out_free; | ||
580 | /* In case of error, no cleanup! */ | ||
581 | if (data->rpc_status != 0) | ||
582 | goto out_free; | ||
583 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
584 | state = nfs4_opendata_to_nfs4_state(data); | ||
585 | if (state != NULL) | ||
586 | nfs4_close_state(state, data->o_arg.open_flags); | ||
587 | out_free: | ||
588 | nfs4_opendata_free(data); | ||
589 | } | ||
590 | |||
591 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | ||
592 | .rpc_call_prepare = nfs4_open_confirm_prepare, | ||
593 | .rpc_call_done = nfs4_open_confirm_done, | ||
594 | .rpc_release = nfs4_open_confirm_release, | ||
595 | }; | ||
596 | |||
597 | /* | ||
598 | * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata | ||
599 | */ | ||
600 | static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | ||
601 | { | ||
602 | struct nfs_server *server = NFS_SERVER(data->dir->d_inode); | ||
603 | struct rpc_task *task; | ||
399 | int status; | 604 | int status; |
400 | 605 | ||
401 | status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); | 606 | atomic_inc(&data->count); |
402 | /* Confirm the sequence as being established */ | 607 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
403 | nfs_confirm_seqid(&sp->so_seqid, status); | 608 | if (IS_ERR(task)) { |
404 | nfs_increment_open_seqid(status, seqid); | 609 | nfs4_opendata_free(data); |
405 | if (status >= 0) | 610 | return PTR_ERR(task); |
406 | memcpy(stateid, &res.stateid, sizeof(*stateid)); | 611 | } |
612 | status = nfs4_wait_for_completion_rpc_task(task); | ||
613 | if (status != 0) { | ||
614 | data->cancelled = 1; | ||
615 | smp_wmb(); | ||
616 | } else | ||
617 | status = data->rpc_status; | ||
618 | rpc_release_task(task); | ||
407 | return status; | 619 | return status; |
408 | } | 620 | } |
409 | 621 | ||
410 | static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res) | 622 | static void nfs4_open_prepare(struct rpc_task *task, void *calldata) |
411 | { | 623 | { |
412 | struct nfs_server *server = NFS_SERVER(dir); | 624 | struct nfs4_opendata *data = calldata; |
625 | struct nfs4_state_owner *sp = data->owner; | ||
413 | struct rpc_message msg = { | 626 | struct rpc_message msg = { |
414 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], | 627 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], |
415 | .rpc_argp = o_arg, | 628 | .rpc_argp = &data->o_arg, |
416 | .rpc_resp = o_res, | 629 | .rpc_resp = &data->o_res, |
417 | .rpc_cred = sp->so_cred, | 630 | .rpc_cred = sp->so_cred, |
418 | }; | 631 | }; |
419 | int status; | 632 | |
633 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | ||
634 | return; | ||
635 | /* Update sequence id. */ | ||
636 | data->o_arg.id = sp->so_id; | ||
637 | data->o_arg.clientid = sp->so_client->cl_clientid; | ||
638 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | ||
639 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | ||
640 | data->timestamp = jiffies; | ||
641 | rpc_call_setup(task, &msg, 0); | ||
642 | } | ||
420 | 643 | ||
421 | /* Update sequence id. The caller must serialize! */ | 644 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
422 | o_arg->id = sp->so_id; | 645 | { |
423 | o_arg->clientid = sp->so_client->cl_clientid; | 646 | struct nfs4_opendata *data = calldata; |
424 | 647 | ||
425 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 648 | data->rpc_status = task->tk_status; |
426 | if (status == 0) { | 649 | if (RPC_ASSASSINATED(task)) |
427 | /* OPEN on anything except a regular file is disallowed in NFSv4 */ | 650 | return; |
428 | switch (o_res->f_attr->mode & S_IFMT) { | 651 | if (task->tk_status == 0) { |
652 | switch (data->o_res.f_attr->mode & S_IFMT) { | ||
429 | case S_IFREG: | 653 | case S_IFREG: |
430 | break; | 654 | break; |
431 | case S_IFLNK: | 655 | case S_IFLNK: |
432 | status = -ELOOP; | 656 | data->rpc_status = -ELOOP; |
433 | break; | 657 | break; |
434 | case S_IFDIR: | 658 | case S_IFDIR: |
435 | status = -EISDIR; | 659 | data->rpc_status = -EISDIR; |
436 | break; | 660 | break; |
437 | default: | 661 | default: |
438 | status = -ENOTDIR; | 662 | data->rpc_status = -ENOTDIR; |
439 | } | 663 | } |
664 | renew_lease(data->o_res.server, data->timestamp); | ||
440 | } | 665 | } |
666 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | ||
667 | } | ||
668 | |||
669 | static void nfs4_open_release(void *calldata) | ||
670 | { | ||
671 | struct nfs4_opendata *data = calldata; | ||
672 | struct nfs4_state *state = NULL; | ||
441 | 673 | ||
442 | nfs_increment_open_seqid(status, o_arg->seqid); | 674 | /* If this request hasn't been cancelled, do nothing */ |
675 | if (data->cancelled == 0) | ||
676 | goto out_free; | ||
677 | /* In case of error, no cleanup! */ | ||
678 | if (data->rpc_status != 0) | ||
679 | goto out_free; | ||
680 | /* In case we need an open_confirm, no cleanup! */ | ||
681 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) | ||
682 | goto out_free; | ||
683 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
684 | state = nfs4_opendata_to_nfs4_state(data); | ||
685 | if (state != NULL) | ||
686 | nfs4_close_state(state, data->o_arg.open_flags); | ||
687 | out_free: | ||
688 | nfs4_opendata_free(data); | ||
689 | } | ||
690 | |||
691 | static const struct rpc_call_ops nfs4_open_ops = { | ||
692 | .rpc_call_prepare = nfs4_open_prepare, | ||
693 | .rpc_call_done = nfs4_open_done, | ||
694 | .rpc_release = nfs4_open_release, | ||
695 | }; | ||
696 | |||
697 | /* | ||
698 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
699 | */ | ||
700 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
701 | { | ||
702 | struct inode *dir = data->dir->d_inode; | ||
703 | struct nfs_server *server = NFS_SERVER(dir); | ||
704 | struct nfs_openargs *o_arg = &data->o_arg; | ||
705 | struct nfs_openres *o_res = &data->o_res; | ||
706 | struct rpc_task *task; | ||
707 | int status; | ||
708 | |||
709 | atomic_inc(&data->count); | ||
710 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | ||
711 | if (IS_ERR(task)) { | ||
712 | nfs4_opendata_free(data); | ||
713 | return PTR_ERR(task); | ||
714 | } | ||
715 | status = nfs4_wait_for_completion_rpc_task(task); | ||
716 | if (status != 0) { | ||
717 | data->cancelled = 1; | ||
718 | smp_wmb(); | ||
719 | } else | ||
720 | status = data->rpc_status; | ||
721 | rpc_release_task(task); | ||
443 | if (status != 0) | 722 | if (status != 0) |
444 | goto out; | 723 | return status; |
724 | |||
445 | if (o_arg->open_flags & O_CREAT) { | 725 | if (o_arg->open_flags & O_CREAT) { |
446 | update_changeattr(dir, &o_res->cinfo); | 726 | update_changeattr(dir, &o_res->cinfo); |
447 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 727 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
448 | } else | 728 | } else |
449 | nfs_refresh_inode(dir, o_res->dir_attr); | 729 | nfs_refresh_inode(dir, o_res->dir_attr); |
450 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 730 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
451 | status = _nfs4_proc_open_confirm(server->client, &o_res->fh, | 731 | status = _nfs4_proc_open_confirm(data); |
452 | sp, &o_res->stateid, o_arg->seqid); | ||
453 | if (status != 0) | 732 | if (status != 0) |
454 | goto out; | 733 | return status; |
455 | } | 734 | } |
456 | nfs_confirm_seqid(&sp->so_seqid, 0); | 735 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
457 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 736 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
458 | status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 737 | return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
459 | out: | 738 | return 0; |
460 | return status; | ||
461 | } | 739 | } |
462 | 740 | ||
463 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) | 741 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) |
@@ -488,6 +766,15 @@ out: | |||
488 | return -EACCES; | 766 | return -EACCES; |
489 | } | 767 | } |
490 | 768 | ||
769 | int nfs4_recover_expired_lease(struct nfs_server *server) | ||
770 | { | ||
771 | struct nfs4_client *clp = server->nfs4_state; | ||
772 | |||
773 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
774 | nfs4_schedule_state_recovery(clp); | ||
775 | return nfs4_wait_clnt_recover(server->client, clp); | ||
776 | } | ||
777 | |||
491 | /* | 778 | /* |
492 | * OPEN_EXPIRED: | 779 | * OPEN_EXPIRED: |
493 | * reclaim state on the server after a network partition. | 780 | * reclaim state on the server after a network partition. |
@@ -495,77 +782,31 @@ out: | |||
495 | */ | 782 | */ |
496 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 783 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
497 | { | 784 | { |
498 | struct dentry *parent = dget_parent(dentry); | ||
499 | struct inode *dir = parent->d_inode; | ||
500 | struct inode *inode = state->inode; | 785 | struct inode *inode = state->inode; |
501 | struct nfs_server *server = NFS_SERVER(dir); | ||
502 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 786 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; |
503 | struct nfs_fattr f_attr, dir_attr; | 787 | struct nfs4_opendata *opendata; |
504 | struct nfs_openargs o_arg = { | 788 | int openflags = state->state & (FMODE_READ|FMODE_WRITE); |
505 | .fh = NFS_FH(dir), | 789 | int ret; |
506 | .open_flags = state->state, | ||
507 | .name = &dentry->d_name, | ||
508 | .bitmask = server->attr_bitmask, | ||
509 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
510 | }; | ||
511 | struct nfs_openres o_res = { | ||
512 | .f_attr = &f_attr, | ||
513 | .dir_attr = &dir_attr, | ||
514 | .server = server, | ||
515 | }; | ||
516 | int status = 0; | ||
517 | 790 | ||
518 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 791 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { |
519 | status = _nfs4_do_access(inode, sp->so_cred, state->state); | 792 | ret = _nfs4_do_access(inode, sp->so_cred, openflags); |
520 | if (status < 0) | 793 | if (ret < 0) |
521 | goto out; | 794 | return ret; |
522 | memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); | 795 | memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); |
523 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 796 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
524 | goto out; | 797 | return 0; |
525 | } | 798 | } |
526 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 799 | opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); |
527 | status = -ENOMEM; | 800 | if (opendata == NULL) |
528 | if (o_arg.seqid == NULL) | 801 | return -ENOMEM; |
529 | goto out; | 802 | ret = nfs4_open_recover(opendata, state); |
530 | nfs_fattr_init(&f_attr); | 803 | if (ret == -ESTALE) { |
531 | nfs_fattr_init(&dir_attr); | 804 | /* Invalidate the state owner so we don't ever use it again */ |
532 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | 805 | nfs4_drop_state_owner(sp); |
533 | if (status != 0) | 806 | d_drop(dentry); |
534 | goto out_nodeleg; | ||
535 | /* Check if files differ */ | ||
536 | if ((f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) | ||
537 | goto out_stale; | ||
538 | /* Has the file handle changed? */ | ||
539 | if (nfs_compare_fh(&o_res.fh, NFS_FH(inode)) != 0) { | ||
540 | /* Verify if the change attributes are the same */ | ||
541 | if (f_attr.change_attr != NFS_I(inode)->change_attr) | ||
542 | goto out_stale; | ||
543 | if (nfs_size_to_loff_t(f_attr.size) != inode->i_size) | ||
544 | goto out_stale; | ||
545 | /* Lets just pretend that this is the same file */ | ||
546 | nfs_copy_fh(NFS_FH(inode), &o_res.fh); | ||
547 | NFS_I(inode)->fileid = f_attr.fileid; | ||
548 | } | ||
549 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | ||
550 | if (o_res.delegation_type != 0) { | ||
551 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
552 | nfs_inode_set_delegation(inode, sp->so_cred, &o_res); | ||
553 | else | ||
554 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | ||
555 | } | 807 | } |
556 | out_nodeleg: | 808 | nfs4_opendata_free(opendata); |
557 | nfs_free_seqid(o_arg.seqid); | 809 | return ret; |
558 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
559 | out: | ||
560 | dput(parent); | ||
561 | return status; | ||
562 | out_stale: | ||
563 | status = -ESTALE; | ||
564 | /* Invalidate the state owner so we don't ever use it again */ | ||
565 | nfs4_drop_state_owner(sp); | ||
566 | d_drop(dentry); | ||
567 | /* Should we be trying to close that stateid? */ | ||
568 | goto out_nodeleg; | ||
569 | } | 810 | } |
570 | 811 | ||
571 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 812 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) |
@@ -584,26 +825,19 @@ static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_ | |||
584 | 825 | ||
585 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 826 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
586 | { | 827 | { |
587 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
588 | struct nfs_open_context *ctx; | 828 | struct nfs_open_context *ctx; |
589 | int status; | 829 | int ret; |
590 | 830 | ||
591 | spin_lock(&state->inode->i_lock); | 831 | ctx = nfs4_state_find_open_context(state); |
592 | list_for_each_entry(ctx, &nfsi->open_files, list) { | 832 | if (IS_ERR(ctx)) |
593 | if (ctx->state != state) | 833 | return PTR_ERR(ctx); |
594 | continue; | 834 | ret = nfs4_do_open_expired(sp, state, ctx->dentry); |
595 | get_nfs_open_context(ctx); | 835 | put_nfs_open_context(ctx); |
596 | spin_unlock(&state->inode->i_lock); | 836 | return ret; |
597 | status = nfs4_do_open_expired(sp, state, ctx->dentry); | ||
598 | put_nfs_open_context(ctx); | ||
599 | return status; | ||
600 | } | ||
601 | spin_unlock(&state->inode->i_lock); | ||
602 | return -ENOENT; | ||
603 | } | 837 | } |
604 | 838 | ||
605 | /* | 839 | /* |
606 | * Returns an nfs4_state + an extra reference to the inode | 840 | * Returns a referenced nfs4_state if there is an open delegation on the file |
607 | */ | 841 | */ |
608 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | 842 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) |
609 | { | 843 | { |
@@ -616,6 +850,14 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
616 | int open_flags = flags & (FMODE_READ|FMODE_WRITE); | 850 | int open_flags = flags & (FMODE_READ|FMODE_WRITE); |
617 | int err; | 851 | int err; |
618 | 852 | ||
853 | err = -ENOMEM; | ||
854 | if (!(sp = nfs4_get_state_owner(server, cred))) { | ||
855 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | ||
856 | return err; | ||
857 | } | ||
858 | err = nfs4_recover_expired_lease(server); | ||
859 | if (err != 0) | ||
860 | goto out_put_state_owner; | ||
619 | /* Protect against reboot recovery - NOTE ORDER! */ | 861 | /* Protect against reboot recovery - NOTE ORDER! */ |
620 | down_read(&clp->cl_sem); | 862 | down_read(&clp->cl_sem); |
621 | /* Protect against delegation recall */ | 863 | /* Protect against delegation recall */ |
@@ -625,10 +867,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
625 | if (delegation == NULL || (delegation->type & open_flags) != open_flags) | 867 | if (delegation == NULL || (delegation->type & open_flags) != open_flags) |
626 | goto out_err; | 868 | goto out_err; |
627 | err = -ENOMEM; | 869 | err = -ENOMEM; |
628 | if (!(sp = nfs4_get_state_owner(server, cred))) { | ||
629 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | ||
630 | goto out_err; | ||
631 | } | ||
632 | state = nfs4_get_open_state(inode, sp); | 870 | state = nfs4_get_open_state(inode, sp); |
633 | if (state == NULL) | 871 | if (state == NULL) |
634 | goto out_err; | 872 | goto out_err; |
@@ -636,39 +874,34 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
636 | err = -ENOENT; | 874 | err = -ENOENT; |
637 | if ((state->state & open_flags) == open_flags) { | 875 | if ((state->state & open_flags) == open_flags) { |
638 | spin_lock(&inode->i_lock); | 876 | spin_lock(&inode->i_lock); |
639 | if (open_flags & FMODE_READ) | 877 | update_open_stateflags(state, open_flags); |
640 | state->nreaders++; | ||
641 | if (open_flags & FMODE_WRITE) | ||
642 | state->nwriters++; | ||
643 | spin_unlock(&inode->i_lock); | 878 | spin_unlock(&inode->i_lock); |
644 | goto out_ok; | 879 | goto out_ok; |
645 | } else if (state->state != 0) | 880 | } else if (state->state != 0) |
646 | goto out_err; | 881 | goto out_put_open_state; |
647 | 882 | ||
648 | lock_kernel(); | 883 | lock_kernel(); |
649 | err = _nfs4_do_access(inode, cred, open_flags); | 884 | err = _nfs4_do_access(inode, cred, open_flags); |
650 | unlock_kernel(); | 885 | unlock_kernel(); |
651 | if (err != 0) | 886 | if (err != 0) |
652 | goto out_err; | 887 | goto out_put_open_state; |
653 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 888 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
654 | update_open_stateid(state, &delegation->stateid, open_flags); | 889 | update_open_stateid(state, &delegation->stateid, open_flags); |
655 | out_ok: | 890 | out_ok: |
656 | nfs4_put_state_owner(sp); | 891 | nfs4_put_state_owner(sp); |
657 | up_read(&nfsi->rwsem); | 892 | up_read(&nfsi->rwsem); |
658 | up_read(&clp->cl_sem); | 893 | up_read(&clp->cl_sem); |
659 | igrab(inode); | ||
660 | *res = state; | 894 | *res = state; |
661 | return 0; | 895 | return 0; |
896 | out_put_open_state: | ||
897 | nfs4_put_open_state(state); | ||
662 | out_err: | 898 | out_err: |
663 | if (sp != NULL) { | ||
664 | if (state != NULL) | ||
665 | nfs4_put_open_state(state); | ||
666 | nfs4_put_state_owner(sp); | ||
667 | } | ||
668 | up_read(&nfsi->rwsem); | 899 | up_read(&nfsi->rwsem); |
669 | up_read(&clp->cl_sem); | 900 | up_read(&clp->cl_sem); |
670 | if (err != -EACCES) | 901 | if (err != -EACCES) |
671 | nfs_inode_return_delegation(inode); | 902 | nfs_inode_return_delegation(inode); |
903 | out_put_state_owner: | ||
904 | nfs4_put_state_owner(sp); | ||
672 | return err; | 905 | return err; |
673 | } | 906 | } |
674 | 907 | ||
@@ -689,7 +922,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st | |||
689 | } | 922 | } |
690 | 923 | ||
691 | /* | 924 | /* |
692 | * Returns an nfs4_state + an referenced inode | 925 | * Returns a referenced nfs4_state |
693 | */ | 926 | */ |
694 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 927 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
695 | { | 928 | { |
@@ -697,73 +930,46 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
697 | struct nfs4_state *state = NULL; | 930 | struct nfs4_state *state = NULL; |
698 | struct nfs_server *server = NFS_SERVER(dir); | 931 | struct nfs_server *server = NFS_SERVER(dir); |
699 | struct nfs4_client *clp = server->nfs4_state; | 932 | struct nfs4_client *clp = server->nfs4_state; |
700 | struct inode *inode = NULL; | 933 | struct nfs4_opendata *opendata; |
701 | int status; | 934 | int status; |
702 | struct nfs_fattr f_attr, dir_attr; | ||
703 | struct nfs_openargs o_arg = { | ||
704 | .fh = NFS_FH(dir), | ||
705 | .open_flags = flags, | ||
706 | .name = &dentry->d_name, | ||
707 | .server = server, | ||
708 | .bitmask = server->attr_bitmask, | ||
709 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
710 | }; | ||
711 | struct nfs_openres o_res = { | ||
712 | .f_attr = &f_attr, | ||
713 | .dir_attr = &dir_attr, | ||
714 | .server = server, | ||
715 | }; | ||
716 | 935 | ||
717 | /* Protect against reboot recovery conflicts */ | 936 | /* Protect against reboot recovery conflicts */ |
718 | down_read(&clp->cl_sem); | ||
719 | status = -ENOMEM; | 937 | status = -ENOMEM; |
720 | if (!(sp = nfs4_get_state_owner(server, cred))) { | 938 | if (!(sp = nfs4_get_state_owner(server, cred))) { |
721 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); | 939 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); |
722 | goto out_err; | 940 | goto out_err; |
723 | } | 941 | } |
724 | if (flags & O_EXCL) { | 942 | status = nfs4_recover_expired_lease(server); |
725 | u32 *p = (u32 *) o_arg.u.verifier.data; | 943 | if (status != 0) |
726 | p[0] = jiffies; | 944 | goto err_put_state_owner; |
727 | p[1] = current->pid; | 945 | down_read(&clp->cl_sem); |
728 | } else | 946 | status = -ENOMEM; |
729 | o_arg.u.attrs = sattr; | 947 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); |
730 | /* Serialization for the sequence id */ | 948 | if (opendata == NULL) |
949 | goto err_put_state_owner; | ||
731 | 950 | ||
732 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 951 | status = _nfs4_proc_open(opendata); |
733 | if (o_arg.seqid == NULL) | ||
734 | return -ENOMEM; | ||
735 | nfs_fattr_init(&f_attr); | ||
736 | nfs_fattr_init(&dir_attr); | ||
737 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | ||
738 | if (status != 0) | 952 | if (status != 0) |
739 | goto out_err; | 953 | goto err_opendata_free; |
740 | 954 | ||
741 | status = -ENOMEM; | 955 | status = -ENOMEM; |
742 | inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); | 956 | state = nfs4_opendata_to_nfs4_state(opendata); |
743 | if (!inode) | 957 | if (state == NULL) |
744 | goto out_err; | 958 | goto err_opendata_free; |
745 | state = nfs4_get_open_state(inode, sp); | 959 | if (opendata->o_res.delegation_type != 0) |
746 | if (!state) | 960 | nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); |
747 | goto out_err; | 961 | nfs4_opendata_free(opendata); |
748 | update_open_stateid(state, &o_res.stateid, flags); | ||
749 | if (o_res.delegation_type != 0) | ||
750 | nfs_inode_set_delegation(inode, cred, &o_res); | ||
751 | nfs_free_seqid(o_arg.seqid); | ||
752 | nfs4_put_state_owner(sp); | 962 | nfs4_put_state_owner(sp); |
753 | up_read(&clp->cl_sem); | 963 | up_read(&clp->cl_sem); |
754 | *res = state; | 964 | *res = state; |
755 | return 0; | 965 | return 0; |
966 | err_opendata_free: | ||
967 | nfs4_opendata_free(opendata); | ||
968 | err_put_state_owner: | ||
969 | nfs4_put_state_owner(sp); | ||
756 | out_err: | 970 | out_err: |
757 | if (sp != NULL) { | ||
758 | if (state != NULL) | ||
759 | nfs4_put_open_state(state); | ||
760 | nfs_free_seqid(o_arg.seqid); | ||
761 | nfs4_put_state_owner(sp); | ||
762 | } | ||
763 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ | 971 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ |
764 | up_read(&clp->cl_sem); | 972 | up_read(&clp->cl_sem); |
765 | if (inode != NULL) | ||
766 | iput(inode); | ||
767 | *res = NULL; | 973 | *res = NULL; |
768 | return status; | 974 | return status; |
769 | } | 975 | } |
@@ -830,6 +1036,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
830 | .rpc_argp = &arg, | 1036 | .rpc_argp = &arg, |
831 | .rpc_resp = &res, | 1037 | .rpc_resp = &res, |
832 | }; | 1038 | }; |
1039 | unsigned long timestamp = jiffies; | ||
833 | int status; | 1040 | int status; |
834 | 1041 | ||
835 | nfs_fattr_init(fattr); | 1042 | nfs_fattr_init(fattr); |
@@ -841,6 +1048,8 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
841 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1048 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
842 | 1049 | ||
843 | status = rpc_call_sync(server->client, &msg, 0); | 1050 | status = rpc_call_sync(server->client, &msg, 0); |
1051 | if (status == 0 && state != NULL) | ||
1052 | renew_lease(server, timestamp); | ||
844 | return status; | 1053 | return status; |
845 | } | 1054 | } |
846 | 1055 | ||
@@ -865,12 +1074,13 @@ struct nfs4_closedata { | |||
865 | struct nfs_closeargs arg; | 1074 | struct nfs_closeargs arg; |
866 | struct nfs_closeres res; | 1075 | struct nfs_closeres res; |
867 | struct nfs_fattr fattr; | 1076 | struct nfs_fattr fattr; |
1077 | unsigned long timestamp; | ||
868 | }; | 1078 | }; |
869 | 1079 | ||
870 | static void nfs4_free_closedata(struct nfs4_closedata *calldata) | 1080 | static void nfs4_free_closedata(void *data) |
871 | { | 1081 | { |
872 | struct nfs4_state *state = calldata->state; | 1082 | struct nfs4_closedata *calldata = data; |
873 | struct nfs4_state_owner *sp = state->owner; | 1083 | struct nfs4_state_owner *sp = calldata->state->owner; |
874 | 1084 | ||
875 | nfs4_put_open_state(calldata->state); | 1085 | nfs4_put_open_state(calldata->state); |
876 | nfs_free_seqid(calldata->arg.seqid); | 1086 | nfs_free_seqid(calldata->arg.seqid); |
@@ -878,12 +1088,14 @@ static void nfs4_free_closedata(struct nfs4_closedata *calldata) | |||
878 | kfree(calldata); | 1088 | kfree(calldata); |
879 | } | 1089 | } |
880 | 1090 | ||
881 | static void nfs4_close_done(struct rpc_task *task) | 1091 | static void nfs4_close_done(struct rpc_task *task, void *data) |
882 | { | 1092 | { |
883 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 1093 | struct nfs4_closedata *calldata = data; |
884 | struct nfs4_state *state = calldata->state; | 1094 | struct nfs4_state *state = calldata->state; |
885 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1095 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
886 | 1096 | ||
1097 | if (RPC_ASSASSINATED(task)) | ||
1098 | return; | ||
887 | /* hmm. we are done with the inode, and in the process of freeing | 1099 | /* hmm. we are done with the inode, and in the process of freeing |
888 | * the state_owner. we keep this around to process errors | 1100 | * the state_owner. we keep this around to process errors |
889 | */ | 1101 | */ |
@@ -892,6 +1104,7 @@ static void nfs4_close_done(struct rpc_task *task) | |||
892 | case 0: | 1104 | case 0: |
893 | memcpy(&state->stateid, &calldata->res.stateid, | 1105 | memcpy(&state->stateid, &calldata->res.stateid, |
894 | sizeof(state->stateid)); | 1106 | sizeof(state->stateid)); |
1107 | renew_lease(server, calldata->timestamp); | ||
895 | break; | 1108 | break; |
896 | case -NFS4ERR_STALE_STATEID: | 1109 | case -NFS4ERR_STALE_STATEID: |
897 | case -NFS4ERR_EXPIRED: | 1110 | case -NFS4ERR_EXPIRED: |
@@ -904,12 +1117,11 @@ static void nfs4_close_done(struct rpc_task *task) | |||
904 | } | 1117 | } |
905 | } | 1118 | } |
906 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1119 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
907 | nfs4_free_closedata(calldata); | ||
908 | } | 1120 | } |
909 | 1121 | ||
910 | static void nfs4_close_begin(struct rpc_task *task) | 1122 | static void nfs4_close_prepare(struct rpc_task *task, void *data) |
911 | { | 1123 | { |
912 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 1124 | struct nfs4_closedata *calldata = data; |
913 | struct nfs4_state *state = calldata->state; | 1125 | struct nfs4_state *state = calldata->state; |
914 | struct rpc_message msg = { | 1126 | struct rpc_message msg = { |
915 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | 1127 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], |
@@ -918,10 +1130,8 @@ static void nfs4_close_begin(struct rpc_task *task) | |||
918 | .rpc_cred = state->owner->so_cred, | 1130 | .rpc_cred = state->owner->so_cred, |
919 | }; | 1131 | }; |
920 | int mode = 0, old_mode; | 1132 | int mode = 0, old_mode; |
921 | int status; | ||
922 | 1133 | ||
923 | status = nfs_wait_on_sequence(calldata->arg.seqid, task); | 1134 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
924 | if (status != 0) | ||
925 | return; | 1135 | return; |
926 | /* Recalculate the new open mode in case someone reopened the file | 1136 | /* Recalculate the new open mode in case someone reopened the file |
927 | * while we were waiting in line to be scheduled. | 1137 | * while we were waiting in line to be scheduled. |
@@ -929,26 +1139,34 @@ static void nfs4_close_begin(struct rpc_task *task) | |||
929 | spin_lock(&state->owner->so_lock); | 1139 | spin_lock(&state->owner->so_lock); |
930 | spin_lock(&calldata->inode->i_lock); | 1140 | spin_lock(&calldata->inode->i_lock); |
931 | mode = old_mode = state->state; | 1141 | mode = old_mode = state->state; |
932 | if (state->nreaders == 0) | 1142 | if (state->n_rdwr == 0) { |
933 | mode &= ~FMODE_READ; | 1143 | if (state->n_rdonly == 0) |
934 | if (state->nwriters == 0) | 1144 | mode &= ~FMODE_READ; |
935 | mode &= ~FMODE_WRITE; | 1145 | if (state->n_wronly == 0) |
1146 | mode &= ~FMODE_WRITE; | ||
1147 | } | ||
936 | nfs4_state_set_mode_locked(state, mode); | 1148 | nfs4_state_set_mode_locked(state, mode); |
937 | spin_unlock(&calldata->inode->i_lock); | 1149 | spin_unlock(&calldata->inode->i_lock); |
938 | spin_unlock(&state->owner->so_lock); | 1150 | spin_unlock(&state->owner->so_lock); |
939 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 1151 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
940 | nfs4_free_closedata(calldata); | 1152 | /* Note: exit _without_ calling nfs4_close_done */ |
941 | task->tk_exit = NULL; | 1153 | task->tk_action = NULL; |
942 | rpc_exit(task, 0); | ||
943 | return; | 1154 | return; |
944 | } | 1155 | } |
945 | nfs_fattr_init(calldata->res.fattr); | 1156 | nfs_fattr_init(calldata->res.fattr); |
946 | if (mode != 0) | 1157 | if (mode != 0) |
947 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1158 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
948 | calldata->arg.open_flags = mode; | 1159 | calldata->arg.open_flags = mode; |
1160 | calldata->timestamp = jiffies; | ||
949 | rpc_call_setup(task, &msg, 0); | 1161 | rpc_call_setup(task, &msg, 0); |
950 | } | 1162 | } |
951 | 1163 | ||
1164 | static const struct rpc_call_ops nfs4_close_ops = { | ||
1165 | .rpc_call_prepare = nfs4_close_prepare, | ||
1166 | .rpc_call_done = nfs4_close_done, | ||
1167 | .rpc_release = nfs4_free_closedata, | ||
1168 | }; | ||
1169 | |||
952 | /* | 1170 | /* |
953 | * It is possible for data to be read/written from a mem-mapped file | 1171 | * It is possible for data to be read/written from a mem-mapped file |
954 | * after the sys_close call (which hits the vfs layer as a flush). | 1172 | * after the sys_close call (which hits the vfs layer as a flush). |
@@ -981,8 +1199,7 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |||
981 | calldata->res.fattr = &calldata->fattr; | 1199 | calldata->res.fattr = &calldata->fattr; |
982 | calldata->res.server = server; | 1200 | calldata->res.server = server; |
983 | 1201 | ||
984 | status = nfs4_call_async(server->client, nfs4_close_begin, | 1202 | status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); |
985 | nfs4_close_done, calldata); | ||
986 | if (status == 0) | 1203 | if (status == 0) |
987 | goto out; | 1204 | goto out; |
988 | 1205 | ||
@@ -1034,7 +1251,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1034 | d_add(dentry, NULL); | 1251 | d_add(dentry, NULL); |
1035 | return (struct dentry *)state; | 1252 | return (struct dentry *)state; |
1036 | } | 1253 | } |
1037 | res = d_add_unique(dentry, state->inode); | 1254 | res = d_add_unique(dentry, igrab(state->inode)); |
1038 | if (res != NULL) | 1255 | if (res != NULL) |
1039 | dentry = res; | 1256 | dentry = res; |
1040 | nfs4_intent_set_file(nd, dentry, state); | 1257 | nfs4_intent_set_file(nd, dentry, state); |
@@ -1046,7 +1263,6 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1046 | { | 1263 | { |
1047 | struct rpc_cred *cred; | 1264 | struct rpc_cred *cred; |
1048 | struct nfs4_state *state; | 1265 | struct nfs4_state *state; |
1049 | struct inode *inode; | ||
1050 | 1266 | ||
1051 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1267 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); |
1052 | if (IS_ERR(cred)) | 1268 | if (IS_ERR(cred)) |
@@ -1070,9 +1286,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1070 | } | 1286 | } |
1071 | goto out_drop; | 1287 | goto out_drop; |
1072 | } | 1288 | } |
1073 | inode = state->inode; | 1289 | if (state->inode == dentry->d_inode) { |
1074 | iput(inode); | ||
1075 | if (inode == dentry->d_inode) { | ||
1076 | nfs4_intent_set_file(nd, dentry, state); | 1290 | nfs4_intent_set_file(nd, dentry, state); |
1077 | return 1; | 1291 | return 1; |
1078 | } | 1292 | } |
@@ -1508,11 +1722,13 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata) | |||
1508 | 1722 | ||
1509 | wdata->args.bitmask = server->attr_bitmask; | 1723 | wdata->args.bitmask = server->attr_bitmask; |
1510 | wdata->res.server = server; | 1724 | wdata->res.server = server; |
1725 | wdata->timestamp = jiffies; | ||
1511 | nfs_fattr_init(fattr); | 1726 | nfs_fattr_init(fattr); |
1512 | status = rpc_call_sync(server->client, &msg, rpcflags); | 1727 | status = rpc_call_sync(server->client, &msg, rpcflags); |
1513 | dprintk("NFS reply write: %d\n", status); | 1728 | dprintk("NFS reply write: %d\n", status); |
1514 | if (status < 0) | 1729 | if (status < 0) |
1515 | return status; | 1730 | return status; |
1731 | renew_lease(server, wdata->timestamp); | ||
1516 | nfs_post_op_update_inode(inode, fattr); | 1732 | nfs_post_op_update_inode(inode, fattr); |
1517 | return wdata->res.count; | 1733 | return wdata->res.count; |
1518 | } | 1734 | } |
@@ -1547,8 +1763,11 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata) | |||
1547 | 1763 | ||
1548 | cdata->args.bitmask = server->attr_bitmask; | 1764 | cdata->args.bitmask = server->attr_bitmask; |
1549 | cdata->res.server = server; | 1765 | cdata->res.server = server; |
1766 | cdata->timestamp = jiffies; | ||
1550 | nfs_fattr_init(fattr); | 1767 | nfs_fattr_init(fattr); |
1551 | status = rpc_call_sync(server->client, &msg, 0); | 1768 | status = rpc_call_sync(server->client, &msg, 0); |
1769 | if (status >= 0) | ||
1770 | renew_lease(server, cdata->timestamp); | ||
1552 | dprintk("NFS reply commit: %d\n", status); | 1771 | dprintk("NFS reply commit: %d\n", status); |
1553 | if (status >= 0) | 1772 | if (status >= 0) |
1554 | nfs_post_op_update_inode(inode, fattr); | 1773 | nfs_post_op_update_inode(inode, fattr); |
@@ -1601,7 +1820,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1601 | status = PTR_ERR(state); | 1820 | status = PTR_ERR(state); |
1602 | goto out; | 1821 | goto out; |
1603 | } | 1822 | } |
1604 | d_instantiate(dentry, state->inode); | 1823 | d_instantiate(dentry, igrab(state->inode)); |
1605 | if (flags & O_EXCL) { | 1824 | if (flags & O_EXCL) { |
1606 | struct nfs_fattr fattr; | 1825 | struct nfs_fattr fattr; |
1607 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, | 1826 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, |
@@ -2125,10 +2344,9 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2125 | return err; | 2344 | return err; |
2126 | } | 2345 | } |
2127 | 2346 | ||
2128 | static void | 2347 | static void nfs4_read_done(struct rpc_task *task, void *calldata) |
2129 | nfs4_read_done(struct rpc_task *task) | ||
2130 | { | 2348 | { |
2131 | struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; | 2349 | struct nfs_read_data *data = calldata; |
2132 | struct inode *inode = data->inode; | 2350 | struct inode *inode = data->inode; |
2133 | 2351 | ||
2134 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2352 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2138,9 +2356,14 @@ nfs4_read_done(struct rpc_task *task) | |||
2138 | if (task->tk_status > 0) | 2356 | if (task->tk_status > 0) |
2139 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2357 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2140 | /* Call back common NFS readpage processing */ | 2358 | /* Call back common NFS readpage processing */ |
2141 | nfs_readpage_result(task); | 2359 | nfs_readpage_result(task, calldata); |
2142 | } | 2360 | } |
2143 | 2361 | ||
2362 | static const struct rpc_call_ops nfs4_read_ops = { | ||
2363 | .rpc_call_done = nfs4_read_done, | ||
2364 | .rpc_release = nfs_readdata_release, | ||
2365 | }; | ||
2366 | |||
2144 | static void | 2367 | static void |
2145 | nfs4_proc_read_setup(struct nfs_read_data *data) | 2368 | nfs4_proc_read_setup(struct nfs_read_data *data) |
2146 | { | 2369 | { |
@@ -2160,14 +2383,13 @@ nfs4_proc_read_setup(struct nfs_read_data *data) | |||
2160 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 2383 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
2161 | 2384 | ||
2162 | /* Finalize the task. */ | 2385 | /* Finalize the task. */ |
2163 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); | 2386 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_read_ops, data); |
2164 | rpc_call_setup(task, &msg, 0); | 2387 | rpc_call_setup(task, &msg, 0); |
2165 | } | 2388 | } |
2166 | 2389 | ||
2167 | static void | 2390 | static void nfs4_write_done(struct rpc_task *task, void *calldata) |
2168 | nfs4_write_done(struct rpc_task *task) | ||
2169 | { | 2391 | { |
2170 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 2392 | struct nfs_write_data *data = calldata; |
2171 | struct inode *inode = data->inode; | 2393 | struct inode *inode = data->inode; |
2172 | 2394 | ||
2173 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2395 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2179,9 +2401,14 @@ nfs4_write_done(struct rpc_task *task) | |||
2179 | nfs_post_op_update_inode(inode, data->res.fattr); | 2401 | nfs_post_op_update_inode(inode, data->res.fattr); |
2180 | } | 2402 | } |
2181 | /* Call back common NFS writeback processing */ | 2403 | /* Call back common NFS writeback processing */ |
2182 | nfs_writeback_done(task); | 2404 | nfs_writeback_done(task, calldata); |
2183 | } | 2405 | } |
2184 | 2406 | ||
2407 | static const struct rpc_call_ops nfs4_write_ops = { | ||
2408 | .rpc_call_done = nfs4_write_done, | ||
2409 | .rpc_release = nfs_writedata_release, | ||
2410 | }; | ||
2411 | |||
2185 | static void | 2412 | static void |
2186 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) | 2413 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) |
2187 | { | 2414 | { |
@@ -2214,14 +2441,13 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2214 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 2441 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
2215 | 2442 | ||
2216 | /* Finalize the task. */ | 2443 | /* Finalize the task. */ |
2217 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); | 2444 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_write_ops, data); |
2218 | rpc_call_setup(task, &msg, 0); | 2445 | rpc_call_setup(task, &msg, 0); |
2219 | } | 2446 | } |
2220 | 2447 | ||
2221 | static void | 2448 | static void nfs4_commit_done(struct rpc_task *task, void *calldata) |
2222 | nfs4_commit_done(struct rpc_task *task) | ||
2223 | { | 2449 | { |
2224 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 2450 | struct nfs_write_data *data = calldata; |
2225 | struct inode *inode = data->inode; | 2451 | struct inode *inode = data->inode; |
2226 | 2452 | ||
2227 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2453 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
@@ -2231,9 +2457,14 @@ nfs4_commit_done(struct rpc_task *task) | |||
2231 | if (task->tk_status >= 0) | 2457 | if (task->tk_status >= 0) |
2232 | nfs_post_op_update_inode(inode, data->res.fattr); | 2458 | nfs_post_op_update_inode(inode, data->res.fattr); |
2233 | /* Call back common NFS writeback processing */ | 2459 | /* Call back common NFS writeback processing */ |
2234 | nfs_commit_done(task); | 2460 | nfs_commit_done(task, calldata); |
2235 | } | 2461 | } |
2236 | 2462 | ||
2463 | static const struct rpc_call_ops nfs4_commit_ops = { | ||
2464 | .rpc_call_done = nfs4_commit_done, | ||
2465 | .rpc_release = nfs_commit_release, | ||
2466 | }; | ||
2467 | |||
2237 | static void | 2468 | static void |
2238 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | 2469 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) |
2239 | { | 2470 | { |
@@ -2255,7 +2486,7 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2255 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 2486 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
2256 | 2487 | ||
2257 | /* Finalize the task. */ | 2488 | /* Finalize the task. */ |
2258 | rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); | 2489 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_commit_ops, data); |
2259 | rpc_call_setup(task, &msg, 0); | 2490 | rpc_call_setup(task, &msg, 0); |
2260 | } | 2491 | } |
2261 | 2492 | ||
@@ -2263,11 +2494,10 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2263 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 2494 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
2264 | * standalone procedure for queueing an asynchronous RENEW. | 2495 | * standalone procedure for queueing an asynchronous RENEW. |
2265 | */ | 2496 | */ |
2266 | static void | 2497 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
2267 | renew_done(struct rpc_task *task) | ||
2268 | { | 2498 | { |
2269 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 2499 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; |
2270 | unsigned long timestamp = (unsigned long)task->tk_calldata; | 2500 | unsigned long timestamp = (unsigned long)data; |
2271 | 2501 | ||
2272 | if (task->tk_status < 0) { | 2502 | if (task->tk_status < 0) { |
2273 | switch (task->tk_status) { | 2503 | switch (task->tk_status) { |
@@ -2284,26 +2514,28 @@ renew_done(struct rpc_task *task) | |||
2284 | spin_unlock(&clp->cl_lock); | 2514 | spin_unlock(&clp->cl_lock); |
2285 | } | 2515 | } |
2286 | 2516 | ||
2287 | int | 2517 | static const struct rpc_call_ops nfs4_renew_ops = { |
2288 | nfs4_proc_async_renew(struct nfs4_client *clp) | 2518 | .rpc_call_done = nfs4_renew_done, |
2519 | }; | ||
2520 | |||
2521 | int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | ||
2289 | { | 2522 | { |
2290 | struct rpc_message msg = { | 2523 | struct rpc_message msg = { |
2291 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2524 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
2292 | .rpc_argp = clp, | 2525 | .rpc_argp = clp, |
2293 | .rpc_cred = clp->cl_cred, | 2526 | .rpc_cred = cred, |
2294 | }; | 2527 | }; |
2295 | 2528 | ||
2296 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 2529 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
2297 | renew_done, (void *)jiffies); | 2530 | &nfs4_renew_ops, (void *)jiffies); |
2298 | } | 2531 | } |
2299 | 2532 | ||
2300 | int | 2533 | int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred) |
2301 | nfs4_proc_renew(struct nfs4_client *clp) | ||
2302 | { | 2534 | { |
2303 | struct rpc_message msg = { | 2535 | struct rpc_message msg = { |
2304 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2536 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
2305 | .rpc_argp = clp, | 2537 | .rpc_argp = clp, |
2306 | .rpc_cred = clp->cl_cred, | 2538 | .rpc_cred = cred, |
2307 | }; | 2539 | }; |
2308 | unsigned long now = jiffies; | 2540 | unsigned long now = jiffies; |
2309 | int status; | 2541 | int status; |
@@ -2519,7 +2751,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2519 | case -NFS4ERR_EXPIRED: | 2751 | case -NFS4ERR_EXPIRED: |
2520 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); | 2752 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); |
2521 | nfs4_schedule_state_recovery(clp); | 2753 | nfs4_schedule_state_recovery(clp); |
2522 | if (test_bit(NFS4CLNT_OK, &clp->cl_state)) | 2754 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
2523 | rpc_wake_up_task(task); | 2755 | rpc_wake_up_task(task); |
2524 | task->tk_status = 0; | 2756 | task->tk_status = 0; |
2525 | return -EAGAIN; | 2757 | return -EAGAIN; |
@@ -2536,25 +2768,25 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2536 | return 0; | 2768 | return 0; |
2537 | } | 2769 | } |
2538 | 2770 | ||
2771 | static int nfs4_wait_bit_interruptible(void *word) | ||
2772 | { | ||
2773 | if (signal_pending(current)) | ||
2774 | return -ERESTARTSYS; | ||
2775 | schedule(); | ||
2776 | return 0; | ||
2777 | } | ||
2778 | |||
2539 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) | 2779 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) |
2540 | { | 2780 | { |
2541 | DEFINE_WAIT(wait); | ||
2542 | sigset_t oldset; | 2781 | sigset_t oldset; |
2543 | int interruptible, res = 0; | 2782 | int res; |
2544 | 2783 | ||
2545 | might_sleep(); | 2784 | might_sleep(); |
2546 | 2785 | ||
2547 | rpc_clnt_sigmask(clnt, &oldset); | 2786 | rpc_clnt_sigmask(clnt, &oldset); |
2548 | interruptible = TASK_UNINTERRUPTIBLE; | 2787 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, |
2549 | if (clnt->cl_intr) | 2788 | nfs4_wait_bit_interruptible, |
2550 | interruptible = TASK_INTERRUPTIBLE; | 2789 | TASK_INTERRUPTIBLE); |
2551 | prepare_to_wait(&clp->cl_waitq, &wait, interruptible); | ||
2552 | nfs4_schedule_state_recovery(clp); | ||
2553 | if (clnt->cl_intr && signalled()) | ||
2554 | res = -ERESTARTSYS; | ||
2555 | else if (!test_bit(NFS4CLNT_OK, &clp->cl_state)) | ||
2556 | schedule(); | ||
2557 | finish_wait(&clp->cl_waitq, &wait); | ||
2558 | rpc_clnt_sigunmask(clnt, &oldset); | 2790 | rpc_clnt_sigunmask(clnt, &oldset); |
2559 | return res; | 2791 | return res; |
2560 | } | 2792 | } |
@@ -2597,6 +2829,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2597 | case -NFS4ERR_STALE_CLIENTID: | 2829 | case -NFS4ERR_STALE_CLIENTID: |
2598 | case -NFS4ERR_STALE_STATEID: | 2830 | case -NFS4ERR_STALE_STATEID: |
2599 | case -NFS4ERR_EXPIRED: | 2831 | case -NFS4ERR_EXPIRED: |
2832 | nfs4_schedule_state_recovery(clp); | ||
2600 | ret = nfs4_wait_clnt_recover(server->client, clp); | 2833 | ret = nfs4_wait_clnt_recover(server->client, clp); |
2601 | if (ret == 0) | 2834 | if (ret == 0) |
2602 | exception->retry = 1; | 2835 | exception->retry = 1; |
@@ -2613,7 +2846,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2613 | return nfs4_map_errors(ret); | 2846 | return nfs4_map_errors(ret); |
2614 | } | 2847 | } |
2615 | 2848 | ||
2616 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port) | 2849 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2617 | { | 2850 | { |
2618 | nfs4_verifier sc_verifier; | 2851 | nfs4_verifier sc_verifier; |
2619 | struct nfs4_setclientid setclientid = { | 2852 | struct nfs4_setclientid setclientid = { |
@@ -2624,7 +2857,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2624 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 2857 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
2625 | .rpc_argp = &setclientid, | 2858 | .rpc_argp = &setclientid, |
2626 | .rpc_resp = clp, | 2859 | .rpc_resp = clp, |
2627 | .rpc_cred = clp->cl_cred, | 2860 | .rpc_cred = cred, |
2628 | }; | 2861 | }; |
2629 | u32 *p; | 2862 | u32 *p; |
2630 | int loop = 0; | 2863 | int loop = 0; |
@@ -2638,7 +2871,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2638 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2871 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
2639 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2872 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", |
2640 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), | 2873 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), |
2641 | clp->cl_cred->cr_ops->cr_name, | 2874 | cred->cr_ops->cr_name, |
2642 | clp->cl_id_uniquifier); | 2875 | clp->cl_id_uniquifier); |
2643 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2876 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2644 | sizeof(setclientid.sc_netid), "tcp"); | 2877 | sizeof(setclientid.sc_netid), "tcp"); |
@@ -2661,14 +2894,14 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2661 | } | 2894 | } |
2662 | 2895 | ||
2663 | int | 2896 | int |
2664 | nfs4_proc_setclientid_confirm(struct nfs4_client *clp) | 2897 | nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) |
2665 | { | 2898 | { |
2666 | struct nfs_fsinfo fsinfo; | 2899 | struct nfs_fsinfo fsinfo; |
2667 | struct rpc_message msg = { | 2900 | struct rpc_message msg = { |
2668 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 2901 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
2669 | .rpc_argp = clp, | 2902 | .rpc_argp = clp, |
2670 | .rpc_resp = &fsinfo, | 2903 | .rpc_resp = &fsinfo, |
2671 | .rpc_cred = clp->cl_cred, | 2904 | .rpc_cred = cred, |
2672 | }; | 2905 | }; |
2673 | unsigned long now; | 2906 | unsigned long now; |
2674 | int status; | 2907 | int status; |
@@ -2679,24 +2912,92 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) | |||
2679 | spin_lock(&clp->cl_lock); | 2912 | spin_lock(&clp->cl_lock); |
2680 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 2913 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
2681 | clp->cl_last_renewal = now; | 2914 | clp->cl_last_renewal = now; |
2915 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
2682 | spin_unlock(&clp->cl_lock); | 2916 | spin_unlock(&clp->cl_lock); |
2683 | } | 2917 | } |
2684 | return status; | 2918 | return status; |
2685 | } | 2919 | } |
2686 | 2920 | ||
2687 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 2921 | struct nfs4_delegreturndata { |
2922 | struct nfs4_delegreturnargs args; | ||
2923 | struct nfs4_delegreturnres res; | ||
2924 | struct nfs_fh fh; | ||
2925 | nfs4_stateid stateid; | ||
2926 | struct rpc_cred *cred; | ||
2927 | unsigned long timestamp; | ||
2928 | struct nfs_fattr fattr; | ||
2929 | int rpc_status; | ||
2930 | }; | ||
2931 | |||
2932 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *calldata) | ||
2688 | { | 2933 | { |
2689 | struct nfs4_delegreturnargs args = { | 2934 | struct nfs4_delegreturndata *data = calldata; |
2690 | .fhandle = NFS_FH(inode), | ||
2691 | .stateid = stateid, | ||
2692 | }; | ||
2693 | struct rpc_message msg = { | 2935 | struct rpc_message msg = { |
2694 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], | 2936 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], |
2695 | .rpc_argp = &args, | 2937 | .rpc_argp = &data->args, |
2696 | .rpc_cred = cred, | 2938 | .rpc_resp = &data->res, |
2939 | .rpc_cred = data->cred, | ||
2697 | }; | 2940 | }; |
2941 | nfs_fattr_init(data->res.fattr); | ||
2942 | rpc_call_setup(task, &msg, 0); | ||
2943 | } | ||
2698 | 2944 | ||
2699 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2945 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
2946 | { | ||
2947 | struct nfs4_delegreturndata *data = calldata; | ||
2948 | data->rpc_status = task->tk_status; | ||
2949 | if (data->rpc_status == 0) | ||
2950 | renew_lease(data->res.server, data->timestamp); | ||
2951 | } | ||
2952 | |||
2953 | static void nfs4_delegreturn_release(void *calldata) | ||
2954 | { | ||
2955 | struct nfs4_delegreturndata *data = calldata; | ||
2956 | |||
2957 | put_rpccred(data->cred); | ||
2958 | kfree(calldata); | ||
2959 | } | ||
2960 | |||
2961 | const static struct rpc_call_ops nfs4_delegreturn_ops = { | ||
2962 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
2963 | .rpc_call_done = nfs4_delegreturn_done, | ||
2964 | .rpc_release = nfs4_delegreturn_release, | ||
2965 | }; | ||
2966 | |||
2967 | static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | ||
2968 | { | ||
2969 | struct nfs4_delegreturndata *data; | ||
2970 | struct nfs_server *server = NFS_SERVER(inode); | ||
2971 | struct rpc_task *task; | ||
2972 | int status; | ||
2973 | |||
2974 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
2975 | if (data == NULL) | ||
2976 | return -ENOMEM; | ||
2977 | data->args.fhandle = &data->fh; | ||
2978 | data->args.stateid = &data->stateid; | ||
2979 | data->args.bitmask = server->attr_bitmask; | ||
2980 | nfs_copy_fh(&data->fh, NFS_FH(inode)); | ||
2981 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | ||
2982 | data->res.fattr = &data->fattr; | ||
2983 | data->res.server = server; | ||
2984 | data->cred = get_rpccred(cred); | ||
2985 | data->timestamp = jiffies; | ||
2986 | data->rpc_status = 0; | ||
2987 | |||
2988 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); | ||
2989 | if (IS_ERR(task)) { | ||
2990 | nfs4_delegreturn_release(data); | ||
2991 | return PTR_ERR(task); | ||
2992 | } | ||
2993 | status = nfs4_wait_for_completion_rpc_task(task); | ||
2994 | if (status == 0) { | ||
2995 | status = data->rpc_status; | ||
2996 | if (status == 0) | ||
2997 | nfs_post_op_update_inode(inode, &data->fattr); | ||
2998 | } | ||
2999 | rpc_release_task(task); | ||
3000 | return status; | ||
2700 | } | 3001 | } |
2701 | 3002 | ||
2702 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) | 3003 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid) |
@@ -2734,43 +3035,17 @@ nfs4_set_lock_task_retry(unsigned long timeout) | |||
2734 | return timeout; | 3035 | return timeout; |
2735 | } | 3036 | } |
2736 | 3037 | ||
2737 | static inline int | ||
2738 | nfs4_lck_type(int cmd, struct file_lock *request) | ||
2739 | { | ||
2740 | /* set lock type */ | ||
2741 | switch (request->fl_type) { | ||
2742 | case F_RDLCK: | ||
2743 | return IS_SETLKW(cmd) ? NFS4_READW_LT : NFS4_READ_LT; | ||
2744 | case F_WRLCK: | ||
2745 | return IS_SETLKW(cmd) ? NFS4_WRITEW_LT : NFS4_WRITE_LT; | ||
2746 | case F_UNLCK: | ||
2747 | return NFS4_WRITE_LT; | ||
2748 | } | ||
2749 | BUG(); | ||
2750 | return 0; | ||
2751 | } | ||
2752 | |||
2753 | static inline uint64_t | ||
2754 | nfs4_lck_length(struct file_lock *request) | ||
2755 | { | ||
2756 | if (request->fl_end == OFFSET_MAX) | ||
2757 | return ~(uint64_t)0; | ||
2758 | return request->fl_end - request->fl_start + 1; | ||
2759 | } | ||
2760 | |||
2761 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3038 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
2762 | { | 3039 | { |
2763 | struct inode *inode = state->inode; | 3040 | struct inode *inode = state->inode; |
2764 | struct nfs_server *server = NFS_SERVER(inode); | 3041 | struct nfs_server *server = NFS_SERVER(inode); |
2765 | struct nfs4_client *clp = server->nfs4_state; | 3042 | struct nfs4_client *clp = server->nfs4_state; |
2766 | struct nfs_lockargs arg = { | 3043 | struct nfs_lockt_args arg = { |
2767 | .fh = NFS_FH(inode), | 3044 | .fh = NFS_FH(inode), |
2768 | .type = nfs4_lck_type(cmd, request), | 3045 | .fl = request, |
2769 | .offset = request->fl_start, | ||
2770 | .length = nfs4_lck_length(request), | ||
2771 | }; | 3046 | }; |
2772 | struct nfs_lockres res = { | 3047 | struct nfs_lockt_res res = { |
2773 | .server = server, | 3048 | .denied = request, |
2774 | }; | 3049 | }; |
2775 | struct rpc_message msg = { | 3050 | struct rpc_message msg = { |
2776 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], | 3051 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], |
@@ -2778,36 +3053,23 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2778 | .rpc_resp = &res, | 3053 | .rpc_resp = &res, |
2779 | .rpc_cred = state->owner->so_cred, | 3054 | .rpc_cred = state->owner->so_cred, |
2780 | }; | 3055 | }; |
2781 | struct nfs_lowner nlo; | ||
2782 | struct nfs4_lock_state *lsp; | 3056 | struct nfs4_lock_state *lsp; |
2783 | int status; | 3057 | int status; |
2784 | 3058 | ||
2785 | down_read(&clp->cl_sem); | 3059 | down_read(&clp->cl_sem); |
2786 | nlo.clientid = clp->cl_clientid; | 3060 | arg.lock_owner.clientid = clp->cl_clientid; |
2787 | status = nfs4_set_lock_state(state, request); | 3061 | status = nfs4_set_lock_state(state, request); |
2788 | if (status != 0) | 3062 | if (status != 0) |
2789 | goto out; | 3063 | goto out; |
2790 | lsp = request->fl_u.nfs4_fl.owner; | 3064 | lsp = request->fl_u.nfs4_fl.owner; |
2791 | nlo.id = lsp->ls_id; | 3065 | arg.lock_owner.id = lsp->ls_id; |
2792 | arg.u.lockt = &nlo; | ||
2793 | status = rpc_call_sync(server->client, &msg, 0); | 3066 | status = rpc_call_sync(server->client, &msg, 0); |
2794 | if (!status) { | 3067 | switch (status) { |
2795 | request->fl_type = F_UNLCK; | 3068 | case 0: |
2796 | } else if (status == -NFS4ERR_DENIED) { | 3069 | request->fl_type = F_UNLCK; |
2797 | int64_t len, start, end; | 3070 | break; |
2798 | start = res.u.denied.offset; | 3071 | case -NFS4ERR_DENIED: |
2799 | len = res.u.denied.length; | 3072 | status = 0; |
2800 | end = start + len - 1; | ||
2801 | if (end < 0 || len == 0) | ||
2802 | request->fl_end = OFFSET_MAX; | ||
2803 | else | ||
2804 | request->fl_end = (loff_t)end; | ||
2805 | request->fl_start = (loff_t)start; | ||
2806 | request->fl_type = F_WRLCK; | ||
2807 | if (res.u.denied.type & 1) | ||
2808 | request->fl_type = F_RDLCK; | ||
2809 | request->fl_pid = 0; | ||
2810 | status = 0; | ||
2811 | } | 3073 | } |
2812 | out: | 3074 | out: |
2813 | up_read(&clp->cl_sem); | 3075 | up_read(&clp->cl_sem); |
@@ -2847,196 +3109,314 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
2847 | } | 3109 | } |
2848 | 3110 | ||
2849 | struct nfs4_unlockdata { | 3111 | struct nfs4_unlockdata { |
2850 | struct nfs_lockargs arg; | 3112 | struct nfs_locku_args arg; |
2851 | struct nfs_locku_opargs luargs; | 3113 | struct nfs_locku_res res; |
2852 | struct nfs_lockres res; | ||
2853 | struct nfs4_lock_state *lsp; | 3114 | struct nfs4_lock_state *lsp; |
2854 | struct nfs_open_context *ctx; | 3115 | struct nfs_open_context *ctx; |
2855 | atomic_t refcount; | 3116 | struct file_lock fl; |
2856 | struct completion completion; | 3117 | const struct nfs_server *server; |
3118 | unsigned long timestamp; | ||
2857 | }; | 3119 | }; |
2858 | 3120 | ||
2859 | static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) | 3121 | static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, |
2860 | { | 3122 | struct nfs_open_context *ctx, |
2861 | if (atomic_dec_and_test(&calldata->refcount)) { | 3123 | struct nfs4_lock_state *lsp, |
2862 | nfs_free_seqid(calldata->luargs.seqid); | 3124 | struct nfs_seqid *seqid) |
2863 | nfs4_put_lock_state(calldata->lsp); | 3125 | { |
2864 | put_nfs_open_context(calldata->ctx); | 3126 | struct nfs4_unlockdata *p; |
2865 | kfree(calldata); | 3127 | struct inode *inode = lsp->ls_state->inode; |
2866 | } | 3128 | |
3129 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
3130 | if (p == NULL) | ||
3131 | return NULL; | ||
3132 | p->arg.fh = NFS_FH(inode); | ||
3133 | p->arg.fl = &p->fl; | ||
3134 | p->arg.seqid = seqid; | ||
3135 | p->arg.stateid = &lsp->ls_stateid; | ||
3136 | p->lsp = lsp; | ||
3137 | atomic_inc(&lsp->ls_count); | ||
3138 | /* Ensure we don't close file until we're done freeing locks! */ | ||
3139 | p->ctx = get_nfs_open_context(ctx); | ||
3140 | memcpy(&p->fl, fl, sizeof(p->fl)); | ||
3141 | p->server = NFS_SERVER(inode); | ||
3142 | return p; | ||
2867 | } | 3143 | } |
2868 | 3144 | ||
2869 | static void nfs4_locku_complete(struct nfs4_unlockdata *calldata) | 3145 | static void nfs4_locku_release_calldata(void *data) |
2870 | { | 3146 | { |
2871 | complete(&calldata->completion); | 3147 | struct nfs4_unlockdata *calldata = data; |
2872 | nfs4_locku_release_calldata(calldata); | 3148 | nfs_free_seqid(calldata->arg.seqid); |
3149 | nfs4_put_lock_state(calldata->lsp); | ||
3150 | put_nfs_open_context(calldata->ctx); | ||
3151 | kfree(calldata); | ||
2873 | } | 3152 | } |
2874 | 3153 | ||
2875 | static void nfs4_locku_done(struct rpc_task *task) | 3154 | static void nfs4_locku_done(struct rpc_task *task, void *data) |
2876 | { | 3155 | { |
2877 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | 3156 | struct nfs4_unlockdata *calldata = data; |
2878 | 3157 | ||
2879 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | 3158 | if (RPC_ASSASSINATED(task)) |
3159 | return; | ||
3160 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); | ||
2880 | switch (task->tk_status) { | 3161 | switch (task->tk_status) { |
2881 | case 0: | 3162 | case 0: |
2882 | memcpy(calldata->lsp->ls_stateid.data, | 3163 | memcpy(calldata->lsp->ls_stateid.data, |
2883 | calldata->res.u.stateid.data, | 3164 | calldata->res.stateid.data, |
2884 | sizeof(calldata->lsp->ls_stateid.data)); | 3165 | sizeof(calldata->lsp->ls_stateid.data)); |
3166 | renew_lease(calldata->server, calldata->timestamp); | ||
2885 | break; | 3167 | break; |
2886 | case -NFS4ERR_STALE_STATEID: | 3168 | case -NFS4ERR_STALE_STATEID: |
2887 | case -NFS4ERR_EXPIRED: | 3169 | case -NFS4ERR_EXPIRED: |
2888 | nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); | 3170 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); |
2889 | break; | 3171 | break; |
2890 | default: | 3172 | default: |
2891 | if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { | 3173 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
2892 | rpc_restart_call(task); | 3174 | rpc_restart_call(task); |
2893 | return; | ||
2894 | } | 3175 | } |
2895 | } | 3176 | } |
2896 | nfs4_locku_complete(calldata); | ||
2897 | } | 3177 | } |
2898 | 3178 | ||
2899 | static void nfs4_locku_begin(struct rpc_task *task) | 3179 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
2900 | { | 3180 | { |
2901 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | 3181 | struct nfs4_unlockdata *calldata = data; |
2902 | struct rpc_message msg = { | 3182 | struct rpc_message msg = { |
2903 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | 3183 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], |
2904 | .rpc_argp = &calldata->arg, | 3184 | .rpc_argp = &calldata->arg, |
2905 | .rpc_resp = &calldata->res, | 3185 | .rpc_resp = &calldata->res, |
2906 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, | 3186 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, |
2907 | }; | 3187 | }; |
2908 | int status; | ||
2909 | 3188 | ||
2910 | status = nfs_wait_on_sequence(calldata->luargs.seqid, task); | 3189 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
2911 | if (status != 0) | ||
2912 | return; | 3190 | return; |
2913 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { | 3191 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { |
2914 | nfs4_locku_complete(calldata); | 3192 | /* Note: exit _without_ running nfs4_locku_done */ |
2915 | task->tk_exit = NULL; | 3193 | task->tk_action = NULL; |
2916 | rpc_exit(task, 0); | ||
2917 | return; | 3194 | return; |
2918 | } | 3195 | } |
3196 | calldata->timestamp = jiffies; | ||
2919 | rpc_call_setup(task, &msg, 0); | 3197 | rpc_call_setup(task, &msg, 0); |
2920 | } | 3198 | } |
2921 | 3199 | ||
3200 | static const struct rpc_call_ops nfs4_locku_ops = { | ||
3201 | .rpc_call_prepare = nfs4_locku_prepare, | ||
3202 | .rpc_call_done = nfs4_locku_done, | ||
3203 | .rpc_release = nfs4_locku_release_calldata, | ||
3204 | }; | ||
3205 | |||
3206 | static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | ||
3207 | struct nfs_open_context *ctx, | ||
3208 | struct nfs4_lock_state *lsp, | ||
3209 | struct nfs_seqid *seqid) | ||
3210 | { | ||
3211 | struct nfs4_unlockdata *data; | ||
3212 | struct rpc_task *task; | ||
3213 | |||
3214 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | ||
3215 | if (data == NULL) { | ||
3216 | nfs_free_seqid(seqid); | ||
3217 | return ERR_PTR(-ENOMEM); | ||
3218 | } | ||
3219 | |||
3220 | /* Unlock _before_ we do the RPC call */ | ||
3221 | do_vfs_lock(fl->fl_file, fl); | ||
3222 | task = rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | ||
3223 | if (IS_ERR(task)) | ||
3224 | nfs4_locku_release_calldata(data); | ||
3225 | return task; | ||
3226 | } | ||
3227 | |||
2922 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3228 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
2923 | { | 3229 | { |
2924 | struct nfs4_unlockdata *calldata; | 3230 | struct nfs_seqid *seqid; |
2925 | struct inode *inode = state->inode; | ||
2926 | struct nfs_server *server = NFS_SERVER(inode); | ||
2927 | struct nfs4_lock_state *lsp; | 3231 | struct nfs4_lock_state *lsp; |
2928 | int status; | 3232 | struct rpc_task *task; |
3233 | int status = 0; | ||
2929 | 3234 | ||
2930 | /* Is this a delegated lock? */ | 3235 | /* Is this a delegated lock? */ |
2931 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 3236 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
2932 | return do_vfs_lock(request->fl_file, request); | 3237 | goto out_unlock; |
3238 | /* Is this open_owner holding any locks on the server? */ | ||
3239 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | ||
3240 | goto out_unlock; | ||
2933 | 3241 | ||
2934 | status = nfs4_set_lock_state(state, request); | 3242 | status = nfs4_set_lock_state(state, request); |
2935 | if (status != 0) | 3243 | if (status != 0) |
2936 | return status; | 3244 | goto out_unlock; |
2937 | lsp = request->fl_u.nfs4_fl.owner; | 3245 | lsp = request->fl_u.nfs4_fl.owner; |
2938 | /* We might have lost the locks! */ | 3246 | status = -ENOMEM; |
2939 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | 3247 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2940 | return 0; | 3248 | if (seqid == NULL) |
2941 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 3249 | goto out_unlock; |
2942 | if (calldata == NULL) | 3250 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); |
2943 | return -ENOMEM; | 3251 | status = PTR_ERR(task); |
2944 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3252 | if (IS_ERR(task)) |
2945 | if (calldata->luargs.seqid == NULL) { | 3253 | goto out_unlock; |
2946 | kfree(calldata); | 3254 | status = nfs4_wait_for_completion_rpc_task(task); |
2947 | return -ENOMEM; | 3255 | rpc_release_task(task); |
2948 | } | 3256 | return status; |
2949 | calldata->luargs.stateid = &lsp->ls_stateid; | 3257 | out_unlock: |
2950 | calldata->arg.fh = NFS_FH(inode); | ||
2951 | calldata->arg.type = nfs4_lck_type(cmd, request); | ||
2952 | calldata->arg.offset = request->fl_start; | ||
2953 | calldata->arg.length = nfs4_lck_length(request); | ||
2954 | calldata->arg.u.locku = &calldata->luargs; | ||
2955 | calldata->res.server = server; | ||
2956 | calldata->lsp = lsp; | ||
2957 | atomic_inc(&lsp->ls_count); | ||
2958 | |||
2959 | /* Ensure we don't close file until we're done freeing locks! */ | ||
2960 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | ||
2961 | |||
2962 | atomic_set(&calldata->refcount, 2); | ||
2963 | init_completion(&calldata->completion); | ||
2964 | |||
2965 | status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin, | ||
2966 | nfs4_locku_done, calldata); | ||
2967 | if (status == 0) | ||
2968 | wait_for_completion_interruptible(&calldata->completion); | ||
2969 | do_vfs_lock(request->fl_file, request); | 3258 | do_vfs_lock(request->fl_file, request); |
2970 | nfs4_locku_release_calldata(calldata); | ||
2971 | return status; | 3259 | return status; |
2972 | } | 3260 | } |
2973 | 3261 | ||
2974 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) | 3262 | struct nfs4_lockdata { |
3263 | struct nfs_lock_args arg; | ||
3264 | struct nfs_lock_res res; | ||
3265 | struct nfs4_lock_state *lsp; | ||
3266 | struct nfs_open_context *ctx; | ||
3267 | struct file_lock fl; | ||
3268 | unsigned long timestamp; | ||
3269 | int rpc_status; | ||
3270 | int cancelled; | ||
3271 | }; | ||
3272 | |||
3273 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | ||
3274 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | ||
2975 | { | 3275 | { |
2976 | struct inode *inode = state->inode; | 3276 | struct nfs4_lockdata *p; |
3277 | struct inode *inode = lsp->ls_state->inode; | ||
2977 | struct nfs_server *server = NFS_SERVER(inode); | 3278 | struct nfs_server *server = NFS_SERVER(inode); |
2978 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | 3279 | |
2979 | struct nfs_lock_opargs largs = { | 3280 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
2980 | .lock_stateid = &lsp->ls_stateid, | 3281 | if (p == NULL) |
2981 | .open_stateid = &state->stateid, | 3282 | return NULL; |
2982 | .lock_owner = { | 3283 | |
2983 | .clientid = server->nfs4_state->cl_clientid, | 3284 | p->arg.fh = NFS_FH(inode); |
2984 | .id = lsp->ls_id, | 3285 | p->arg.fl = &p->fl; |
2985 | }, | 3286 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2986 | .reclaim = reclaim, | 3287 | if (p->arg.lock_seqid == NULL) |
2987 | }; | 3288 | goto out_free; |
2988 | struct nfs_lockargs arg = { | 3289 | p->arg.lock_stateid = &lsp->ls_stateid; |
2989 | .fh = NFS_FH(inode), | 3290 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; |
2990 | .type = nfs4_lck_type(cmd, request), | 3291 | p->arg.lock_owner.id = lsp->ls_id; |
2991 | .offset = request->fl_start, | 3292 | p->lsp = lsp; |
2992 | .length = nfs4_lck_length(request), | 3293 | atomic_inc(&lsp->ls_count); |
2993 | .u = { | 3294 | p->ctx = get_nfs_open_context(ctx); |
2994 | .lock = &largs, | 3295 | memcpy(&p->fl, fl, sizeof(p->fl)); |
2995 | }, | 3296 | return p; |
2996 | }; | 3297 | out_free: |
2997 | struct nfs_lockres res = { | 3298 | kfree(p); |
2998 | .server = server, | 3299 | return NULL; |
2999 | }; | 3300 | } |
3301 | |||
3302 | static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | ||
3303 | { | ||
3304 | struct nfs4_lockdata *data = calldata; | ||
3305 | struct nfs4_state *state = data->lsp->ls_state; | ||
3306 | struct nfs4_state_owner *sp = state->owner; | ||
3000 | struct rpc_message msg = { | 3307 | struct rpc_message msg = { |
3001 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | 3308 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], |
3002 | .rpc_argp = &arg, | 3309 | .rpc_argp = &data->arg, |
3003 | .rpc_resp = &res, | 3310 | .rpc_resp = &data->res, |
3004 | .rpc_cred = state->owner->so_cred, | 3311 | .rpc_cred = sp->so_cred, |
3005 | }; | 3312 | }; |
3006 | int status = -ENOMEM; | ||
3007 | |||
3008 | largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | ||
3009 | if (largs.lock_seqid == NULL) | ||
3010 | return -ENOMEM; | ||
3011 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | ||
3012 | struct nfs4_state_owner *owner = state->owner; | ||
3013 | 3313 | ||
3014 | largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); | 3314 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) |
3015 | if (largs.open_seqid == NULL) | 3315 | return; |
3316 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3317 | /* Do we need to do an open_to_lock_owner? */ | ||
3318 | if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | ||
3319 | data->arg.open_seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
3320 | if (data->arg.open_seqid == NULL) { | ||
3321 | data->rpc_status = -ENOMEM; | ||
3322 | task->tk_action = NULL; | ||
3016 | goto out; | 3323 | goto out; |
3017 | largs.new_lock_owner = 1; | ||
3018 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | ||
3019 | /* increment open seqid on success, and seqid mutating errors */ | ||
3020 | if (largs.new_lock_owner != 0) { | ||
3021 | nfs_increment_open_seqid(status, largs.open_seqid); | ||
3022 | if (status == 0) | ||
3023 | nfs_confirm_seqid(&lsp->ls_seqid, 0); | ||
3024 | } | 3324 | } |
3025 | nfs_free_seqid(largs.open_seqid); | 3325 | data->arg.open_stateid = &state->stateid; |
3026 | } else | 3326 | data->arg.new_lock_owner = 1; |
3027 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3327 | } |
3028 | /* increment lock seqid on success, and seqid mutating errors*/ | 3328 | data->timestamp = jiffies; |
3029 | nfs_increment_lock_seqid(status, largs.lock_seqid); | 3329 | rpc_call_setup(task, &msg, 0); |
3030 | /* save the returned stateid. */ | ||
3031 | if (status == 0) { | ||
3032 | memcpy(lsp->ls_stateid.data, res.u.stateid.data, | ||
3033 | sizeof(lsp->ls_stateid.data)); | ||
3034 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
3035 | } else if (status == -NFS4ERR_DENIED) | ||
3036 | status = -EAGAIN; | ||
3037 | out: | 3330 | out: |
3038 | nfs_free_seqid(largs.lock_seqid); | 3331 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); |
3039 | return status; | 3332 | } |
3333 | |||
3334 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | ||
3335 | { | ||
3336 | struct nfs4_lockdata *data = calldata; | ||
3337 | |||
3338 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3339 | |||
3340 | data->rpc_status = task->tk_status; | ||
3341 | if (RPC_ASSASSINATED(task)) | ||
3342 | goto out; | ||
3343 | if (data->arg.new_lock_owner != 0) { | ||
3344 | nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | ||
3345 | if (data->rpc_status == 0) | ||
3346 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | ||
3347 | else | ||
3348 | goto out; | ||
3349 | } | ||
3350 | if (data->rpc_status == 0) { | ||
3351 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | ||
3352 | sizeof(data->lsp->ls_stateid.data)); | ||
3353 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
3354 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | ||
3355 | } | ||
3356 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | ||
3357 | out: | ||
3358 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | ||
3359 | } | ||
3360 | |||
3361 | static void nfs4_lock_release(void *calldata) | ||
3362 | { | ||
3363 | struct nfs4_lockdata *data = calldata; | ||
3364 | |||
3365 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3366 | if (data->arg.open_seqid != NULL) | ||
3367 | nfs_free_seqid(data->arg.open_seqid); | ||
3368 | if (data->cancelled != 0) { | ||
3369 | struct rpc_task *task; | ||
3370 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | ||
3371 | data->arg.lock_seqid); | ||
3372 | if (!IS_ERR(task)) | ||
3373 | rpc_release_task(task); | ||
3374 | dprintk("%s: cancelling lock!\n", __FUNCTION__); | ||
3375 | } else | ||
3376 | nfs_free_seqid(data->arg.lock_seqid); | ||
3377 | nfs4_put_lock_state(data->lsp); | ||
3378 | put_nfs_open_context(data->ctx); | ||
3379 | kfree(data); | ||
3380 | dprintk("%s: done!\n", __FUNCTION__); | ||
3381 | } | ||
3382 | |||
3383 | static const struct rpc_call_ops nfs4_lock_ops = { | ||
3384 | .rpc_call_prepare = nfs4_lock_prepare, | ||
3385 | .rpc_call_done = nfs4_lock_done, | ||
3386 | .rpc_release = nfs4_lock_release, | ||
3387 | }; | ||
3388 | |||
3389 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | ||
3390 | { | ||
3391 | struct nfs4_lockdata *data; | ||
3392 | struct rpc_task *task; | ||
3393 | int ret; | ||
3394 | |||
3395 | dprintk("%s: begin!\n", __FUNCTION__); | ||
3396 | data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, | ||
3397 | fl->fl_u.nfs4_fl.owner); | ||
3398 | if (data == NULL) | ||
3399 | return -ENOMEM; | ||
3400 | if (IS_SETLKW(cmd)) | ||
3401 | data->arg.block = 1; | ||
3402 | if (reclaim != 0) | ||
3403 | data->arg.reclaim = 1; | ||
3404 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | ||
3405 | &nfs4_lock_ops, data); | ||
3406 | if (IS_ERR(task)) { | ||
3407 | nfs4_lock_release(data); | ||
3408 | return PTR_ERR(task); | ||
3409 | } | ||
3410 | ret = nfs4_wait_for_completion_rpc_task(task); | ||
3411 | if (ret == 0) { | ||
3412 | ret = data->rpc_status; | ||
3413 | if (ret == -NFS4ERR_DENIED) | ||
3414 | ret = -EAGAIN; | ||
3415 | } else | ||
3416 | data->cancelled = 1; | ||
3417 | rpc_release_task(task); | ||
3418 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); | ||
3419 | return ret; | ||
3040 | } | 3420 | } |
3041 | 3421 | ||
3042 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 3422 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |