diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 431 |
1 files changed, 240 insertions, 191 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 83e700a2b0c0..8dde84b988d9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -62,14 +62,12 @@ | |||
62 | struct nfs4_opendata; | 62 | struct nfs4_opendata; |
63 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 63 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 64 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 65 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | ||
67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); | ||
68 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 66 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
69 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 67 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
70 | 68 | ||
71 | /* Prevent leaks of NFSv4 errors into userland */ | 69 | /* Prevent leaks of NFSv4 errors into userland */ |
72 | int nfs4_map_errors(int err) | 70 | static int nfs4_map_errors(int err) |
73 | { | 71 | { |
74 | if (err < -1000) { | 72 | if (err < -1000) { |
75 | dprintk("%s could not handle NFSv4 error %d\n", | 73 | dprintk("%s could not handle NFSv4 error %d\n", |
@@ -195,6 +193,83 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent | |||
195 | kunmap_atomic(start, KM_USER0); | 193 | kunmap_atomic(start, KM_USER0); |
196 | } | 194 | } |
197 | 195 | ||
196 | static int nfs4_wait_bit_killable(void *word) | ||
197 | { | ||
198 | if (fatal_signal_pending(current)) | ||
199 | return -ERESTARTSYS; | ||
200 | schedule(); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int nfs4_wait_clnt_recover(struct nfs_client *clp) | ||
205 | { | ||
206 | int res; | ||
207 | |||
208 | might_sleep(); | ||
209 | |||
210 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, | ||
211 | nfs4_wait_bit_killable, TASK_KILLABLE); | ||
212 | return res; | ||
213 | } | ||
214 | |||
215 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | ||
216 | { | ||
217 | int res = 0; | ||
218 | |||
219 | might_sleep(); | ||
220 | |||
221 | if (*timeout <= 0) | ||
222 | *timeout = NFS4_POLL_RETRY_MIN; | ||
223 | if (*timeout > NFS4_POLL_RETRY_MAX) | ||
224 | *timeout = NFS4_POLL_RETRY_MAX; | ||
225 | schedule_timeout_killable(*timeout); | ||
226 | if (fatal_signal_pending(current)) | ||
227 | res = -ERESTARTSYS; | ||
228 | *timeout <<= 1; | ||
229 | return res; | ||
230 | } | ||
231 | |||
232 | /* This is the error handling routine for processes that are allowed | ||
233 | * to sleep. | ||
234 | */ | ||
235 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | ||
236 | { | ||
237 | struct nfs_client *clp = server->nfs_client; | ||
238 | struct nfs4_state *state = exception->state; | ||
239 | int ret = errorcode; | ||
240 | |||
241 | exception->retry = 0; | ||
242 | switch(errorcode) { | ||
243 | case 0: | ||
244 | return 0; | ||
245 | case -NFS4ERR_ADMIN_REVOKED: | ||
246 | case -NFS4ERR_BAD_STATEID: | ||
247 | case -NFS4ERR_OPENMODE: | ||
248 | if (state == NULL) | ||
249 | break; | ||
250 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
251 | case -NFS4ERR_STALE_CLIENTID: | ||
252 | case -NFS4ERR_STALE_STATEID: | ||
253 | case -NFS4ERR_EXPIRED: | ||
254 | nfs4_schedule_state_recovery(clp); | ||
255 | ret = nfs4_wait_clnt_recover(clp); | ||
256 | if (ret == 0) | ||
257 | exception->retry = 1; | ||
258 | break; | ||
259 | case -NFS4ERR_FILE_OPEN: | ||
260 | case -NFS4ERR_GRACE: | ||
261 | case -NFS4ERR_DELAY: | ||
262 | ret = nfs4_delay(server->client, &exception->timeout); | ||
263 | if (ret != 0) | ||
264 | break; | ||
265 | case -NFS4ERR_OLD_STATEID: | ||
266 | exception->retry = 1; | ||
267 | } | ||
268 | /* We failed to handle the error */ | ||
269 | return nfs4_map_errors(ret); | ||
270 | } | ||
271 | |||
272 | |||
198 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 273 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
199 | { | 274 | { |
200 | struct nfs_client *clp = server->nfs_client; | 275 | struct nfs_client *clp = server->nfs_client; |
@@ -248,7 +323,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
248 | } | 323 | } |
249 | 324 | ||
250 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 325 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
251 | struct nfs4_state_owner *sp, int flags, | 326 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
252 | const struct iattr *attrs) | 327 | const struct iattr *attrs) |
253 | { | 328 | { |
254 | struct dentry *parent = dget_parent(path->dentry); | 329 | struct dentry *parent = dget_parent(path->dentry); |
@@ -268,7 +343,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
268 | p->owner = sp; | 343 | p->owner = sp; |
269 | atomic_inc(&sp->so_count); | 344 | atomic_inc(&sp->so_count); |
270 | p->o_arg.fh = NFS_FH(dir); | 345 | p->o_arg.fh = NFS_FH(dir); |
271 | p->o_arg.open_flags = flags, | 346 | p->o_arg.open_flags = flags; |
347 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | ||
272 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 348 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
273 | p->o_arg.id = sp->so_owner_id.id; | 349 | p->o_arg.id = sp->so_owner_id.id; |
274 | p->o_arg.name = &p->path.dentry->d_name; | 350 | p->o_arg.name = &p->path.dentry->d_name; |
@@ -324,10 +400,13 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
324 | return ret; | 400 | return ret; |
325 | } | 401 | } |
326 | 402 | ||
327 | static int can_open_cached(struct nfs4_state *state, int mode) | 403 | static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) |
328 | { | 404 | { |
329 | int ret = 0; | 405 | int ret = 0; |
330 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | 406 | |
407 | if (open_mode & O_EXCL) | ||
408 | goto out; | ||
409 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | ||
331 | case FMODE_READ: | 410 | case FMODE_READ: |
332 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 411 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; |
333 | break; | 412 | break; |
@@ -337,21 +416,23 @@ static int can_open_cached(struct nfs4_state *state, int mode) | |||
337 | case FMODE_READ|FMODE_WRITE: | 416 | case FMODE_READ|FMODE_WRITE: |
338 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 417 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; |
339 | } | 418 | } |
419 | out: | ||
340 | return ret; | 420 | return ret; |
341 | } | 421 | } |
342 | 422 | ||
343 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | 423 | static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) |
344 | { | 424 | { |
345 | if ((delegation->type & open_flags) != open_flags) | 425 | if ((delegation->type & fmode) != fmode) |
346 | return 0; | 426 | return 0; |
347 | if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) | 427 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) |
348 | return 0; | 428 | return 0; |
429 | nfs_mark_delegation_referenced(delegation); | ||
349 | return 1; | 430 | return 1; |
350 | } | 431 | } |
351 | 432 | ||
352 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 433 | static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode) |
353 | { | 434 | { |
354 | switch (open_flags) { | 435 | switch (fmode) { |
355 | case FMODE_WRITE: | 436 | case FMODE_WRITE: |
356 | state->n_wronly++; | 437 | state->n_wronly++; |
357 | break; | 438 | break; |
@@ -361,15 +442,15 @@ static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | |||
361 | case FMODE_READ|FMODE_WRITE: | 442 | case FMODE_READ|FMODE_WRITE: |
362 | state->n_rdwr++; | 443 | state->n_rdwr++; |
363 | } | 444 | } |
364 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 445 | nfs4_state_set_mode_locked(state, state->state | fmode); |
365 | } | 446 | } |
366 | 447 | ||
367 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 448 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
368 | { | 449 | { |
369 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 450 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
370 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | 451 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); |
371 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | 452 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); |
372 | switch (open_flags) { | 453 | switch (fmode) { |
373 | case FMODE_READ: | 454 | case FMODE_READ: |
374 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 455 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
375 | break; | 456 | break; |
@@ -381,16 +462,15 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
381 | } | 462 | } |
382 | } | 463 | } |
383 | 464 | ||
384 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 465 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
385 | { | 466 | { |
386 | write_seqlock(&state->seqlock); | 467 | write_seqlock(&state->seqlock); |
387 | nfs_set_open_stateid_locked(state, stateid, open_flags); | 468 | nfs_set_open_stateid_locked(state, stateid, fmode); |
388 | write_sequnlock(&state->seqlock); | 469 | write_sequnlock(&state->seqlock); |
389 | } | 470 | } |
390 | 471 | ||
391 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | 472 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) |
392 | { | 473 | { |
393 | open_flags &= (FMODE_READ|FMODE_WRITE); | ||
394 | /* | 474 | /* |
395 | * Protect the call to nfs4_state_set_mode_locked and | 475 | * Protect the call to nfs4_state_set_mode_locked and |
396 | * serialise the stateid update | 476 | * serialise the stateid update |
@@ -401,20 +481,60 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_sta | |||
401 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 481 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
402 | } | 482 | } |
403 | if (open_stateid != NULL) | 483 | if (open_stateid != NULL) |
404 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | 484 | nfs_set_open_stateid_locked(state, open_stateid, fmode); |
405 | write_sequnlock(&state->seqlock); | 485 | write_sequnlock(&state->seqlock); |
406 | spin_lock(&state->owner->so_lock); | 486 | spin_lock(&state->owner->so_lock); |
407 | update_open_stateflags(state, open_flags); | 487 | update_open_stateflags(state, fmode); |
408 | spin_unlock(&state->owner->so_lock); | 488 | spin_unlock(&state->owner->so_lock); |
409 | } | 489 | } |
410 | 490 | ||
411 | static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | 491 | static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode) |
492 | { | ||
493 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
494 | struct nfs_delegation *deleg_cur; | ||
495 | int ret = 0; | ||
496 | |||
497 | fmode &= (FMODE_READ|FMODE_WRITE); | ||
498 | |||
499 | rcu_read_lock(); | ||
500 | deleg_cur = rcu_dereference(nfsi->delegation); | ||
501 | if (deleg_cur == NULL) | ||
502 | goto no_delegation; | ||
503 | |||
504 | spin_lock(&deleg_cur->lock); | ||
505 | if (nfsi->delegation != deleg_cur || | ||
506 | (deleg_cur->type & fmode) != fmode) | ||
507 | goto no_delegation_unlock; | ||
508 | |||
509 | if (delegation == NULL) | ||
510 | delegation = &deleg_cur->stateid; | ||
511 | else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0) | ||
512 | goto no_delegation_unlock; | ||
513 | |||
514 | nfs_mark_delegation_referenced(deleg_cur); | ||
515 | __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode); | ||
516 | ret = 1; | ||
517 | no_delegation_unlock: | ||
518 | spin_unlock(&deleg_cur->lock); | ||
519 | no_delegation: | ||
520 | rcu_read_unlock(); | ||
521 | |||
522 | if (!ret && open_stateid != NULL) { | ||
523 | __update_open_stateid(state, open_stateid, NULL, fmode); | ||
524 | ret = 1; | ||
525 | } | ||
526 | |||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | |||
531 | static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode) | ||
412 | { | 532 | { |
413 | struct nfs_delegation *delegation; | 533 | struct nfs_delegation *delegation; |
414 | 534 | ||
415 | rcu_read_lock(); | 535 | rcu_read_lock(); |
416 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 536 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
417 | if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | 537 | if (delegation == NULL || (delegation->type & fmode) == fmode) { |
418 | rcu_read_unlock(); | 538 | rcu_read_unlock(); |
419 | return; | 539 | return; |
420 | } | 540 | } |
@@ -427,27 +547,28 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
427 | struct nfs4_state *state = opendata->state; | 547 | struct nfs4_state *state = opendata->state; |
428 | struct nfs_inode *nfsi = NFS_I(state->inode); | 548 | struct nfs_inode *nfsi = NFS_I(state->inode); |
429 | struct nfs_delegation *delegation; | 549 | struct nfs_delegation *delegation; |
430 | int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | 550 | int open_mode = opendata->o_arg.open_flags & O_EXCL; |
551 | fmode_t fmode = opendata->o_arg.fmode; | ||
431 | nfs4_stateid stateid; | 552 | nfs4_stateid stateid; |
432 | int ret = -EAGAIN; | 553 | int ret = -EAGAIN; |
433 | 554 | ||
434 | rcu_read_lock(); | ||
435 | delegation = rcu_dereference(nfsi->delegation); | ||
436 | for (;;) { | 555 | for (;;) { |
437 | if (can_open_cached(state, open_mode)) { | 556 | if (can_open_cached(state, fmode, open_mode)) { |
438 | spin_lock(&state->owner->so_lock); | 557 | spin_lock(&state->owner->so_lock); |
439 | if (can_open_cached(state, open_mode)) { | 558 | if (can_open_cached(state, fmode, open_mode)) { |
440 | update_open_stateflags(state, open_mode); | 559 | update_open_stateflags(state, fmode); |
441 | spin_unlock(&state->owner->so_lock); | 560 | spin_unlock(&state->owner->so_lock); |
442 | rcu_read_unlock(); | ||
443 | goto out_return_state; | 561 | goto out_return_state; |
444 | } | 562 | } |
445 | spin_unlock(&state->owner->so_lock); | 563 | spin_unlock(&state->owner->so_lock); |
446 | } | 564 | } |
447 | if (delegation == NULL) | 565 | rcu_read_lock(); |
448 | break; | 566 | delegation = rcu_dereference(nfsi->delegation); |
449 | if (!can_open_delegated(delegation, open_mode)) | 567 | if (delegation == NULL || |
568 | !can_open_delegated(delegation, fmode)) { | ||
569 | rcu_read_unlock(); | ||
450 | break; | 570 | break; |
571 | } | ||
451 | /* Save the delegation */ | 572 | /* Save the delegation */ |
452 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | 573 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); |
453 | rcu_read_unlock(); | 574 | rcu_read_unlock(); |
@@ -455,19 +576,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
455 | if (ret != 0) | 576 | if (ret != 0) |
456 | goto out; | 577 | goto out; |
457 | ret = -EAGAIN; | 578 | ret = -EAGAIN; |
458 | rcu_read_lock(); | 579 | |
459 | delegation = rcu_dereference(nfsi->delegation); | 580 | /* Try to update the stateid using the delegation */ |
460 | /* If no delegation, try a cached open */ | 581 | if (update_open_stateid(state, NULL, &stateid, fmode)) |
461 | if (delegation == NULL) | 582 | goto out_return_state; |
462 | continue; | ||
463 | /* Is the delegation still valid? */ | ||
464 | if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) | ||
465 | continue; | ||
466 | rcu_read_unlock(); | ||
467 | update_open_stateid(state, NULL, &stateid, open_mode); | ||
468 | goto out_return_state; | ||
469 | } | 583 | } |
470 | rcu_read_unlock(); | ||
471 | out: | 584 | out: |
472 | return ERR_PTR(ret); | 585 | return ERR_PTR(ret); |
473 | out_return_state: | 586 | out_return_state: |
@@ -480,7 +593,6 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
480 | struct inode *inode; | 593 | struct inode *inode; |
481 | struct nfs4_state *state = NULL; | 594 | struct nfs4_state *state = NULL; |
482 | struct nfs_delegation *delegation; | 595 | struct nfs_delegation *delegation; |
483 | nfs4_stateid *deleg_stateid = NULL; | ||
484 | int ret; | 596 | int ret; |
485 | 597 | ||
486 | if (!data->rpc_done) { | 598 | if (!data->rpc_done) { |
@@ -507,7 +619,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
507 | if (delegation) | 619 | if (delegation) |
508 | delegation_flags = delegation->flags; | 620 | delegation_flags = delegation->flags; |
509 | rcu_read_unlock(); | 621 | rcu_read_unlock(); |
510 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | 622 | if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) |
511 | nfs_inode_set_delegation(state->inode, | 623 | nfs_inode_set_delegation(state->inode, |
512 | data->owner->so_cred, | 624 | data->owner->so_cred, |
513 | &data->o_res); | 625 | &data->o_res); |
@@ -516,12 +628,9 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
516 | data->owner->so_cred, | 628 | data->owner->so_cred, |
517 | &data->o_res); | 629 | &data->o_res); |
518 | } | 630 | } |
519 | rcu_read_lock(); | 631 | |
520 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 632 | update_open_stateid(state, &data->o_res.stateid, NULL, |
521 | if (delegation != NULL) | 633 | data->o_arg.fmode); |
522 | deleg_stateid = &delegation->stateid; | ||
523 | update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | ||
524 | rcu_read_unlock(); | ||
525 | iput(inode); | 634 | iput(inode); |
526 | out: | 635 | out: |
527 | return state; | 636 | return state; |
@@ -552,7 +661,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
552 | { | 661 | { |
553 | struct nfs4_opendata *opendata; | 662 | struct nfs4_opendata *opendata; |
554 | 663 | ||
555 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | 664 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); |
556 | if (opendata == NULL) | 665 | if (opendata == NULL) |
557 | return ERR_PTR(-ENOMEM); | 666 | return ERR_PTR(-ENOMEM); |
558 | opendata->state = state; | 667 | opendata->state = state; |
@@ -560,12 +669,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
560 | return opendata; | 669 | return opendata; |
561 | } | 670 | } |
562 | 671 | ||
563 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) | 672 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) |
564 | { | 673 | { |
565 | struct nfs4_state *newstate; | 674 | struct nfs4_state *newstate; |
566 | int ret; | 675 | int ret; |
567 | 676 | ||
568 | opendata->o_arg.open_flags = openflags; | 677 | opendata->o_arg.open_flags = 0; |
678 | opendata->o_arg.fmode = fmode; | ||
569 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 679 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
570 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 680 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
571 | nfs4_init_opendata_res(opendata); | 681 | nfs4_init_opendata_res(opendata); |
@@ -575,7 +685,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openf | |||
575 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 685 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
576 | if (IS_ERR(newstate)) | 686 | if (IS_ERR(newstate)) |
577 | return PTR_ERR(newstate); | 687 | return PTR_ERR(newstate); |
578 | nfs4_close_state(&opendata->path, newstate, openflags); | 688 | nfs4_close_state(&opendata->path, newstate, fmode); |
579 | *res = newstate; | 689 | *res = newstate; |
580 | return 0; | 690 | return 0; |
581 | } | 691 | } |
@@ -631,7 +741,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
631 | { | 741 | { |
632 | struct nfs_delegation *delegation; | 742 | struct nfs_delegation *delegation; |
633 | struct nfs4_opendata *opendata; | 743 | struct nfs4_opendata *opendata; |
634 | int delegation_type = 0; | 744 | fmode_t delegation_type = 0; |
635 | int status; | 745 | int status; |
636 | 746 | ||
637 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 747 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
@@ -641,7 +751,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
641 | opendata->o_arg.fh = NFS_FH(state->inode); | 751 | opendata->o_arg.fh = NFS_FH(state->inode); |
642 | rcu_read_lock(); | 752 | rcu_read_lock(); |
643 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | 753 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); |
644 | if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) | 754 | if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0) |
645 | delegation_type = delegation->type; | 755 | delegation_type = delegation->type; |
646 | rcu_read_unlock(); | 756 | rcu_read_unlock(); |
647 | opendata->o_arg.u.delegation_type = delegation_type; | 757 | opendata->o_arg.u.delegation_type = delegation_type; |
@@ -744,7 +854,7 @@ static void nfs4_open_confirm_release(void *calldata) | |||
744 | goto out_free; | 854 | goto out_free; |
745 | state = nfs4_opendata_to_nfs4_state(data); | 855 | state = nfs4_opendata_to_nfs4_state(data); |
746 | if (!IS_ERR(state)) | 856 | if (!IS_ERR(state)) |
747 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 857 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
748 | out_free: | 858 | out_free: |
749 | nfs4_opendata_put(data); | 859 | nfs4_opendata_put(data); |
750 | } | 860 | } |
@@ -808,12 +918,12 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
808 | if (data->state != NULL) { | 918 | if (data->state != NULL) { |
809 | struct nfs_delegation *delegation; | 919 | struct nfs_delegation *delegation; |
810 | 920 | ||
811 | if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | 921 | if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags)) |
812 | goto out_no_action; | 922 | goto out_no_action; |
813 | rcu_read_lock(); | 923 | rcu_read_lock(); |
814 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | 924 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); |
815 | if (delegation != NULL && | 925 | if (delegation != NULL && |
816 | (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { | 926 | test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) { |
817 | rcu_read_unlock(); | 927 | rcu_read_unlock(); |
818 | goto out_no_action; | 928 | goto out_no_action; |
819 | } | 929 | } |
@@ -877,7 +987,7 @@ static void nfs4_open_release(void *calldata) | |||
877 | goto out_free; | 987 | goto out_free; |
878 | state = nfs4_opendata_to_nfs4_state(data); | 988 | state = nfs4_opendata_to_nfs4_state(data); |
879 | if (!IS_ERR(state)) | 989 | if (!IS_ERR(state)) |
880 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 990 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
881 | out_free: | 991 | out_free: |
882 | nfs4_opendata_put(data); | 992 | nfs4_opendata_put(data); |
883 | } | 993 | } |
@@ -955,10 +1065,11 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |||
955 | int ret; | 1065 | int ret; |
956 | 1066 | ||
957 | for (;;) { | 1067 | for (;;) { |
958 | ret = nfs4_wait_clnt_recover(server->client, clp); | 1068 | ret = nfs4_wait_clnt_recover(clp); |
959 | if (ret != 0) | 1069 | if (ret != 0) |
960 | return ret; | 1070 | return ret; |
961 | if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1071 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && |
1072 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) | ||
962 | break; | 1073 | break; |
963 | nfs4_schedule_state_recovery(clp); | 1074 | nfs4_schedule_state_recovery(clp); |
964 | } | 1075 | } |
@@ -993,8 +1104,9 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4 | |||
993 | 1104 | ||
994 | do { | 1105 | do { |
995 | err = _nfs4_open_expired(ctx, state); | 1106 | err = _nfs4_open_expired(ctx, state); |
996 | if (err == -NFS4ERR_DELAY) | 1107 | if (err != -NFS4ERR_DELAY) |
997 | nfs4_handle_exception(server, err, &exception); | 1108 | break; |
1109 | nfs4_handle_exception(server, err, &exception); | ||
998 | } while (exception.retry); | 1110 | } while (exception.retry); |
999 | return err; | 1111 | return err; |
1000 | } | 1112 | } |
@@ -1031,12 +1143,11 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
1031 | /* | 1143 | /* |
1032 | * Returns a referenced nfs4_state | 1144 | * Returns a referenced nfs4_state |
1033 | */ | 1145 | */ |
1034 | static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 1146 | static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
1035 | { | 1147 | { |
1036 | struct nfs4_state_owner *sp; | 1148 | struct nfs4_state_owner *sp; |
1037 | struct nfs4_state *state = NULL; | 1149 | struct nfs4_state *state = NULL; |
1038 | struct nfs_server *server = NFS_SERVER(dir); | 1150 | struct nfs_server *server = NFS_SERVER(dir); |
1039 | struct nfs_client *clp = server->nfs_client; | ||
1040 | struct nfs4_opendata *opendata; | 1151 | struct nfs4_opendata *opendata; |
1041 | int status; | 1152 | int status; |
1042 | 1153 | ||
@@ -1050,12 +1161,11 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct | |||
1050 | if (status != 0) | 1161 | if (status != 0) |
1051 | goto err_put_state_owner; | 1162 | goto err_put_state_owner; |
1052 | if (path->dentry->d_inode != NULL) | 1163 | if (path->dentry->d_inode != NULL) |
1053 | nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | 1164 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
1054 | down_read(&clp->cl_sem); | ||
1055 | status = -ENOMEM; | 1165 | status = -ENOMEM; |
1056 | opendata = nfs4_opendata_alloc(path, sp, flags, sattr); | 1166 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); |
1057 | if (opendata == NULL) | 1167 | if (opendata == NULL) |
1058 | goto err_release_rwsem; | 1168 | goto err_put_state_owner; |
1059 | 1169 | ||
1060 | if (path->dentry->d_inode != NULL) | 1170 | if (path->dentry->d_inode != NULL) |
1061 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | 1171 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); |
@@ -1073,13 +1183,10 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct | |||
1073 | goto err_opendata_put; | 1183 | goto err_opendata_put; |
1074 | nfs4_opendata_put(opendata); | 1184 | nfs4_opendata_put(opendata); |
1075 | nfs4_put_state_owner(sp); | 1185 | nfs4_put_state_owner(sp); |
1076 | up_read(&clp->cl_sem); | ||
1077 | *res = state; | 1186 | *res = state; |
1078 | return 0; | 1187 | return 0; |
1079 | err_opendata_put: | 1188 | err_opendata_put: |
1080 | nfs4_opendata_put(opendata); | 1189 | nfs4_opendata_put(opendata); |
1081 | err_release_rwsem: | ||
1082 | up_read(&clp->cl_sem); | ||
1083 | err_put_state_owner: | 1190 | err_put_state_owner: |
1084 | nfs4_put_state_owner(sp); | 1191 | nfs4_put_state_owner(sp); |
1085 | out_err: | 1192 | out_err: |
@@ -1088,14 +1195,14 @@ out_err: | |||
1088 | } | 1195 | } |
1089 | 1196 | ||
1090 | 1197 | ||
1091 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1198 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) |
1092 | { | 1199 | { |
1093 | struct nfs4_exception exception = { }; | 1200 | struct nfs4_exception exception = { }; |
1094 | struct nfs4_state *res; | 1201 | struct nfs4_state *res; |
1095 | int status; | 1202 | int status; |
1096 | 1203 | ||
1097 | do { | 1204 | do { |
1098 | status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); | 1205 | status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); |
1099 | if (status == 0) | 1206 | if (status == 0) |
1100 | break; | 1207 | break; |
1101 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1208 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -1230,10 +1337,13 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1230 | renew_lease(server, calldata->timestamp); | 1337 | renew_lease(server, calldata->timestamp); |
1231 | break; | 1338 | break; |
1232 | case -NFS4ERR_STALE_STATEID: | 1339 | case -NFS4ERR_STALE_STATEID: |
1340 | case -NFS4ERR_OLD_STATEID: | ||
1341 | case -NFS4ERR_BAD_STATEID: | ||
1233 | case -NFS4ERR_EXPIRED: | 1342 | case -NFS4ERR_EXPIRED: |
1234 | break; | 1343 | if (calldata->arg.fmode == 0) |
1344 | break; | ||
1235 | default: | 1345 | default: |
1236 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1346 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1237 | rpc_restart_call(task); | 1347 | rpc_restart_call(task); |
1238 | return; | 1348 | return; |
1239 | } | 1349 | } |
@@ -1272,10 +1382,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1272 | nfs_fattr_init(calldata->res.fattr); | 1382 | nfs_fattr_init(calldata->res.fattr); |
1273 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | 1383 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
1274 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1384 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1275 | calldata->arg.open_flags = FMODE_READ; | 1385 | calldata->arg.fmode = FMODE_READ; |
1276 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | 1386 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { |
1277 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1387 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1278 | calldata->arg.open_flags = FMODE_WRITE; | 1388 | calldata->arg.fmode = FMODE_WRITE; |
1279 | } | 1389 | } |
1280 | calldata->timestamp = jiffies; | 1390 | calldata->timestamp = jiffies; |
1281 | rpc_call_start(task); | 1391 | rpc_call_start(task); |
@@ -1328,6 +1438,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1328 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1438 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1329 | if (calldata->arg.seqid == NULL) | 1439 | if (calldata->arg.seqid == NULL) |
1330 | goto out_free_calldata; | 1440 | goto out_free_calldata; |
1441 | calldata->arg.fmode = 0; | ||
1331 | calldata->arg.bitmask = server->attr_bitmask; | 1442 | calldata->arg.bitmask = server->attr_bitmask; |
1332 | calldata->res.fattr = &calldata->fattr; | 1443 | calldata->res.fattr = &calldata->fattr; |
1333 | calldata->res.seqid = calldata->arg.seqid; | 1444 | calldata->res.seqid = calldata->arg.seqid; |
@@ -1354,13 +1465,13 @@ out: | |||
1354 | return status; | 1465 | return status; |
1355 | } | 1466 | } |
1356 | 1467 | ||
1357 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) | 1468 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode) |
1358 | { | 1469 | { |
1359 | struct file *filp; | 1470 | struct file *filp; |
1360 | int ret; | 1471 | int ret; |
1361 | 1472 | ||
1362 | /* If the open_intent is for execute, we have an extra check to make */ | 1473 | /* If the open_intent is for execute, we have an extra check to make */ |
1363 | if (nd->intent.open.flags & FMODE_EXEC) { | 1474 | if (fmode & FMODE_EXEC) { |
1364 | ret = nfs_may_open(state->inode, | 1475 | ret = nfs_may_open(state->inode, |
1365 | state->owner->so_cred, | 1476 | state->owner->so_cred, |
1366 | nd->intent.open.flags); | 1477 | nd->intent.open.flags); |
@@ -1376,7 +1487,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
1376 | } | 1487 | } |
1377 | ret = PTR_ERR(filp); | 1488 | ret = PTR_ERR(filp); |
1378 | out_close: | 1489 | out_close: |
1379 | nfs4_close_sync(path, state, nd->intent.open.flags); | 1490 | nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE)); |
1380 | return ret; | 1491 | return ret; |
1381 | } | 1492 | } |
1382 | 1493 | ||
@@ -1392,6 +1503,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1392 | struct rpc_cred *cred; | 1503 | struct rpc_cred *cred; |
1393 | struct nfs4_state *state; | 1504 | struct nfs4_state *state; |
1394 | struct dentry *res; | 1505 | struct dentry *res; |
1506 | fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
1395 | 1507 | ||
1396 | if (nd->flags & LOOKUP_CREATE) { | 1508 | if (nd->flags & LOOKUP_CREATE) { |
1397 | attr.ia_mode = nd->intent.open.create_mode; | 1509 | attr.ia_mode = nd->intent.open.create_mode; |
@@ -1409,7 +1521,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1409 | parent = dentry->d_parent; | 1521 | parent = dentry->d_parent; |
1410 | /* Protect against concurrent sillydeletes */ | 1522 | /* Protect against concurrent sillydeletes */ |
1411 | nfs_block_sillyrename(parent); | 1523 | nfs_block_sillyrename(parent); |
1412 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); | 1524 | state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); |
1413 | put_rpccred(cred); | 1525 | put_rpccred(cred); |
1414 | if (IS_ERR(state)) { | 1526 | if (IS_ERR(state)) { |
1415 | if (PTR_ERR(state) == -ENOENT) { | 1527 | if (PTR_ERR(state) == -ENOENT) { |
@@ -1424,7 +1536,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1424 | path.dentry = res; | 1536 | path.dentry = res; |
1425 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | 1537 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); |
1426 | nfs_unblock_sillyrename(parent); | 1538 | nfs_unblock_sillyrename(parent); |
1427 | nfs4_intent_set_file(nd, &path, state); | 1539 | nfs4_intent_set_file(nd, &path, state, fmode); |
1428 | return res; | 1540 | return res; |
1429 | } | 1541 | } |
1430 | 1542 | ||
@@ -1437,11 +1549,12 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1437 | }; | 1549 | }; |
1438 | struct rpc_cred *cred; | 1550 | struct rpc_cred *cred; |
1439 | struct nfs4_state *state; | 1551 | struct nfs4_state *state; |
1552 | fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE); | ||
1440 | 1553 | ||
1441 | cred = rpc_lookup_cred(); | 1554 | cred = rpc_lookup_cred(); |
1442 | if (IS_ERR(cred)) | 1555 | if (IS_ERR(cred)) |
1443 | return PTR_ERR(cred); | 1556 | return PTR_ERR(cred); |
1444 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1557 | state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred); |
1445 | put_rpccred(cred); | 1558 | put_rpccred(cred); |
1446 | if (IS_ERR(state)) { | 1559 | if (IS_ERR(state)) { |
1447 | switch (PTR_ERR(state)) { | 1560 | switch (PTR_ERR(state)) { |
@@ -1458,10 +1571,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1458 | } | 1571 | } |
1459 | if (state->inode == dentry->d_inode) { | 1572 | if (state->inode == dentry->d_inode) { |
1460 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1573 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1461 | nfs4_intent_set_file(nd, &path, state); | 1574 | nfs4_intent_set_file(nd, &path, state, fmode); |
1462 | return 1; | 1575 | return 1; |
1463 | } | 1576 | } |
1464 | nfs4_close_sync(&path, state, openflags); | 1577 | nfs4_close_sync(&path, state, fmode); |
1465 | out_drop: | 1578 | out_drop: |
1466 | d_drop(dentry); | 1579 | d_drop(dentry); |
1467 | return 0; | 1580 | return 0; |
@@ -1887,6 +2000,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1887 | }; | 2000 | }; |
1888 | struct nfs4_state *state; | 2001 | struct nfs4_state *state; |
1889 | struct rpc_cred *cred; | 2002 | struct rpc_cred *cred; |
2003 | fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE); | ||
1890 | int status = 0; | 2004 | int status = 0; |
1891 | 2005 | ||
1892 | cred = rpc_lookup_cred(); | 2006 | cred = rpc_lookup_cred(); |
@@ -1894,7 +2008,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1894 | status = PTR_ERR(cred); | 2008 | status = PTR_ERR(cred); |
1895 | goto out; | 2009 | goto out; |
1896 | } | 2010 | } |
1897 | state = nfs4_do_open(dir, &path, flags, sattr, cred); | 2011 | state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred); |
1898 | d_drop(dentry); | 2012 | d_drop(dentry); |
1899 | if (IS_ERR(state)) { | 2013 | if (IS_ERR(state)) { |
1900 | status = PTR_ERR(state); | 2014 | status = PTR_ERR(state); |
@@ -1910,9 +2024,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1910 | nfs_post_op_update_inode(state->inode, &fattr); | 2024 | nfs_post_op_update_inode(state->inode, &fattr); |
1911 | } | 2025 | } |
1912 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2026 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
1913 | status = nfs4_intent_set_file(nd, &path, state); | 2027 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
1914 | else | 2028 | else |
1915 | nfs4_close_sync(&path, state, flags); | 2029 | nfs4_close_sync(&path, state, fmode); |
1916 | out_putcred: | 2030 | out_putcred: |
1917 | put_rpccred(cred); | 2031 | put_rpccred(cred); |
1918 | out: | 2032 | out: |
@@ -1974,7 +2088,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
1974 | { | 2088 | { |
1975 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2089 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
1976 | 2090 | ||
1977 | if (nfs4_async_handle_error(task, res->server) == -EAGAIN) | 2091 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
1978 | return 0; | 2092 | return 0; |
1979 | update_changeattr(dir, &res->cinfo); | 2093 | update_changeattr(dir, &res->cinfo); |
1980 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2094 | nfs_post_op_update_inode(dir, &res->dir_attr); |
@@ -2402,7 +2516,7 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2402 | { | 2516 | { |
2403 | struct nfs_server *server = NFS_SERVER(data->inode); | 2517 | struct nfs_server *server = NFS_SERVER(data->inode); |
2404 | 2518 | ||
2405 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 2519 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2406 | rpc_restart_call(task); | 2520 | rpc_restart_call(task); |
2407 | return -EAGAIN; | 2521 | return -EAGAIN; |
2408 | } | 2522 | } |
@@ -2423,7 +2537,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2423 | { | 2537 | { |
2424 | struct inode *inode = data->inode; | 2538 | struct inode *inode = data->inode; |
2425 | 2539 | ||
2426 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2540 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2427 | rpc_restart_call(task); | 2541 | rpc_restart_call(task); |
2428 | return -EAGAIN; | 2542 | return -EAGAIN; |
2429 | } | 2543 | } |
@@ -2449,7 +2563,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2449 | { | 2563 | { |
2450 | struct inode *inode = data->inode; | 2564 | struct inode *inode = data->inode; |
2451 | 2565 | ||
2452 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2566 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2453 | rpc_restart_call(task); | 2567 | rpc_restart_call(task); |
2454 | return -EAGAIN; | 2568 | return -EAGAIN; |
2455 | } | 2569 | } |
@@ -2742,19 +2856,25 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2742 | } | 2856 | } |
2743 | 2857 | ||
2744 | static int | 2858 | static int |
2745 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2859 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
2746 | { | 2860 | { |
2747 | struct nfs_client *clp = server->nfs_client; | 2861 | struct nfs_client *clp = server->nfs_client; |
2748 | 2862 | ||
2749 | if (!clp || task->tk_status >= 0) | 2863 | if (!clp || task->tk_status >= 0) |
2750 | return 0; | 2864 | return 0; |
2751 | switch(task->tk_status) { | 2865 | switch(task->tk_status) { |
2866 | case -NFS4ERR_ADMIN_REVOKED: | ||
2867 | case -NFS4ERR_BAD_STATEID: | ||
2868 | case -NFS4ERR_OPENMODE: | ||
2869 | if (state == NULL) | ||
2870 | break; | ||
2871 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
2752 | case -NFS4ERR_STALE_CLIENTID: | 2872 | case -NFS4ERR_STALE_CLIENTID: |
2753 | case -NFS4ERR_STALE_STATEID: | 2873 | case -NFS4ERR_STALE_STATEID: |
2754 | case -NFS4ERR_EXPIRED: | 2874 | case -NFS4ERR_EXPIRED: |
2755 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 2875 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
2756 | nfs4_schedule_state_recovery(clp); | 2876 | nfs4_schedule_state_recovery(clp); |
2757 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 2877 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) |
2758 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 2878 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2759 | task->tk_status = 0; | 2879 | task->tk_status = 0; |
2760 | return -EAGAIN; | 2880 | return -EAGAIN; |
@@ -2772,79 +2892,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2772 | return 0; | 2892 | return 0; |
2773 | } | 2893 | } |
2774 | 2894 | ||
2775 | static int nfs4_wait_bit_killable(void *word) | ||
2776 | { | ||
2777 | if (fatal_signal_pending(current)) | ||
2778 | return -ERESTARTSYS; | ||
2779 | schedule(); | ||
2780 | return 0; | ||
2781 | } | ||
2782 | |||
2783 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) | ||
2784 | { | ||
2785 | int res; | ||
2786 | |||
2787 | might_sleep(); | ||
2788 | |||
2789 | rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_); | ||
2790 | |||
2791 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, | ||
2792 | nfs4_wait_bit_killable, TASK_KILLABLE); | ||
2793 | |||
2794 | rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_); | ||
2795 | return res; | ||
2796 | } | ||
2797 | |||
2798 | static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | ||
2799 | { | ||
2800 | int res = 0; | ||
2801 | |||
2802 | might_sleep(); | ||
2803 | |||
2804 | if (*timeout <= 0) | ||
2805 | *timeout = NFS4_POLL_RETRY_MIN; | ||
2806 | if (*timeout > NFS4_POLL_RETRY_MAX) | ||
2807 | *timeout = NFS4_POLL_RETRY_MAX; | ||
2808 | schedule_timeout_killable(*timeout); | ||
2809 | if (fatal_signal_pending(current)) | ||
2810 | res = -ERESTARTSYS; | ||
2811 | *timeout <<= 1; | ||
2812 | return res; | ||
2813 | } | ||
2814 | |||
2815 | /* This is the error handling routine for processes that are allowed | ||
2816 | * to sleep. | ||
2817 | */ | ||
2818 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | ||
2819 | { | ||
2820 | struct nfs_client *clp = server->nfs_client; | ||
2821 | int ret = errorcode; | ||
2822 | |||
2823 | exception->retry = 0; | ||
2824 | switch(errorcode) { | ||
2825 | case 0: | ||
2826 | return 0; | ||
2827 | case -NFS4ERR_STALE_CLIENTID: | ||
2828 | case -NFS4ERR_STALE_STATEID: | ||
2829 | case -NFS4ERR_EXPIRED: | ||
2830 | nfs4_schedule_state_recovery(clp); | ||
2831 | ret = nfs4_wait_clnt_recover(server->client, clp); | ||
2832 | if (ret == 0) | ||
2833 | exception->retry = 1; | ||
2834 | break; | ||
2835 | case -NFS4ERR_FILE_OPEN: | ||
2836 | case -NFS4ERR_GRACE: | ||
2837 | case -NFS4ERR_DELAY: | ||
2838 | ret = nfs4_delay(server->client, &exception->timeout); | ||
2839 | if (ret != 0) | ||
2840 | break; | ||
2841 | case -NFS4ERR_OLD_STATEID: | ||
2842 | exception->retry = 1; | ||
2843 | } | ||
2844 | /* We failed to handle the error */ | ||
2845 | return nfs4_map_errors(ret); | ||
2846 | } | ||
2847 | |||
2848 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 2895 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2849 | { | 2896 | { |
2850 | nfs4_verifier sc_verifier; | 2897 | nfs4_verifier sc_verifier; |
@@ -2916,7 +2963,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre | |||
2916 | spin_lock(&clp->cl_lock); | 2963 | spin_lock(&clp->cl_lock); |
2917 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 2964 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
2918 | clp->cl_last_renewal = now; | 2965 | clp->cl_last_renewal = now; |
2919 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
2920 | spin_unlock(&clp->cl_lock); | 2966 | spin_unlock(&clp->cl_lock); |
2921 | } | 2967 | } |
2922 | return status; | 2968 | return status; |
@@ -3074,7 +3120,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3074 | struct nfs4_lock_state *lsp; | 3120 | struct nfs4_lock_state *lsp; |
3075 | int status; | 3121 | int status; |
3076 | 3122 | ||
3077 | down_read(&clp->cl_sem); | ||
3078 | arg.lock_owner.clientid = clp->cl_clientid; | 3123 | arg.lock_owner.clientid = clp->cl_clientid; |
3079 | status = nfs4_set_lock_state(state, request); | 3124 | status = nfs4_set_lock_state(state, request); |
3080 | if (status != 0) | 3125 | if (status != 0) |
@@ -3091,7 +3136,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3091 | } | 3136 | } |
3092 | request->fl_ops->fl_release_private(request); | 3137 | request->fl_ops->fl_release_private(request); |
3093 | out: | 3138 | out: |
3094 | up_read(&clp->cl_sem); | ||
3095 | return status; | 3139 | return status; |
3096 | } | 3140 | } |
3097 | 3141 | ||
@@ -3181,11 +3225,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3181 | sizeof(calldata->lsp->ls_stateid.data)); | 3225 | sizeof(calldata->lsp->ls_stateid.data)); |
3182 | renew_lease(calldata->server, calldata->timestamp); | 3226 | renew_lease(calldata->server, calldata->timestamp); |
3183 | break; | 3227 | break; |
3228 | case -NFS4ERR_BAD_STATEID: | ||
3229 | case -NFS4ERR_OLD_STATEID: | ||
3184 | case -NFS4ERR_STALE_STATEID: | 3230 | case -NFS4ERR_STALE_STATEID: |
3185 | case -NFS4ERR_EXPIRED: | 3231 | case -NFS4ERR_EXPIRED: |
3186 | break; | 3232 | break; |
3187 | default: | 3233 | default: |
3188 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) | 3234 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3189 | rpc_restart_call(task); | 3235 | rpc_restart_call(task); |
3190 | } | 3236 | } |
3191 | } | 3237 | } |
@@ -3248,6 +3294,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3248 | 3294 | ||
3249 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3295 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
3250 | { | 3296 | { |
3297 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
3251 | struct nfs_seqid *seqid; | 3298 | struct nfs_seqid *seqid; |
3252 | struct nfs4_lock_state *lsp; | 3299 | struct nfs4_lock_state *lsp; |
3253 | struct rpc_task *task; | 3300 | struct rpc_task *task; |
@@ -3257,8 +3304,12 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3257 | status = nfs4_set_lock_state(state, request); | 3304 | status = nfs4_set_lock_state(state, request); |
3258 | /* Unlock _before_ we do the RPC call */ | 3305 | /* Unlock _before_ we do the RPC call */ |
3259 | request->fl_flags |= FL_EXISTS; | 3306 | request->fl_flags |= FL_EXISTS; |
3260 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) | 3307 | down_read(&nfsi->rwsem); |
3308 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) { | ||
3309 | up_read(&nfsi->rwsem); | ||
3261 | goto out; | 3310 | goto out; |
3311 | } | ||
3312 | up_read(&nfsi->rwsem); | ||
3262 | if (status != 0) | 3313 | if (status != 0) |
3263 | goto out; | 3314 | goto out; |
3264 | /* Is this a delegated lock? */ | 3315 | /* Is this a delegated lock? */ |
@@ -3484,7 +3535,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
3484 | 3535 | ||
3485 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3536 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
3486 | { | 3537 | { |
3487 | struct nfs_client *clp = state->owner->so_client; | 3538 | struct nfs_inode *nfsi = NFS_I(state->inode); |
3488 | unsigned char fl_flags = request->fl_flags; | 3539 | unsigned char fl_flags = request->fl_flags; |
3489 | int status; | 3540 | int status; |
3490 | 3541 | ||
@@ -3496,19 +3547,13 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3496 | status = do_vfs_lock(request->fl_file, request); | 3547 | status = do_vfs_lock(request->fl_file, request); |
3497 | if (status < 0) | 3548 | if (status < 0) |
3498 | goto out; | 3549 | goto out; |
3499 | down_read(&clp->cl_sem); | 3550 | down_read(&nfsi->rwsem); |
3500 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 3551 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
3501 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
3502 | /* Yes: cache locks! */ | 3552 | /* Yes: cache locks! */ |
3503 | down_read(&nfsi->rwsem); | ||
3504 | /* ...but avoid races with delegation recall... */ | 3553 | /* ...but avoid races with delegation recall... */ |
3505 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 3554 | request->fl_flags = fl_flags & ~FL_SLEEP; |
3506 | request->fl_flags = fl_flags & ~FL_SLEEP; | 3555 | status = do_vfs_lock(request->fl_file, request); |
3507 | status = do_vfs_lock(request->fl_file, request); | 3556 | goto out_unlock; |
3508 | up_read(&nfsi->rwsem); | ||
3509 | goto out_unlock; | ||
3510 | } | ||
3511 | up_read(&nfsi->rwsem); | ||
3512 | } | 3557 | } |
3513 | status = _nfs4_do_setlk(state, cmd, request, 0); | 3558 | status = _nfs4_do_setlk(state, cmd, request, 0); |
3514 | if (status != 0) | 3559 | if (status != 0) |
@@ -3518,7 +3563,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3518 | if (do_vfs_lock(request->fl_file, request) < 0) | 3563 | if (do_vfs_lock(request->fl_file, request) < 0) |
3519 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); | 3564 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); |
3520 | out_unlock: | 3565 | out_unlock: |
3521 | up_read(&clp->cl_sem); | 3566 | up_read(&nfsi->rwsem); |
3522 | out: | 3567 | out: |
3523 | request->fl_flags = fl_flags; | 3568 | request->fl_flags = fl_flags; |
3524 | return status; | 3569 | return status; |
@@ -3664,11 +3709,15 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3664 | } | 3709 | } |
3665 | 3710 | ||
3666 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 3711 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
3712 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
3713 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
3667 | .recover_open = nfs4_open_reclaim, | 3714 | .recover_open = nfs4_open_reclaim, |
3668 | .recover_lock = nfs4_lock_reclaim, | 3715 | .recover_lock = nfs4_lock_reclaim, |
3669 | }; | 3716 | }; |
3670 | 3717 | ||
3671 | struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | 3718 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { |
3719 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
3720 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
3672 | .recover_open = nfs4_open_expired, | 3721 | .recover_open = nfs4_open_expired, |
3673 | .recover_lock = nfs4_lock_expired, | 3722 | .recover_lock = nfs4_lock_expired, |
3674 | }; | 3723 | }; |